SpringBoot實現(xiàn)郵件推送的詳細代碼
SpringBoot實現(xiàn)郵件推送
在項目中經(jīng)常會遇到SpringBoot推送消息的業(yè)務(wù),除了站內(nèi)推送通知,郵件推送也是一種常見的方式,本次小編就帶大家實現(xiàn)郵件推送。
引入依賴
<!-- spring mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
spring-boot-starter-mail:- 作用:提供了使用Spring Framework的郵件發(fā)送功能的起步依賴。
- 功能:使得在Spring Boot應(yīng)用中可以輕松地配置和使用郵件發(fā)送功能,包括發(fā)送簡單文本郵件、HTML郵件、附件郵件等。
- 使用:結(jié)合Spring的郵件模塊,你可以方便地在你的應(yīng)用程序中集成郵件發(fā)送功能,無論是用于發(fā)送通知、驗證郵件還是其他目的。
spring-boot-starter-thymeleaf:- 作用:提供了使用Thymeleaf模板引擎的起步依賴。
- 功能:Thymeleaf是一種流行的Java模板引擎,用于在Web應(yīng)用中創(chuàng)建動態(tài)HTML模板。
- 使用:結(jié)合Spring Boot和Thymeleaf,你可以使用Thymeleaf的模板語言來生成動態(tài)內(nèi)容,比如渲染服務(wù)器端數(shù)據(jù)到HTML頁面上,以便在Web應(yīng)用中更靈活地展示數(shù)據(jù)。
在項目中,使用第二個依賴再結(jié)合靜態(tài)的html文件就可以實現(xiàn),將郵件以預(yù)定義模板的形式發(fā)送出去。

在實際中只需要將對應(yīng)的值以Map的方式填入到對應(yīng)字段中即可,別急~接下來會帶大家實現(xiàn)的。
配置
在項目配置中加入如下配置
yml格式如下:
spring:
# 郵箱配置
mail:
host: smtp.qq.com
# 用戶名 替換成你實際的用戶名
username: test@foxmail.com
# 授權(quán)碼 可以去官方申請 不是個人郵箱密碼
password: xxxxxxxxxx
application.properties文件格式如下:
# 需要開啟 smtp qq郵箱為例 spring.mail.host=smtp.qq.com spring.mail.port=465 # 發(fā)件人的郵箱 spring.mail.username=xxxxx # qq 郵箱的第三方授權(quán)碼 并非個人密碼 spring.mail.password=xxxx #開啟ssl 否則 503 錯誤 但是實際測試發(fā)現(xiàn)其實不加也不會報錯 但是最好還是加上 spring.mail.properties.mail.smtp.ssl.enable=true
代碼具體實現(xiàn)
創(chuàng)建郵件實體封裝類
package com.ican.model.dto;
?
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
?
import java.util.Map;
?
/**
* 郵箱DTO
* @author xiayexiaolu
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "郵箱DTO")
public class MailDTO {
?
/**
* 接收者郵箱號
*/
@ApiModelProperty(value = "接收者郵箱號")
private String toEmail;
?
/**
* 主題
*/
@ApiModelProperty(value = "主題")
private String subject;
?
/**
* 內(nèi)容
*/
@ApiModelProperty(value = "內(nèi)容")
private String content;
?
/**
* 內(nèi)容信息
*/
@ApiModelProperty(value = "內(nèi)容信息")
private Map<String, Object> contentMap;
?
/**
* 郵件模板
*/
@ApiModelProperty(value = "郵件模板")
private String template;
}
?
創(chuàng)建郵件服務(wù)接口并實現(xiàn)
package com.ican.service;
?
import com.ican.model.dto.MailDTO;
?
/**
* 郵件服務(wù)接口
*
* @author xiaoyexiaolu
**/
public interface EmailService {
?
/**
* 發(fā)送簡單郵件
*
* @param mailDTO 郵件信息
*/
void sendSimpleMail(MailDTO mailDTO);
?
/**
* 發(fā)送HTML郵件
*
* @param mailDTO 郵件信息
*/
void sendHtmlMail(MailDTO mailDTO);
}
?
對接口進行實現(xiàn),下面為模板代碼,可直接使用:
package com.ican.service.impl;
?
import com.ican.model.dto.MailDTO;
import com.ican.service.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
?
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
?
/**
* 郵件服務(wù)接口實現(xiàn)類
*
* @author xiayexiaolu
**/
@Service
public class EmailServiceImpl implements EmailService {
?
/**
* 郵箱號
*/
@Value("${spring.mail.username}")
private String email;
?
@Autowired
private JavaMailSender javaMailSender;
?
@Autowired
private TemplateEngine templateEngine;
?
@Override
public void sendSimpleMail(MailDTO mailDTO) {
SimpleMailMessage simpleMail = new SimpleMailMessage();
simpleMail.setFrom(email);
simpleMail.setTo(mailDTO.getToEmail());
simpleMail.setSubject(mailDTO.getSubject());
simpleMail.setText(mailDTO.getContent());
javaMailSender.send(simpleMail);
}
?
@Override
public void sendHtmlMail(MailDTO mailDTO) {
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage);
Context context = new Context();
context.setVariables(mailDTO.getContentMap());
String process = templateEngine.process(mailDTO.getTemplate(), context);
mimeMessageHelper.setFrom(email);
mimeMessageHelper.setTo(mailDTO.getToEmail());
mimeMessageHelper.setSubject(mailDTO.getSubject());
mimeMessageHelper.setText(process, true);
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
其實到這里發(fā)送郵件就已經(jīng)能用了,但是如果使用原生發(fā)送郵件的方式可能會有少許缺點。使用消息隊列有以下好處
- 異步處理:通過消息隊列,你可以將郵件發(fā)送操作異步化,即使發(fā)送郵件的過程比較耗時,也不會阻塞主線程,提高了應(yīng)用程序的響應(yīng)速度和吞吐量。
- 解耦:使用消息隊列可以將郵件發(fā)送操作解耦合,發(fā)送郵件的業(yè)務(wù)邏輯與其他業(yè)務(wù)邏輯相互獨立。這意味著你可以輕松地更改或擴展郵件發(fā)送的實現(xiàn)方式,而不影響其他業(yè)務(wù)邏輯。
- 負載均衡:通過消息隊列,你可以將郵件發(fā)送請求分發(fā)到多個郵件發(fā)送服務(wù)節(jié)點上,從而實現(xiàn)負載均衡,提高了系統(tǒng)的穩(wěn)定性和可用性。
- 削峰填谷:在高并發(fā)情況下,郵件發(fā)送請求可能會突然增加,而消息隊列可以幫助平滑處理這種突發(fā)情況,避免郵件服務(wù)器過載。
- 失敗處理:使用消息隊列可以更好地處理郵件發(fā)送失敗的情況。如果郵件發(fā)送失敗,你可以通過消息隊列實現(xiàn)重試機制或者將失敗的消息重新放回隊列,以便稍后再次嘗試發(fā)送。
使用消息隊列實現(xiàn)郵件發(fā)送
額外引入依賴
<!-- spring amqp -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${saToken.version}</version>
</dependency>
這個依賴會自動地添加所需的 RabbitMQ 客戶端庫,并配置好Spring Boot的AMQP支持。
在配置中配置連接
spring:
# rabbitmq配置
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
listener:
simple:
retry:
enabled: true
# 重試間隔時間
initial-interval: 3000
# 最大重試次數(shù)
max-attempts: 3
創(chuàng)建郵件消費者
package com.ican.consumer;
import com.ican.model.dto.MailDTO;
import com.ican.service.EmailService;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import static com.ican.constant.MqConstant.*;
/**
* 郵件消費者
* @author xiayexiaolu
*/
@Component
public class EmailConsumer {
@Autowired
private EmailService emailService;
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue(value = EMAIL_SIMPLE_QUEUE, durable = "true", autoDelete = "false"),
exchange = @Exchange(value = EMAIL_EXCHANGE, type = ExchangeTypes.TOPIC),
key = EMAIL_SIMPLE_KEY
)})
public void listenSendSimpleEmail(@Payload MailDTO mail) {
emailService.sendSimpleMail(mail);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue(value = EMAIL_HTML_QUEUE, durable = "true", autoDelete = "false"),
exchange = @Exchange(value = EMAIL_EXCHANGE, type = ExchangeTypes.TOPIC),
key = EMAIL_HTML_KEY
)})
public void listenSendHtmlEmail(@Payload MailDTO mail) {
emailService.sendHtmlMail(mail);
}
}
@Component注解表示這是一個 Spring 組件,會被 Spring 掃描并納入到應(yīng)用程序的上下文中。@Autowired注解注入了一個EmailService對象,用于實際發(fā)送郵件的邏輯處理。- 使用了
@RabbitListener注解標注了兩個方法,分別用于監(jiān)聽兩個隊列中的消息。這兩個方法分別處理發(fā)送簡單郵件和發(fā)送 HTML 郵件的邏輯。 - 在
@RabbitListener注解中,通過@QueueBinding注解配置了隊列與交換機的綁定關(guān)系,指定了隊列的屬性和交換機的名稱、類型、路由鍵等信息。 - 在方法參數(shù)中使用
@Payload注解,指定了消息體的類型為MailDTO,這樣方法參數(shù)就會自動解析為消息體的內(nèi)容。
具體使用
首先需要創(chuàng)建一個郵件對象
MailDTO mailDTO = new MailDTO();
mailDTO.setToEmail("目標郵箱");
mailDTO.setSubject("郵件主題");
mailDTO.setTemplate("郵件使用的模板"); //這里需要在之前加入了thymeleaf依賴支持
mailDTO.setContentMap(contentMap);
// 這里的contentMap是一個HashMap 也是最重要的參數(shù),用于將值映射到模板中 具體示例如下圖所示


然后直接使用代碼:
// 發(fā)送HTML郵件 rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO);
背后的原理
郵件發(fā)送(生產(chǎn)者) :
- 當你執(zhí)行
rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO);時,實際上是將mailDTO對象發(fā)送到了 RabbitMQ 中的EMAIL_EXCHANGE交換機,并使用EMAIL_HTML_KEY路由鍵。 - 這個過程是異步的,即發(fā)送操作執(zhí)行后就會立即返回,而不會等待郵件真正發(fā)送完成。
- 當你執(zhí)行
郵件消費者:
- 通過
@RabbitListener注解,你的郵件消費者監(jiān)聽了名為EMAIL_HTML_QUEUE的隊列。 - 當有消息到達隊列時,
listenSendHtmlEmail方法會被調(diào)用,并傳入消息體mailDTO。 - 在
listenSendHtmlEmail方法中,調(diào)用了emailService.sendHtmlMail(mail)方法來實際發(fā)送郵件。
- 通過
消息傳遞:
- RabbitMQ 確保了消息傳遞的可靠性和順序性。當你發(fā)送一條消息到交換機時,RabbitMQ 會根據(jù)路由規(guī)則將消息路由到對應(yīng)的隊列中去。
- 郵件消費者監(jiān)聽隊列,一旦有消息到達隊列,就會立即觸發(fā)消費者方法的執(zhí)行,從而實現(xiàn)郵件發(fā)送的過程。
總的來說,執(zhí)行 rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO); 之后,程序并不會自動調(diào)用消費者中的代碼,而是將消息發(fā)送到 RabbitMQ 中,并觸發(fā)消費者的監(jiān)聽。一旦有消息到達隊列,消費者會立即執(zhí)行對應(yīng)的消費方法,完成郵件發(fā)送的過程。
小結(jié)
本文介紹了如何在Spring Boot項目中實現(xiàn)郵件推送功能。首先,通過引入相關(guān)依賴,包括spring-boot-starter-mail和spring-boot-starter-thymeleaf,使得項目具備了發(fā)送郵件和使用Thymeleaf模板的能力。然后,配置了郵件服務(wù)的連接信息,包括郵箱的主機、端口、用戶名和授權(quán)碼等。接著,創(chuàng)建了郵件實體封裝類MailDTO,定義了郵件的相關(guān)信息。通過郵件服務(wù)接口EmailService和其實現(xiàn)類EmailServiceImpl,實現(xiàn)了發(fā)送簡單郵件和HTML郵件的功能。此外,還介紹了使用消息隊列來異步處理郵件發(fā)送的好處,以及如何通過RabbitMQ實現(xiàn)郵件發(fā)送的異步處理。最后,通過具體的代碼示例,展示了如何在項目中使用消息隊列發(fā)送郵件,并給出了發(fā)送郵件的具體步驟。
以上就是SpringBoot實現(xiàn)郵件推送的詳細代碼的詳細內(nèi)容,更多關(guān)于SpringBoot郵件推送的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用java和sqlserver建立簡易圖書管理系統(tǒng)的完整步驟
圖書館管理系統(tǒng)是圖書館管理工作中不可缺少的部分,它對于圖書館的管理者和使用者都非常重要,下面這篇文章主要給大家介紹了關(guān)于利用java和sqlserver建立簡易圖書管理系統(tǒng)的完整步驟,需要的朋友可以參考下2022-06-06
Java性能優(yōu)化之數(shù)據(jù)結(jié)構(gòu)實例代碼
這篇文章主要介紹了Java性能優(yōu)化之數(shù)據(jù)結(jié)構(gòu)實例代碼,具有一定借鑒價值,需要的朋友可以參考下2018-01-01

