Springboot整合實(shí)現(xiàn)郵件發(fā)送的原理詳解
通常在實(shí)際項(xiàng)目中,也有其他很多地方會(huì)用到郵件發(fā)送,比如通過郵件注冊(cè)賬戶/找回密碼,通過郵件發(fā)送訂閱信息等等。SpringBoot集成郵件服務(wù)非常簡(jiǎn)單,通過簡(jiǎn)單的學(xué)習(xí)即可快速掌握郵件業(yè)務(wù)類的核心邏輯和企業(yè)郵件的日常服務(wù)
開發(fā)前準(zhǔn)備
首先注冊(cè)發(fā)件郵箱并設(shè)置客戶端授權(quán)碼,這里以QQ 免費(fèi)郵箱為例,其他的郵箱的配置也大同小異。
登錄 QQ 郵箱,點(diǎn)擊設(shè)置->賬戶,開啟IMAP/SMTP服務(wù),并生成授權(quán)碼。

基礎(chǔ)知識(shí)
電子郵件需要在郵件客戶端和郵件服務(wù)器之間,以及兩個(gè)郵件服務(wù)器之間進(jìn)行郵件傳遞,那就必須要遵守一定的規(guī)則,這個(gè)規(guī)則就是郵件傳輸協(xié)議。下面我們分別簡(jiǎn)單介紹幾種協(xié)議:
- 什么是SMTP? SMTP全稱為Simple Mail Transfer Protocol(簡(jiǎn)單郵件傳輸協(xié)議),它是一組用于從源地址到目的地址傳輸郵件的規(guī)范,通過它來控制郵件的中轉(zhuǎn)方式。SMTP認(rèn)證要求必須提供賬號(hào)和密碼才能登陸服務(wù)器,其設(shè)計(jì)目的在于避免用戶受到垃圾郵件的侵?jǐn)_。
- 什么是IMAP? IMAP全稱為Internet Message Access Protocol(互聯(lián)網(wǎng)郵件訪問協(xié)議),IMAP允許從郵件服務(wù)器上獲取郵件的信息、下載郵件等。IMAP與POP類似,都是一種郵件獲取協(xié)議。
- 什么是POP3? POP3全稱為Post Office Protocol 3(郵局協(xié)議),POP3支持客戶端遠(yuǎn)程管理服務(wù)器端的郵件。POP3常用于“離線”郵件處理,即允許客戶端下載服務(wù)器郵件,然后服務(wù)器上的郵件將會(huì)被刪除。目前很多POP3的郵件服務(wù)器只提供下載郵件功能,服務(wù)器本身并不刪除郵件,這種屬于改進(jìn)版的POP3協(xié)議。
- IMAP和POP3協(xié)議有什么不同呢? 兩者最大的區(qū)別在于,IMAP允許雙向通信,即在客戶端的操作會(huì)反饋到服務(wù)器上,例如在客戶端收取郵件、標(biāo)記已讀等操作,服務(wù)器會(huì)跟著同步這些操作。而對(duì)于POP協(xié)議雖然也允許客戶端下載服務(wù)器郵件,但是在客戶端的操作并不會(huì)同步到服務(wù)器上面的,例如在客戶端收取或標(biāo)記已讀郵件,服務(wù)器不會(huì)同步這些操作。
用戶要在Internet上提供電子郵件功能,必須有專門的電子郵件服務(wù)器。這些郵件服務(wù)器就類似于現(xiàn)實(shí)生活中的郵局,它主要負(fù)責(zé)接收用戶投遞過來的郵件,并把郵件投遞到郵件接收者的電子郵箱中。
郵件服務(wù)器就好像是互聯(lián)網(wǎng)世界的郵局。按照功能劃分,郵件服務(wù)器可以劃分為兩種類型:
SMTP郵件服務(wù)器:用戶替用戶發(fā)送郵件和接收外面發(fā)送給本地用戶的郵件。 POP3/IMAP郵件服務(wù)器:用戶幫助用戶讀取SMTP郵件服務(wù)器接收進(jìn)來的郵件。
進(jìn)階知識(shí)
- 什么是
JavaMailSender和JavaMailSenderImpl?JavaMailSender和JavaMailSenderImpl是Spring官方提供的集成郵件服務(wù)的接口和實(shí)現(xiàn)類,以簡(jiǎn)單高效的設(shè)計(jì)著稱,目前是Java后端發(fā)送郵件和集成郵件服務(wù)的主流工具。 - 如何通過
JavaMailSenderImpl發(fā)送郵件? 非常簡(jiǎn)單,直接在業(yè)務(wù)類注入JavaMailSenderImpl并調(diào)用send方法發(fā)送郵件。其中簡(jiǎn)單郵件可以通過SimpleMailMessage來發(fā)送郵件,而復(fù)雜的郵件(例如添加附件)可以借助MimeMessageHelper來構(gòu)建MimeMessage發(fā)送郵件。例如:
@Autowired
private JavaMailSenderImpl mailSender;
@Override
public void sendInlineAndAttachMail(String to, String subject, String content, String filePath,String rscPath, String rscId) {
logger.info("發(fā)送帶圖片郵件開始:{},{},{},{},{}", to, subject, content, rscPath, rscId);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = file.getFilename();
helper.addAttachment(fileName, file);
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);//重復(fù)使用添加多個(gè)圖片
mailSender.send(message);
logger.info("發(fā)送帶圖片和附件郵件成功");
} catch (MessagingException e) {
logger.error("發(fā)送帶圖片和附件郵件失敗", e);
}
}
為什么JavaMailSenderImpl 能夠開箱即用 ? 所謂開箱即用其實(shí)就是基于官方內(nèi)置的自動(dòng)配置,翻看源碼可知曉郵件自動(dòng)配置類(MailSenderPropertiesConfiguration) 為上下文提供了郵件服務(wù)實(shí)例(JavaMailSenderImpl)。具體源碼如下:
@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
private final MailProperties properties;
MailSenderPropertiesConfiguration(MailProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
applyProperties(sender);
return sender;
}
其中MailProperties是關(guān)于郵件服務(wù)器的配置信息,具體源碼如下:
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private String host;
private Integer port;
private String username;
private String password;
private String protocol = "smtp";
private Charset defaultEncoding = DEFAULT_CHARSET;
private Map<String, String> properties = new HashMap<>();
}
Spring Boot 集成郵件發(fā)送主要分為以下三步:
加入依賴
pom.xml依賴spring-boot-starter-mail模塊:
<!--javax.mail 郵件發(fā)送-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置郵件
在配置文件 application.properties 中配置郵件的相關(guān)參數(shù),其中指定了郵件的協(xié)議、端口以及郵件賬戶和授權(quán)碼等。具體內(nèi)容如下:
#郵件配置 #SMTP服務(wù)器地址 spring.mail.host=smtp.qq.com #登陸賬號(hào) spring.mail.username=2590742958@qq.com #注意這里不是郵箱密碼,而是SMTP授權(quán)密碼 spring.mail.password=lvlpxkujplqbdh spring.mail.default-encoding=UTF-8 #開啟加密驗(yàn)證 spring.mail.properties.mail.smtp.ssl.enable=true #以下項(xiàng)不用改動(dòng) spring.mail.properties.mail.smtp.starttls.enable: true spring.mail.roperties.mail.smtp.starttls.required: true
編寫郵件發(fā)送service,contorller類等。
public class MailServiceImpl implements MailService {
private final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
//使用@Value注入application.properties中指定的用戶名
@Value("${spring.mail.username}")
private String from;
@Autowired
//用于發(fā)送文件
private JavaMailSender mailSender;
@Override
public void sendAttachmentMail(String to, String subject, String content, String filePath) {
logger.info("發(fā)送帶附件郵件開始:{},{},{},{}", to, subject, content, filePath);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = file.getFilename();
helper.addAttachment(fileName, file);//添加附件,可多次調(diào)用該方法添加多個(gè)附件
mailSender.send(message);
logger.info("發(fā)送帶附件郵件成功");
} catch (MessagingException e) {
logger.error("發(fā)送帶附件郵件失敗", e);
}
在發(fā)送郵件的同時(shí),我們可以自定義參數(shù)從而生成豐富多彩的郵件,如下
public interface MailService {
/**
* 發(fā)送普通文本郵件
* @param to 收件人
* @param subject 主題
* @param content 內(nèi)容
*/
void sendSimpleMail(String to, String subject, String content);
/**
* 發(fā)送HTML郵件
* @param to 收件人
* @param subject 主題
* @param content 內(nèi)容(可以包含<html>等標(biāo)簽)
*/
void sendHtmlMail(String to, String subject, String content);
/**
* 發(fā)送帶附件的郵件
* @param to 收件人
* @param subject 主題
* @param content 內(nèi)容
* @param filePath 附件路徑
*/
void sendAttachmentMail(String to, String subject, String content, String filePath);
/**
* 發(fā)送帶圖片的郵件
* @param to 收件人
* @param subject 主題
* @param content 文本
* @param rscPath 圖片路徑
* @param rscId 圖片ID,用于在<img>標(biāo)簽中使用,從而顯示圖片
*/
void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId);
/**
* 發(fā)送帶圖片的郵件
* @param to 收件人
* @param subject 主題
* @param content 文本
* @param rscPath 圖片路徑
* @param filePath 附件路徑
* @param rscId 圖片ID,用于在<img>標(biāo)簽中使用,從而顯示圖片
*/
void sendInlineAndAttachMail(String to, String subject, String content,String filePath, String rscPath, String rscId);
}
測(cè)試郵件發(fā)送
編寫控制器層,這里使用的是Thymeleaf模板郵件,是常見的模板郵件,比如說我們注冊(cè)賬戶,登錄認(rèn)證所收到的郵件即為模板郵件,特點(diǎn)就是內(nèi)容不變,只是一些特點(diǎn)信息比如說驗(yàn)證碼、認(rèn)證鏈接等是動(dòng)態(tài)變化的。在模板頁面中,id是動(dòng)態(tài)變化的,需要我們傳參設(shè)置,其實(shí)就是傳參后,將頁面解析為HTML字符串,作為我們郵件發(fā)送的主體內(nèi)容
@Controller
public class MailContorller {
@Autowired
private MailService mailService;
@Autowired
private TemplateEngine templateEngine;
@Resource
private UserService userService;
//這一步是獲取application.properties中設(shè)置的發(fā)件人郵箱地址
@Value("${spring.mail.username}")
private String Email;
@RequestMapping("/sendTemplate")
/** 指定模板發(fā)送郵件 */
public String sendTemplate(@RequestParam("Email") String Email, Model model) {
//具體的業(yè)務(wù)
User usermail= userService.retrieve(Email);
System.out.println(usermail);
if (usermail !=null){
//向Thymeleaf模板傳值,并解析成字符串
//通過Context構(gòu)造模版中變量需要的值
Context context = new Context();
context.setVariable("id", "001");
String emailContent = templateEngine.process("emailTemplate", context);
mailService.sendHtmlMail(Email,"密碼找回驗(yàn)證", emailContent);
return "Login";
}
else if(StringUtils.isEmpty(Email)){
model.addAttribute("yuoxiang","郵箱信息不能為空");
return "Login";
}
else {
model.addAttribute("yuoxiang","郵箱錯(cuò)誤或者與綁定賬號(hào)不一致");
return "Login";
}
}
然后我們需要在template文件夾下創(chuàng)建emailTemplate.html,設(shè)計(jì)我們需求的模板樣式
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>密碼驗(yàn)證</title>
</head>
<body>
<span style="color:#5ed02b;font-weight:600;font-size: 18px">您好,歡迎您的查看,這是一封驗(yàn)證郵件,請(qǐng)根據(jù)下面系統(tǒng)找回的密碼完成登錄,感謝您的支持!</span><br>
</body>
</html>
調(diào)用發(fā)送復(fù)雜郵件方法后,根據(jù)獲取動(dòng)態(tài)輸入的郵箱地址,成功后就可以在 QQ 郵箱中收到郵件:

總結(jié):Springboot整合郵件發(fā)送的原理和實(shí)現(xiàn)

以上就是Springboot整合實(shí)現(xiàn)郵件發(fā)送的原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Springboot郵件發(fā)送的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解SpringBoot時(shí)間參數(shù)處理完整解決方案
這篇文章主要介紹了詳解SpringBoot時(shí)間參數(shù)處理完整解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Java動(dòng)態(tài)字節(jié)碼注入技術(shù)的實(shí)現(xiàn)
Java動(dòng)態(tài)字節(jié)碼注入技術(shù)是一種在運(yùn)行時(shí)修改Java字節(jié)碼的技術(shù),本文主要介紹了Java動(dòng)態(tài)字節(jié)碼注入技術(shù)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08
SpringMVC中的@ControllerAdvice使用場(chǎng)景詳解
這篇文章主要介紹了SpringMVC中的@ControllerAdvice使用場(chǎng)景詳解,在Spring?MVC進(jìn)行調(diào)用的過程中,會(huì)有很多的特殊的需求,比如全局異常,分頁信息和分頁搜索條件,請(qǐng)求時(shí)帶來返回時(shí)還得回顯頁面,需要的朋友可以參考下2024-01-01
mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實(shí)現(xiàn)
XML 文件在解析時(shí)會(huì)將五種特殊字符進(jìn)行轉(zhuǎn)義,本文主要介紹了mybatis(mybatis-plus)映射文件(XML文件)中特殊字符轉(zhuǎn)義的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
Springboot整合FreeMarker的實(shí)現(xiàn)示例
本文主要介紹了Springboot整合FreeMarker的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
理解JDK動(dòng)態(tài)代理為什么必須要基于接口
這篇文章主要介紹了理解JDK動(dòng)態(tài)代理為什么必須要基于接口,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
詳解Kotlin:forEach也能break和continue
這篇文章主要介紹了詳解Kotlin:forEach也能break和continue的相關(guān)資料,需要的朋友可以參考下2017-06-06

