0

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

Java Backend Zero to Hello

📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 6: REST API & Best Practices | Bài 68/86


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 Series

⬅️ Bài trước: BÀI 6.8: FILE UPLOAD/DOWNLOAD

📋 Lộ trình tổng quan: Xem Toàn Bộ Series

➡️ Bài tiếp theo: BÀI 6.10: LOGGING & MONITORING


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í