Spring Boot整合郵件配置
概述
這個技術是做什么?學習該技術的原因,技術的難點在哪里。
這個技術能使項目具備發送郵件的功能,這個技術我是作為技術儲備來學習的,沒想到在學習后沒多久就能夠有用武之地。該項技術總體難度不大,硬要說難的地方就在於整合模板引擎發送模板郵件,因為還要同時了解一些模板引擎的知識,不過如果有JSP相關知識會容易應付得多。
整合郵件發送功能
Spring Boot 2.x集成了mail模塊
在pom.xml中引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
郵箱配置
一些必要的名詞解釋
-
什么是POP3、SMTP和IMAP?
他們是三種郵件協議。簡單來說,POP3和IMAP是用來從服務器上下載郵件的。SMTP適用於發送或中轉信件時找到下一個目的地。所以我們發送郵件應該使用SMTP協議。 -
什么是郵箱客戶端授權碼?
郵箱客戶端授權碼是為了避免郵箱密碼被盜后,盜號者通過客戶端登錄郵箱而設計的安防功能。
QQ郵箱配置
網頁登錄QQ郵箱→設置→開啟相應服務並生成授權碼
spring boot配置:
spring:
mail:
host: smtp.qq.com #發送郵件服務器
username: xx@qq.com #QQ郵箱
password: xxxxxxxxxxx #客戶端授權碼
protocol: smtp #發送郵件協議
properties.mail.smtp.auth: true
properties.mail.smtp.port: 465 #端口號465或587
properties.mail.display.sendmail: aaa #可以任意
properties.mail.display.sendname: bbb #可以任意
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true #開啟SSL
default-encoding: utf-8
網易系(126/163/yeah)郵箱配置
網頁登錄網易郵箱→設置→POP3/SMTP/IMAP
spring boot配置:
spring:
mail:
host: smtp.126.com #發送郵件服務器
username: xx@126.com #網易郵箱
password: xxxxxxxx #客戶端授權碼
protocol: smtp #發送郵件協議
properties.mail.smtp.auth: true
properties.mail.smtp.port: 994 #465或者994
properties.mail.display.sendmail: aaa #可以任意
properties.mail.display.sendname: bbb #可以任意
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true #開啟SSL
default-encoding: utf-8
from: xx@126.com
- 126郵箱SMTP服務器地址:smtp.126.com
- 163郵箱SMTP服務器地址:smtp.163.com
- yeah郵箱SMTP服務器地址:smtp.yeah.net
發送簡單的文本郵件
寫個郵件服務Service
@Service
public class MailService {
// Spring官方提供的集成郵件服務的實現類,目前是Java后端發送郵件和集成郵件服務的主流工具。
@Resource
private JavaMailSender mailSender;
// 從配置文件中注入發件人的姓名
@Value("${spring.mail.username}")
private String fromEmail;
/**
* 發送文本郵件
*
* @param to 收件人
* @param subject 標題
* @param content 正文
* @throws MessagingException
*/
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(fromEmail); // 發件人
message.setTo(to);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
}
在業務中調用該服務的方法即可
mailService.sendSimpleMail("xxxxxx@xx.com","普通文本郵件","普通文本郵件內容");
發送html郵件
為了方便,在原來的Service里直接添加一個方法
/**
* 發送html郵件
*/
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
//注意這里使用的是MimeMessage
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
//第二個參數:格式是否為html
helper.setText(content, true);
mailSender.send(message);
}
調用該方法,直接傳入html代碼的字符串作為正文參數:
mailService.sendHtmlMail("xxxxxx@xx.com","一封html測試郵件","
"<div style=\"text-align: center;position: absolute;\" >\n"
+"<h3>\"一封html測試郵件\"</h3>\n"
+ "<div>一封html測試郵件</div>\n"
+ "</div>");
像上面直接傳遞html字符串發送html郵件,在java類里寫html代碼總有點怪怪的,而且有很明顯的缺點,若是要用相同樣式發送不同的內容,代碼冗余度就會增加;而且若是需要發送一個復雜的html頁面,代碼看起來就一團亂麻,而且不方便調整郵件的樣式。
我們希望html和java分離開,在java里就只管java,頁面代碼乖乖到頁面文件里面,需要時直接調取該頁面文件,整合模板引擎就是一個不錯的解決方案。👇
發送基於模板的郵件(以模板引擎freemarker為例)
該方法本質上還是發送html郵件,只不過是有一個把模板轉換成html字符串的過程,thymeleaf也可以實現。這個方法還能使你的系統發出的郵件更加美觀。
說明:這里不詳細介紹freemarker的內容,在這里只描述它的一個使用場景——生成電子郵件,想要進一步了解freemarker請行學習
添加依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
springboot配置
spring:
freemarker:
cache: false # 緩存配置 開發階段應該配置為false 因為經常會改
suffix: .html # 模版后綴名 默認為ftl
charset: UTF-8 # 文件編碼
template-loader-path: classpath:/templates/ # 存放模板的文件夾,以resource文件夾為相對路徑
在存放模板的文件夾下寫一個html模板
內容如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>freemarker簡單示例</title>
</head>
<body>
<h1>Hello Freemarker</h1>
<div>My name is ${myname}</div>
</body>
</html>
仍然為了方便,在原來的Service里直接添加代碼
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Test
public void sendTemplateMail(String to, String subject, String template) throws IOException, TemplateException, MessagingException {
// 獲得模板
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(template);
// 使用Map作為數據模型,定義屬性和值
Map<String,Object> model = new HashMap<>();
model.put("myname","ZYF");
// 傳入數據模型到模板,替代模板中的占位符,並將模板轉化為html字符串
String templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template,model);
// 該方法本質上還是發送html郵件,調用之前發送html郵件的方法
this.sendHtmlMail(to, subject, templateHtml);
}
要用的時候調用即可
mailService.sendTemplateMail("xxxxx@xx.com", "基於模板的html郵件", "fremarkertemp.html");
發送帶附件的郵件
話不多說上代碼:
/**
* 發送帶附件的郵件
*/
public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
//要帶附件第二個參數設為true
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
mailSender.send(message);
}
調用時傳入文件路徑:
String filePath = "D:\\projects\\springboot\\template.png";
mailService.sendAttachmentsMail("xxxx@xx.com", "帶附件的郵件", "郵件中有附件", filePath);
郵箱服務實戰
這是我某次實踐中郵箱服務的運用,目的是為了能夠定時發送郵件,由於發送郵件是耗時操作,為了不妨礙系統處理用戶請求,添加了@Async注解,定時任務將會在獨立的線程中被執行,下面放上鏈接:
我的踩坑記錄
郵件服務器連接失敗
org.springframework.mail.MailSendException: Mail server connection failed;
...
nested exception is:
java.net.UnknownHostException: smtp.163.com
...
-
網絡問題
控制台輸入
ping smtp.163.com
看看是否能ping通; -
配置問題
檢查一下application.yml的郵件服務器配置有沒有拼寫或格式錯誤(比如多按了一個空格);
開啟SSL時使用587端口時是無法連接QQ郵件服務器的,請使用465端口。
授權失敗
org.springframework.mail.MailAuthenticationException: Authentication failed;nested exception is
javax.mail.AuthenticationFailedException: 550 User has no permission
...
這個坑是我在教同學時遇到的
按照上文去打開郵箱的stmp服務即可解決
消息發送失敗
org.springframework.mail.MailSendException: Failed messages:
com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 163 smtp11,D8CowACX7CmSHB5b3SrlCA--.26635S3
1528700051,please see http://mail.163.com/help/help_spam_16.htm?ip=182.138.102.204&hostid=smtp11&time=1528700051
...
點進報錯信息提供的網址瞧瞧,是網易官方的退信代碼說明,也就是說我們發送的消息被退回來了:
注意到報錯信息的退信代碼554,看看554是啥來頭:
原來是被識別為垃圾郵件了,檢查一下郵件的主題及內容,使用合法信息,我當時是因為郵件內容包含test、測試這些字眼所以被攔截了。
總結
spring boot整合郵件服務並不難,就是踩到坑的時候挺煩的,但這也是學習新知識所必須經歷的。
參考鏈接
Spring Boot的特性:發送郵件,Arvin Chen