Gửi email trong Spring Boot

Giới thiệu

Cách đơn giản nhất để gửi và nhận email trong Spring Boot là sử dụng spring-boot-starter-mail.

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

spring-boot-starter-mail thực chất sử dụng JavaMail (javax.mail). Nếu bạn muốn tìm hiểu thêm về JavaMail, bạn có thể tham khảo: Hướng dẫn sử dụng JavaMail

API

Spring Framework cung cấp một cách tiếp cận đơn giản để gửi email bằng cách sử dụng giao diện JavaMailSender, đây là API chính để gửi email.

Các API được cung cấp bởi giao diện JavaMailSender như sau:

img

Cấu hình

Spring Boot cung cấp cấu hình tự động và mô-đun khởi động cho JavaMailSender.

Nếu spring.mail.host và các thư viện liên quan (được xác định bởi spring-boot-starter-mail) có sẵn, Spring Boot sẽ tạo ra một JavaMailSender mặc định (nếu chưa tồn tại). Bạn có thể tùy chỉnh người gửi bằng cách sử dụng các cấu hình trong không gian tên spring.mail.
Đặc biệt là, một số giá trị timeout mặc định là vô hạn, bạn có thể thay đổi chúng để tránh việc máy chủ email không phản hồi và làm chặn luồng, như ví dụ sau:

spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000

Bạn cũng có thể sử dụng cấu hình phiên bản hiện có trong JNDI cho JavaMailSender:

spring.mail.jndi-name=mail/Session

Dưới đây là các cấu hình liên quan đến Mail trong Spring Boot:

Để biết thêm thông tin chi tiết, vui lòng xem MailProperties.

# Email (MailProperties)
spring.mail.default-encoding=UTF-8 # Default MimeMessage encoding.
spring.mail.host= # SMTP server host. For instance, `smtp.example.com`.
spring.mail.jndi-name= # Session JNDI name. When set, takes precedence over other Session settings.
spring.mail.password= # Login password of the SMTP server.
spring.mail.port= # SMTP server port.
spring.mail.properties.*= # Additional JavaMail Session properties.
spring.mail.protocol=smtp # Protocol used by the SMTP server.
spring.mail.test-connection=false # Whether to test that the mail server is available on startup.
spring.mail.username= # Login user of the SMTP server.
 

Triển khai

Thêm các phụ thuộc

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
 
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <dependency>
    <groupId>com.github.dozermapper</groupId>
    <artifactId>dozer-spring-boot-starter</artifactId>
    <version>6.4.0</version>
  </dependency>
</dependencies>

Cấu hình thuộc tính email

Thêm tệp cấu hình application-163.properties vào thư mục src/main/resources, nội dung như sau:

spring.mail.host = smtp.163.com
spring.mail.username = xxxxxx
spring.mail.password = xxxxxx
spring.mail.properties.mail.smtp.auth = true
spring.mail.properties.mail.smtp.starttls.enable = true
spring.mail.properties.mail.smtp.starttls.required = true
spring.mail.default-encoding = UTF-8
 
mail.domain = 163.com
mail.from = ${spring.mail.username}@${mail.domain}

Lưu ý: Thay thế spring.mail.usernamespring.mail.password bằng tên người dùng và mật khẩu hợp lệ.

Tệp cấu hình application-163.properties đại diện cho cấu hình khi sử dụng hộp thư 163. Để kích hoạt nó, cần sử dụng spring.profiles.active = 163.

Thêm tệp cấu hình application.properties vào thư mục src/main/resources, nội dung như sau:

spring.profiles.active = 163

Java Code

Trước tiên, chúng ta cần đọc một số thuộc tính cấu hình, phương thức như sau:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
 
@Validated
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
    private String domain;
    private String from;
 
    public String getDomain() {
        return domain;
    }
 
    public void setDomain(String domain) {
        this.domain = domain;
    }
 
    public String getFrom() {
        return from;
    }
 
    public void setFrom(String from) {
        this.from = from;
    }
}

Tiếp theo, định nghĩa một lớp thực thể tham số email (sử dụng lombok để rút gọn getter, setter):

import lombok.Data;
import java.util.Date;
 
@Data
public class MailDTO {
    private String from;
    private String replyTo;
    private String[] to;
    private String[] cc;
    private String[] bcc;
    private Date sentDate;
    private String subject;
    private String text;
    private String[] filenames;
}

Sau đó, triển khai giao diện chức năng gửi email:

import com.github.dozermapper.core.Mapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
 
import javax.mail.MessagingException;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.IOException;
 
@Service
public class MailService {
 
    private final Logger log = LoggerFactory.getLogger(this.getClass());
 
    @Autowired
    private MailProperties mailProperties;
 
    @Autowired
    private JavaMailSender javaMailSender;
 
    @Autowired
    private Mapper mapper;
 
    public void sendSimpleMailMessage(MailDTO mailDTO) {
        SimpleMailMessage simpleMailMessage = mapper.map(mailDTO, SimpleMailMessage.class);
        if (StringUtils.isEmpty(mailDTO.getFrom())) {
            mailDTO.setFrom(mailProperties.getFrom());
        }
        javaMailSender.send(simpleMailMessage);
    }
 
    public void sendMimeMessage(MailDTO mailDTO) {
 
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(mimeMessage, true);
 
            if (StringUtils.isEmpty(mailDTO.getFrom())) {
                messageHelper.setFrom(mailProperties.getFrom());
            }
            messageHelper.setTo(mailDTO.getTo());
            messageHelper.setSubject(mailDTO.getSubject());
 
            mimeMessage = messageHelper.getMimeMessage();
            MimeBodyPart mimeBodyPart = new MimeBodyPart();
            mimeBodyPart.setContent(mailDTO.getText(), "text/html;charset=UTF-8");
 
            // Mô tả mối quan hệ dữ liệu
            MimeMultipart mm = new MimeMultipart();
            mm.setSubType("related");
            mm.addBodyPart(mimeBodyPart);
 
            // Thêm tệp đính kèm email
            for (String filename : mailDTO.getFilenames()) {
                MimeBodyPart attachPart = new MimeBodyPart();
                try {
                    attachPart.attachFile(filename);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mm.addBodyPart(attachPart);
            }
            mimeMessage.setContent(mm);
            mimeMessage.saveChanges();
 
        } catch (MessagingException e) {
            e.printStackTrace();
        }
 
        javaMailSender.send(mimeMessage);
    }
}