Thực tế thì việc gửi email có thể sử dụng java mail API là đủ. Tuy nhiên spring boot cũng giúp chúng ta đóng gói một chút để việc gửi email trở nên dễ dàng hơn. Trong bài này chúng ta sẽ cùng nhau tìm hiểu về spring boot mail nhé.

Email làm việc thế nào?

Khi bạn gửi một email cho bạn bè hoặc liên hệ, email gần như được chuyển đến người nhận ngay lập tức trong nháy mắt. Tuy nhiên, có một loạt các quy trình diễn ra ở hậu trường từ khi bạn gửi email cho đến khi email được chuyển đến Hộp thư đến của người nhận. Dưới đây là một tóm tắt ngắn về quy trình này:

  1. Bạn đăng nhập vào email của mình (webmail, thiết bị di động hoặc ứng dụng máy tính để bàn).
  2. Mở trình soạn thảo, chỉ định tiêu đề, nhập nội dung email, chọn người nhận và soạn thảo email.
  3. Nhấn gửi để gửi email.
  4. Ứng dụng email (web, di động, máy tính để bàn) kết nối với máy chủ SMTP gửi đi dựa trên tài khoản email đã sử dụng.
  5. Ứng dụng email chuyển email ở định dạng MIME đến máy chủ SMTP gửi đi.
  6. Máy chủ SMTP gửi đi xác thực chi tiết của người gửi và xử lý thông điệp để gửi.
  7. Kiểm tra kích thước tệp đính kèm và xem email có tuân thủ chính sách gửi đi của tài khoản hay không.
  8. Sau khi xác thực xong, email được đặt vào hàng đợi gửi đi.
  9. Máy chủ SMTP tìm kiếm bản ghi DNS của tên miền và lấy thông tin bản ghi MX của máy chủ nhận (hoặc bản ghi A nếu không có MX).
  10. Máy chủ SMTP kết nối với máy chủ email nhận MTA và gửi email qua giao thức SMTP.
  11. Máy chủ nhận kiểm tra Spam, Virus và chấp nhận email theo chính sách chống Spam, Virus.
  12. Máy chủ nhận xác thực tài khoản người nhận và chuyển email vào tài khoản thư người dùng, theo chính sách email nhận.
  13. Người dùng xem email đã nhận qua ứng dụng email của mình.
    Bạn có thể tham khảo bài viết gốc tại đây.
    Như bạn thấy để gửi một email phải trải qua rất nhiều bước, chính vì thế gửi email rất chậm và đây là một trong những vấn đề không dễ giải quyết.

Khởi tạo module

Chúng ta sẽ khởi tạo module có tên spring-boot-mail.

Cấu hình dự án

Chúng ta sẽ cần thay đổi tập tin spring-boot-mail/pom.xml với mã nguồn như sau:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>vn.techmaster</groupId>
        <artifactId>mastering-spring-boot</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>spring-boot-mail</artifactId>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql.version}</version>
        </dependency>
    </dependencies>
</project>

Ở đây chúng bổ sung thư viện spring-boot-starter-mail để có thể sử dụng các thành phần liên quan đến mail client.

Cấu hình

Chúng ta sẽ gửi mail thông qua giao thức SMTP, vậy nên cấu hình cho SMTP thông qua tập tin application.yaml sẽ như sau:

spring:
  mail:
    host: smtp.ethereal.email
    port: 587
    username: maddison53@ethereal.email
    password: jn7jnAPss4f63QBp6D
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: truespring:
  mail:
    host: smtp.ethereal.email
    port: 587
    username: maddison53@ethereal.email
    password: jn7jnAPss4f63QBp6D
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

Ở đây mình đang sử dụng các giá trị test, nó có thể không hoạt động ở trên máy của các bạn, các bạn có thể tham khảo bài viết này để tìm cách cho phép gửi mail thông qua SMTP từ gmail của bạn. Tuy nhiên hãy để ý một chút về vấn đề bảo mật, đừng push mã nguồn của bạn có chứa thông tin về gmail và mật khẩu của bạn lên bất kỳ đâu nhé.

Tạo một lớp gửi mail

Sau khi đã có cấu hình thì spring boot sẽ tự tạo cho chúng ta một đối tượng singleton của JavaMailSender, chúng ta sẽ chỉ cần sử dụng lớp này trong lớp gửi mail EmailService của chúng ta mà thôi:

package vn.techmaster.mail.service;

import lombok.AllArgsConstructor;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class EmailService {

    private final JavaMailSender mailSender;

    public void sendMail(
        String from,
        String to,
        String subject,
        String text
    ) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        mailSender.send(message);
    }
}

Khởi chạy dự án

Chúng ta có thể tạo lớp SpringBootMailStartUp với mã nguồn như sau:

package vn.techmaster.mail;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import vn.techmaster.mail.service.EmailService;

@SpringBootApplication
public class SpringBootMailStartUp {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication
            .run(SpringBootMailStartUp.class);
        EmailService emailService = applicationContext
            .getBean(EmailService.class);
        emailService.sendMail(
            "\"Techmaster 👻\" <ta.van.dung@techmaster.vn>",
            "itprono3@gmail.com",
            "Hello ✔",
            "<b>Hello world?</b>"
        );
    }
}

Ở đây chúng ta đang gửi một email từ ta.van.dung@techmaster.vn đến itprono3@gmail.com bạn có thể thay bằng các email của mình nhé.
Sau khi khởi chạy chương trình bạn sẽ thấy có email trong hộp thư đến nghĩa là thành công.

Giải quyết vấn đề gửi mail bị chậm

Để gửi một email thông qua SMTP có thể mất đến vài giây trong trường hợp tiêu cực, nếu như vậy thì nó sẽ làm block luồng xử lý yêu cầu đang gọi gửi email như vậy làm khả năng phục vụ của toàn bộ hệ thống gặp vấn đề, sẽ có những yêu cầu đến sau phài chờ đợi rất lâu.
Để giải quyết vấn đề này chúng ta phải sử dụng kỹ thuật lập trình sử dụng blocking queue và đa luồng để tách phần gửi mail ra khỏi luồng xử lý, lúc này mã nguồn của EmailService sẽ như sau:

package vn.techmaster.mail.service;

import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@Service
public class EmailService {

    private final JavaMailSender mailSender;
    private final BlockingQueue<SimpleMailMessage> queue;

    public EmailService(JavaMailSender mailSender) {
        this.mailSender = mailSender;
        this.queue = new LinkedBlockingQueue<>();
        this.start();
    }

    private void start() {
        Thread newThread = new Thread(() -> {
           while (true) {
               try {
                   SimpleMailMessage mail = queue.take();
                   mailSender.send(mail);
                   System.out.println("sent mail: " + mail);
               } catch (InterruptedException e) {
                   break;
               } catch (Throwable e) {
                   System.out.println("send mail error: " + e);
               }
           }
        });
        newThread.setName("mail-sender");
        newThread.start();
    }

    public void sendMail(
        String from,
        String to,
        String subject,
        String text
    ) {
        SimpleMailMessage mail = new SimpleMailMessage();
        mail.setFrom(from);
        mail.setTo(to);
        mail.setSubject(subject);
        mail.setText(text);
        queue.add(mail);
    }
}

Ở đây khi chúng ta gọi hàm sendMail, chúng ta sẽ không ngay lập tức gửi email đi mà lưu nó lại ở trong hàng đợi để được xử lý trong luồng khác có tên là mail-sender.

Tổng kết

Như vậy chúng ta đã cùng nhau tạo tìm hiểu và gửi email với spring boot.


Cám ơn bạn đã quan tâm đến bài viết|video này. Để nhận được thêm các kiến thức bổ ích bạn có thể:

  1. Đọc các bài viết của TechMaster trên facebook: https://www.facebook.com/techmastervn
  2. Xem các video của TechMaster qua Youtube: https://www.youtube.com/@TechMasterVietnam nếu bạn thấy video/bài viết hay bạn có thể theo dõi kênh của TechMaster để nhận được thông báo về các video mới nhất nhé.
  3. Chat với techmaster qua Discord: https://discord.gg/yQjRTFXb7a