整合郵件傳送功能
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註解,定時任務將會在獨立的執行緒中被執行,下面放上鍊接:
ScheduleJob.java
MailServiceImpl.java
EmailTemplate.html
application.yml
我的踩坑記錄
郵件伺服器連線失敗
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整合郵件服務並不難,就是踩到坑的時候挺煩的,但這也是學習新知識所必須經歷的