0

[Java Backend Zero to Hello] [Phase 6] BÀI 6.9: EMAIL & NOTIFICATION

📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 6: REST API & Best Practices 📖 Nội dung: BÀI 6.9: EMAIL & NOTIFICATION 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.


BÀI 6.9: EMAIL & NOTIFICATION

Mục tiêu

  • Gửi email với Spring Boot
  • Sử dụng template engine
  • Gửi SMS, Push notification
  • Xử lý async

1. GỬI EMAIL CƠ BẢN

1.1 Dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

1.2 Cấu hình

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: your-email@gmail.com
    password: your-password
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true

1.3 JavaMailSender

@Service
@RequiredArgsConstructor
public class EmailService {

    private final JavaMailSender mailSender;

    public void sendSimpleEmail(String to, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        message.setFrom("noreply@example.com");

        mailSender.send(message);
    }
}

2. HTML EMAIL

@Service
@RequiredArgsConstructor
public class EmailService {

    private final JavaMailSender mailSender;

    public void sendHtmlEmail(String to, String subject, String htmlContent) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");

        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(htmlContent, true);
        helper.setFrom("noreply@example.com");

        mailSender.send(message);
    }
}

3. EMAIL VỚI ATTACHMENT

public void sendEmailWithAttachment(String to, String subject, String text,
                                     String attachmentPath) throws MessagingException {
    MimeMessage message = mailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(message, true);

    helper.setTo(to);
    helper.setSubject(subject);
    helper.setText(text);

    File file = new File(attachmentPath);
    helper.addAttachment(file.getName(), file);

    mailSender.send(message);
}

4. TEMPLATE VỚI THYMELEAF

4.1 Dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

4.2 Template templates/email/welcome.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Welcome</title>
</head>
<body>
    <h1>Chào mừng <span th:text="${name}">User</span>!</h1>
    <p>Cảm ơn bạn đã đăng ký tài khoản.</p>
    <a th:href="${activationLink}">Kích hoạt tài khoản</a>
</body>
</html>

4.3 Service

@Service
@RequiredArgsConstructor
public class EmailService {

    private final JavaMailSender mailSender;
    private final TemplateEngine templateEngine;

    public void sendWelcomeEmail(User user) throws MessagingException {
        Context context = new Context();
        context.setVariable("name", user.getName());
        context.setVariable("activationLink",
            "https://example.com/activate?token=" + user.getActivationToken());

        String html = templateEngine.process("email/welcome", context);

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setTo(user.getEmail());
        helper.setSubject("Chào mừng bạn!");
        helper.setText(html, true);

        mailSender.send(message);
    }
}

5. ASYNC EMAIL

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "emailExecutor")
    public Executor emailExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("email-");
        executor.initialize();
        return executor;
    }
}

@Service
@RequiredArgsConstructor
public class EmailService {

    private final JavaMailSender mailSender;

    @Async("emailExecutor")
    public void sendEmail(String to, String subject, String text) {
        // Gửi email bất đồng bộ
    }
}

6. SMS VỚI TWILIO

6.1 Dependency

<dependency>
    <groupId>com.twilio.sdk</groupId>
    <artifactId>twilio</artifactId>
    <version>9.43.0</version>
</dependency>

6.2 Service

@Service
public class SmsService {

    @Value("${twilio.account.sid}")
    private String accountSid;

    @Value("${twilio.auth.token}")
    private String authToken;

    @Value("${twilio.phone.number}")
    private String fromNumber;

    @PostConstruct
    public void init() {
        Twilio.init(accountSid, authToken);
    }

    public void sendSms(String to, String message) {
        Message.creator(
            new PhoneNumber(to),
            new PhoneNumber(fromNumber),
            message
        ).create();
    }
}

7. PUSH NOTIFICATION VỚI FCM

7.1 Dependency

<dependency>
    <groupId>com.google.firebase</groupId>
    <artifactId>firebase-admin</artifactId>
    <version>9.2.0</version>
</dependency>

7.2 Service

@Service
public class PushNotificationService {

    private final FirebaseMessaging firebaseMessaging;

    public void sendNotification(String token, String title, String body) throws FirebaseMessagingException {
        Notification notification = Notification.builder()
            .setTitle(title)
            .setBody(body)
            .build();

        Message message = Message.builder()
            .setToken(token)
            .setNotification(notification)
            .build();

        firebaseMessaging.send(message);
    }
}

8. IN-APP NOTIFICATION

8.1 Entity

@Entity
@Table(name = "notifications")
public class Notification {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    private User user;

    private String title;
    private String message;
    private String type;
    private boolean read;
    private LocalDateTime createdAt;
}

8.2 Service

@Service
@RequiredArgsConstructor
public class NotificationService {

    private final NotificationRepository repository;
    private final SimpMessagingTemplate websocket;

    public Notification create(User user, String title, String message, String type) {
        Notification notification = new Notification();
        notification.setUser(user);
        notification.setTitle(title);
        notification.setMessage(message);
        notification.setType(type);
        notification.setRead(false);
        notification.setCreatedAt(LocalDateTime.now());

        Notification saved = repository.save(notification);

        // Gửi qua WebSocket
        websocket.convertAndSendToUser(
            user.getId().toString(),
            "/queue/notifications",
            saved
        );

        return saved;
    }
}

9. WEBHOOK

Gửi HTTP request khi có sự kiện.

@Service
@RequiredArgsConstructor
public class WebhookService {

    private final RestTemplate restTemplate;

    public void sendWebhook(String url, Object payload) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity<Object> request = new HttpEntity<>(payload, headers);

        try {
            restTemplate.postForEntity(url, request, String.class);
        } catch (Exception e) {
            log.error("Webhook failed: {}", url, e);
        }
    }
}

10. BÀI TẬP THỰC HÀNH

Bài 1: Welcome Email

Gửi email chào mừng khi user đăng ký.

Bài 2: Order Confirmation

Gửi email xác nhận đơn hàng với template.

Bài 3: Async Notification

Implement hệ thống notification async.


11. TÓM TẮT

Khái niệm Mô tả
JavaMailSender Gửi email
Thymeleaf Template
@Async Bất đồng bộ
Twilio SMS
FCM Push notification
WebSocket Real-time
Webhook HTTP callback

Bài tiếp theo: 6.10 Logging & Monitoring


🧭 Điều hướng bài học

⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí