? ?互聯(lián)網(wǎng)發(fā)展到現(xiàn)在,相必大家都知道發(fā)送郵件應(yīng)該是網(wǎng)站的必備功能之一:用戶(hù)注冊(cè)發(fā)送郵箱驗(yàn)證、忘記密碼、監(jiān)控提醒以及發(fā)送營(yíng)銷(xiāo)信息等。
? ?Spring Email抽象的核心是MailSender接口,MailSender的實(shí)現(xiàn)能夠把Email發(fā)送給郵件服務(wù)器,由郵件服務(wù)器實(shí)現(xiàn)郵件發(fā)送的功能。
? ?早期發(fā)送郵件是通過(guò)Java自帶的JavaMail類(lèi)來(lái)發(fā)送郵件的,需要自己封裝消息體;
? ?后來(lái)Spring推出了JavaMailSender類(lèi)大大簡(jiǎn)化了發(fā)送郵件的過(guò)程,JavaMailSender繼承自MailSender,提供了更強(qiáng)大的郵件發(fā)送功能,可支持不同類(lèi)型的郵件發(fā)送。再到現(xiàn)在的Spring Boot又對(duì)其進(jìn)行封裝從而出現(xiàn)了spring-boot-starter-mail,進(jìn)一步優(yōu)化和完善郵件發(fā)送功能。
一、郵箱授權(quán)
在集成郵件服務(wù)前,需要獲取郵箱的授權(quán)碼。
? ?1、163郵箱步驟
? ?163郵箱- > 設(shè)置 - > 郵箱安全設(shè)置 - >客戶(hù)端授權(quán)密碼 - > 開(kāi)啟客戶(hù)端授權(quán)碼 - > 填寫(xiě)授權(quán)碼。

? ?2、QQ郵箱步驟
QQ郵箱 - > 設(shè)置 - > 賬戶(hù)- >POP3/SMTP服務(wù):開(kāi)啟服務(wù)后會(huì)獲得QQ的授權(quán)碼。

二、搭建準(zhǔn)備
? ?1、pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
? ?2、配置文件
spring.mail.host=smtp.163.com
# 郵箱地址
spring.mail.username=****@qq.com
# 郵箱授權(quán)碼
spring.mail.password=****
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.default-encoding=UTF-8
? ?3、創(chuàng)建郵件發(fā)送Bean
public class MailBean implements Serializable {
private static final long serialVersionUID = -2116367492649751914L;
private String recipient;//郵件接收人
private String subject; //郵件主題
private String content; //郵件內(nèi)容
// 省略setget方法
}
三、文本郵件發(fā)送
??Spring已經(jīng)幫我們內(nèi)置了JavaMailSender,直接在項(xiàng)目中引用即可。有了JavaMailSender,那么郵件發(fā)送就是一件再簡(jiǎn)單不過(guò)的事情了。我們只需要將JavaMailSender的Bean注入到我們自己的實(shí)現(xiàn)類(lèi)中,然后使用JavaMail API來(lái)發(fā)送Email。
@Component
public class MailUtil {
@Value("${spring.mail.username}")
private String MAIL_SENDER; //郵件發(fā)送者
@Autowired
private JavaMailSender javaMailSender;
private Logger logger = LoggerFactory.getLogger(MailUtil.class);
/**
* 發(fā)送文本郵件
*
* @param mailBean
*/
public void sendSimpleMail(MailBean mailBean) {
try {
SimpleMailMessage mailMessage= new SimpleMailMessage();
mailMessage.setFrom(MAIL_SENDER);
mailMessage.setTo(mailBean.getRecipient());
mailMessage.setSubject(mailBean.getSubject());
mailMessage.setText(mailBean.getContent());
//mailMessage.copyTo(copyTo);
javaMailSender.send(mailMessage);
} catch (Exception e) {
logger.error("郵件發(fā)送失敗", e.getMessage());
}
}
}
其中:
from:即為郵件發(fā)送者,一般設(shè)置在配置文件中
to:郵件接收者,此參數(shù)可以為數(shù)組,同時(shí)發(fā)送多人
subject:郵件主題
content:郵件的主體
copyTo:抄送人
- 文本郵件測(cè)試類(lèi)
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMailApplicationTests {
@Autowired
private MailUtil mailUtil;
@Autowired
private TemplateEngine templateEngine;
//接收人
private static final String RECIPINET = "****@163.com";
/**
* 發(fā)送文本郵件
*/
@Test
public void sendSimpleMail() {
MailBean mailBean = new MailBean();
mailBean.setRecipient(RECIPINET);
mailBean.setSubject("SpringBootMail之這是一封文本的郵件");
mailBean.setContent("SpringBootMail發(fā)送一個(gè)簡(jiǎn)單格式的郵件,時(shí)間為:" + DateUtils.format(new Date()));
mailUtil.sendSimpleMail(mailBean);
}
}
-
稍微等待幾秒,就可以在郵箱中找到此郵件內(nèi)容了。至此一個(gè)簡(jiǎn)單的文本郵件發(fā)送就完成了。
四、HTML格式郵件發(fā)送
? ? 與文本格式郵件代碼對(duì)比,富文本HTML郵件發(fā)送使用MimeMessageHelper類(lèi),把setText()方法的消息文本設(shè)置為html,并將第二個(gè)參數(shù)設(shè)置為true,表示這是html的富文本。MimeMessageHelper支持發(fā)送復(fù)雜郵件模板,支持文本、附件、HTML、圖片等。
public void sendHTMLMail(MailBean mailBean) {
MimeMessage mimeMailMessage = null;
try {
mimeMailMessage = javaMailSender.createMimeMessage();
//true 表示需要?jiǎng)?chuàng)建一個(gè)multipart message
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
mimeMessageHelper.setFrom(MAIL_SENDER);
mimeMessageHelper.setTo(mailBean.getRecipient());
mimeMessageHelper.setSubject(mailBean.getSubject());
//郵件抄送
//mimeMessageHelper.addCc("抄送人");
mimeMessageHelper.setText(mailBean.getContent(), true);
javaMailSender.send(mimeMailMessage);
} catch (Exception e) {
logger.error("郵件發(fā)送失敗", e.getMessage());
}
}
- HTML格式郵件測(cè)試類(lèi)
@Test
public void sendHTMLMail() {
MailBean mailBean = new MailBean();
mailBean.setRecipient(RECIPINET);
mailBean.setSubject("SpringBootMailHTML之這是一封HTML格式的郵件");
StringBuilder sb = new StringBuilder();
sb.append("<h2>SpirngBoot測(cè)試郵件HTML</h2>")
.append("<p style='text-align:left'>這是一封HTML郵件...</p>")
.append("<p> 時(shí)間為:"+ DateUtils.format(new Date()) +"</p>");
mailBean.setContent(sb.toString());
mailUtil.sendHTMLMail(mailBean);
}
-
郵件內(nèi)容寫(xiě)了一段話(huà),下面為接收到的效果:
由此我們發(fā)現(xiàn)發(fā)送HTML郵件,就是需要拼接一段HTML的String字符串交給MimeMessageHelper來(lái)處理,最后由郵件客戶(hù)端負(fù)責(zé)渲染顯示內(nèi)容。
五、附件格式郵件發(fā)送
? ? 發(fā)送附件需要用到FileSystemResource類(lèi)對(duì)文件進(jìn)行封裝,再添加到MimeMessageHelper中??梢酝ㄟ^(guò)多個(gè)addAttachment方法發(fā)送多個(gè)附件,File.separator是用來(lái)分隔同一個(gè)路徑字符串中的目錄。
public void sendAttachmentMail(MailBean mailBean) {
MimeMessage mimeMailMessage = null;
try {
mimeMailMessage = javaMailSender.createMimeMessage();
//true 表示需要?jiǎng)?chuàng)建一個(gè)multipart message
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
mimeMessageHelper.setFrom(MAIL_SENDER);
mimeMessageHelper.setTo(mailBean.getRecipient());
mimeMessageHelper.setSubject(mailBean.getSubject());
mimeMessageHelper.setText(mailBean.getContent());
//文件路徑 目前寫(xiě)死在代碼中,之后可以當(dāng)參數(shù)傳過(guò)來(lái),或者在MailBean中添加屬性absolutePath
String absolutePath = "D:\\Program Files\\test.jpg";
FileSystemResource file = new FileSystemResource(new File(absolutePath));
//FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/image/email.png"));
String fileName = absolutePath.substring(absolutePath.lastIndexOf(File.separator));
//添加附件,第一個(gè)參數(shù)表示添加到 Email 中附件的名稱(chēng),第二個(gè)參數(shù)是圖片資源
mimeMessageHelper.addAttachment(fileName, file);
//多個(gè)附件
//mimeMessageHelper.addAttachment(fileName1, file1);
javaMailSender.send(mimeMailMessage);
} catch (Exception e) {
logger.error("郵件發(fā)送失敗", e.getMessage());
}
}
- 測(cè)試郵件發(fā)送
@Test
public void sendAttachmentMail(){
MailBean mailBean = new MailBean();
mailBean.setRecipient(RECIPINET);
mailBean.setSubject("SpringBootMail之這是一封有附件格式的郵件");
mailBean.setContent("SpringBootMail發(fā)送一封有附件格式的郵件,時(shí)間為:"+ DateUtils.format(new Date()));
mailUtil.sendAttachmentMail(mailBean);
}
-
效果圖如下:
六、靜態(tài)資源格式郵件發(fā)送
? ? 郵件格式的靜態(tài)資源,需要用到MimeMessageHelper中的addInline方法。需要注意的是:添加內(nèi)聯(lián)資源,一個(gè)id對(duì)應(yīng)一個(gè)資源,最終通過(guò)id來(lái)找到該資源。
? ? 即<img src='cid:"+ rscId + "' >和addInline(rscId,res)中的rscId要一致。
同時(shí)要添加多個(gè)圖片,可以使用多條<img src='cid:"+ rscId + "' >和addInline(rscId,res)來(lái)實(shí)現(xiàn)。
public void sendInlineMail(MailBean mailBean) {
MimeMessage mimeMailMessage = null;
try {
mimeMailMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
mimeMessageHelper.setFrom(MAIL_SENDER);
mimeMessageHelper.setTo(mailBean.getRecipient());
mimeMessageHelper.setSubject(mailBean.getSubject());
mimeMessageHelper.setText(mailBean.getContent(), true);
//文件路徑
String absolutePath = "D:\\Program Files\\email.png";
FileSystemResource file = new FileSystemResource(new File(absolutePath));
//FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/image/email.png"))
//添加多個(gè)圖片可以使用多條 <img src='cid:" + rscId + "' > 和
mimeMessageHelper.addInline(rscId, res) 來(lái)實(shí)現(xiàn)
mimeMessageHelper.addInline("picture", file);
javaMailSender.send(mimeMailMessage);
} catch (Exception e) {
logger.error("郵件發(fā)送失敗", e.getMessage());
}
}
- 靜態(tài)資源格式郵件發(fā)送
@Test
public void sendInlineMail() {
MailBean mailBean = new MailBean();
//id,目前寫(xiě)死了,可根據(jù)需要封裝
String rscId = "picture";
String content="<html><body>這是有圖片的郵件:<img src=\'cid:" + rscId + "\' ></body></html>";
mailBean.setRecipient(RECIPINET);
mailBean.setSubject("SpringBootMail之這是一封有靜態(tài)資源格式的郵件");
mailBean.setContent(content);
mailUtil.sendInlineMail(mailBean);
}
-
返回結(jié)果如下:
七、Thymeleaf模板郵件發(fā)送
? ? 上述介紹HTML格式的郵件不太優(yōu)雅,修改起來(lái)也很不便,并且HTML硬編碼在程序中。另外模板也適用于局部變化的內(nèi)容,例如某云的郵件提示

更改郵件內(nèi)容時(shí)只需更改用戶(hù)名和鏈接地址即可。
- 添加依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 創(chuàng)建email.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 th:text="|尊敬的${username} :|"></h3><br />
<img src="http://gtms02.alicdn.com/tps/i2/T1YoblFq4cXXa94Hfd-32-32.png" /> 您有代金券即將到期,逾期失效,請(qǐng)盡早使用。<a th:href = "${url}" >點(diǎn)此查看</a>
<br />
</body>
</html>
-
解析模板并發(fā)送
注意:Context類(lèi)是在org.thymeleaf.context.Context包下的。process第一個(gè)參數(shù)名稱(chēng)要和templates下的模板頁(yè)面視圖名稱(chēng)一致,要不然會(huì)報(bào)錯(cuò)。
@Test
public void sendTemplate2Mail() {
//注意:Context 類(lèi)是在org.thymeleaf.context.Context包下的。
Context context = new Context();
//html中填充動(dòng)態(tài)屬性值
context.setVariable("username", "碼農(nóng)用戶(hù)");
context.setVariable("url", "https://www.aliyun.com/?utm_content=se_1000301881");
//注意:process第一個(gè)參數(shù)名稱(chēng)要和templates下的模板名稱(chēng)一致。要不然會(huì)報(bào)錯(cuò)
//org.thymeleaf.exceptions.TemplateInputException: Error resolving template [email]
String emailContent = templateEngine.process("email", context);
MailBean mailBean = new MailBean();
mailBean.setRecipient(RECIPINET);
mailBean.setSubject("主題:這是模板郵件");
mailBean.setContent(emailContent);
mailUtil.sendHTMLMail(mailBean);
}
-
返回結(jié)果如下:
八、常見(jiàn)問(wèn)題

九、總結(jié)
? ?使用 Spring Boot 集成發(fā)送郵件的功能非常簡(jiǎn)單,只需要簡(jiǎn)單編碼就可以實(shí)現(xiàn)發(fā)送普通文本郵件、帶附件郵件、HTML 格式郵件、帶圖片郵件等。
? ?如果需要做成一個(gè)郵件系統(tǒng)還需要考慮很多因素,比如:郵箱發(fā)送失敗重試機(jī)制、防止郵件被識(shí)別為垃圾郵件,固定時(shí)間內(nèi)發(fā)送郵件的限制等。
? ?在微服務(wù)架構(gòu)中,常常將一些基礎(chǔ)功能下沉下來(lái),作為獨(dú)立的服務(wù)來(lái)使用,郵件系統(tǒng)作為平臺(tái)的基礎(chǔ)功能,特別適合做為獨(dú)立的微服務(wù)來(lái)支持整個(gè)系統(tǒng)。
注意啦! 往期SpringBoot在這里





