1. 程式人生 > 實用技巧 >Spring Boot 傳送郵件

Spring Boot 傳送郵件

Maven 依賴

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

如果需要指定版本,也可以從mvn repo中找到你需要的版本號。

Spring Mail 服務簡介

Spring mail 是Spring 框架提供的一個程式庫,用於傳送電子郵件,使我們不受底層郵件系統的限制,只關注客戶端進行資源處理。Spring mail 包的內容如下:

  • MailSender 介面:核心介面,提供用於傳送簡單電子郵件的基本功能。
  • JavaMailSender 介面:上述MailSender的子介面。它支援MIME訊息,並且通常與MimeMessageHelper類結合使用以建立MimeMessage。
  • JavaMailSenderImpl 類:提供JavaMailSender介面的實現。它支援MimeMessage和SimpleMailMessage。
  • SimpleMailMessage類:用於建立簡單的郵件,包括from(傳送者),to(接收者),cc(抄送),subject(主題)和text(文字)等欄位。
  • MimeMessagePreparator
    介面:提供用於接收MIME訊息的回撥介面。
  • MimeMessageHelper類:用於建立MIME訊息的幫助器類。它提供在HTML佈局中對影象,典型郵件附件和文字內容的支援。

郵件服務配置

引入maven依賴之後,下一步就是使用spring.mail.*namespace 在 application.properties 檔案中配置郵件服務。

spring:
  mail:
    default-encoding: UTF-8
    #郵件伺服器的地址:例如smtp.qq.com,smtp.gmail.com
    host: localhost
    #登陸伺服器的使用者名稱和密碼
    username: username
    password: password
    port: 25
    properties:
      mail:
        debug: false
        smtp:
          debug: false
          auth: true
          #啟用tls連線
          starttls: true
    protocol: smtp
    test-connection: false

傳送郵件

傳送簡單郵件

@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendSimpleMessage() {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("[email protected]");
        message.setTo("[email protected]");
        message.setSubject("Test send simple mail message");
        message.setText("Hello world!");

        javaMailSender.send(message);
    }
}

傳送附件郵件

 @Override
    public void sendMessageWithAttachment() {
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setTo("[email protected]");
            helper.setFrom("[email protected]");
            helper.setSubject("Send attachment file to email");
            helper.setText("attachment file...");

            FileSystemResource file = new FileSystemResource(new File("Absolute path"));
            helper.addAttachment("Invoice", file);
            
			javaMailSender.send(message);
        } catch (MessagingException ex) {
            logger.error("Failed to send email to. error={}", ex.getMessage());
        }
    }

傳送模板郵件

Spring 中可以作為郵件模板的有幾個選擇:Velocity,Freemarker,Thymeleaf。 SpringBoot 1.4.0以後 Velocity 廢棄了,官方建議用Freemarker。而Thymeleaf的效率沒有freemaker高(評測見參考文章【4】)。

Freemarker 的語法可以參考官網的手冊:https://freemarker.apache.org/docs/index.html
中文手冊:https://sourceforge.net/projects/freemarker/files/chinese-manual/

同樣,我們先引入 Freemarker 的 Maven 依賴。

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

然後在專案的 /resoource/templates 目錄下新增一個 Freemarker 模板檔案 notification.flt

<html>
<head>
  <title>Hello world!</title>
</head>
<body>
  <h1>Hello</h1>
  <p>My name is ${name}</p>
 </body>
</html>

在 SpringBoot 的配置檔案中加上 Freemarker 的相關配置:

spring:
  freemarker:
    template-loader-path: classpath:/templates/
    enabled: true
    cache: false
    charset: UTF-8
    content-type: text/html
    check-template-location: true

EmailServiceImpl 中使用 Freemarker 模板傳送郵件:

@Service
public class MailServiceImpl implements MailService {

    private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @Override
    public void sendMessageWithFreemarkerTemplate() {
        MimeMessage message = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            helper.setTo("[email protected]");
            helper.setFrom("[email protected]");
            helper.setSubject("Send freemarker template to email");

            HashMap<String, Object> models = new HashMap<>();
            models.put("name", "freemarker");

            Template template = freeMarkerConfigurer.getConfiguration().getTemplate("notification.flt");
            String text = FreeMarkerTemplateUtils.processTemplateIntoString(template, models);
            
            helper.setText(text);
            javaMailSender.send(message);
        } catch (Exception ex) {
            logger.error("Failed to send email to. error={}", ex.getMessage());
        }
    }
}

至此實現了三中方式:純文字,富文字(圖片/附件),Freemarker模版的郵件傳送功能,接下來就來測試一下我們的郵件是否能傳送出去吧。

測試郵件傳送服務

我們為了測試郵件服務的傳送功能,暫時可以先不用使用真正的郵件伺服器,而是換成GreenMail
GreenMail是用於測試目的的電子郵件伺服器,可以用於郵件整合測試或用於開發的輕量級沙盒郵件伺服器。具體的使用方法可以參考官網上的用例

這裡先引入GreenMail 的Maven依賴:

<dependency>
	<groupId>com.icegreen</groupId>
	<artifactId>greenmail</artifactId>
	<version>1.5.11</version>
	<scope>test</scope>
</dependency>

在Spring boot 的測試檔案(application-test.yaml)中配置用於郵件服務的相關屬性。

spring:
  mail:
    default-encoding: UTF-8
    host: localhost
    username: [email protected]
    password: password
    port: 3025
    properties:
      mail:
        debug: false
        smtp:
          debug: false
          auth: true
          starttls: true
    protocol: smtp
    test-connection: false

我們建立一個自定義的 JUnit Rule 來初始化和停止GreenMail郵件伺服器。

public class SmtpServerRule extends ExternalResource {

	# 設定傳送郵件服務的使用者的使用者名稱
    private static final String USER_PASSWORD = "password";
    # 設定傳送郵件服務使用者的密碼
    private static final String USER_NAME = "[email protected]";

    private GreenMail smtpServer;

    @Override
    protected void before() throws Throwable {
        super.before();
        smtpServer = new GreenMail(ServerSetupTest.SMTP);
        smtpServer.start();
        // setup user on the mail server
        smtpServer.setUser(USER_NAME, USER_PASSWORD);
    }

    public MimeMessage[] getMessage() {
        return smtpServer.getReceivedMessages();
    }

    @Override
    protected void after() {
        super.after();
        smtpServer.stop();
    }
}

然後就可以開始寫我們的測試用例了。
我們使用JUnit @Rule註解配置SmtpServerRule。這標記了在每個整合測試之前和之後要呼叫的自定義規則。並允許我們攔截傳入的電子郵件。最後,我們做出一些斷言並驗證傳送的電子郵件是否等於接收的電子郵件。

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class MailServiceImplTest {

    @Rule
    public SmtpServerRule smtpServerRule = new SmtpServerRule();

    @Autowired
    private MailService mailService;

    @Test
    public void sendSimpleMessage() throws MessagingException {
        mailService.sendSimpleMessage();

        MimeMessage[] messages = smtpServerRule.getMessage();
        assertEquals("Test send simple mail message", messages[0].getSubject());
        assertEquals("[email protected]", messages[0].getFrom()[0].toString());
        assertEquals("[email protected]", messages[0].getAllRecipients()[0].toString());
    }
}

另外的兩種郵件參考上面的程式碼實現。

總結

在這篇文章中,我們展示瞭如何通過Spring Boot應用程式設定和傳送電子郵件。所有這些示例和程式碼片段的實現都可以在MyGitHub專案中找到。

參考文章

【1】Testing mail code in Spring Boot application

【2】Spring Mail Integration Testing with JUnit and GreenMail Example

【3】Guide to Spring Email

【4】SpringBoot開發案例之整合mail傳送服務