一:郵件發送
毋庸置疑,在一個企業級的管理後臺中,企業發送郵件是必要的的。在沒有spring Mail之前,javaMail發送郵件的步驟是繁瑣的。後來spring整合了相關的Mail之後,其API接口方式就變得很簡單了。其實springboot2.x版本整合spring Mail還是很簡單的。這裏主要還是說明一下一些具體邏輯的處理:
關於下面的三個箭頭,我想就不用說明了吧,其實很核心的東西就在這個異步執行中。在企業郵件中我們會因爲各種原因導致郵件發送不出去,如網絡問題等,如果郵件沒有發送出去的話,我我們如何進行二次甚至多次發送呢?
在多數的企業中採用了MQ的消費模式來進行處理。這裏對於應用級別未達到使用tasker+redis實現郵件重發。具體實現:如果郵件發送出現異常,就將該條記錄存儲到Redis中,定時任務查詢,如果有就發送,發送正常就刪除該條K。
一些實現的邏輯說明了,我們直接上代碼吧
二:代碼
1.pom引入
<!--springboot爲2.0.6-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.yml配置
spring.mail.host=smtp.163.com //qq則爲smtp.qq.com,其中qq需要開啓smtp
spring.mail.password=mxz123456ccc
[email protected]
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
3.方法接口
package com.config.mail.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.config.mail.model.MyMailProperties;
import com.config.mail.service.MailConService;
import javax.mail.internet.MimeMessage;
/**
* 實現類
* @author Owner
*
*/
@Service
public class MailConServiceImpl implements MailConService {
private final static Logger logger = LoggerFactory.getLogger(MailConServiceImpl.class);
@Autowired
private MailProperties mailProperties;
@Autowired
private JavaMailSender javaMailSender;
/**
* 發送簡單文本的郵件
* @param to
* @param subject
* @param content
* @return
*/
@Override
public boolean send(String to, String subject, String content) {
logger.info("## Ready to send mail ...");
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
// 郵件發送來源
simpleMailMessage.setFrom(mailProperties.getUsername());
// 郵件發送目標
simpleMailMessage.setTo(to);
// 設置標題
simpleMailMessage.setSubject(subject);
// 設置內容
simpleMailMessage.setText(content);
try {
// 發送
javaMailSender.send(simpleMailMessage);
logger.info("=====================>Send the mail success ...");
} catch (Exception e) {
logger.error("Send mail error: ", e);
return false;
}
return true;
}
@Override
@Async("taskExecutor")
public boolean sendToSome(String[] tos, String subject, String content) {
for(String snedTo:tos) {
this.send(snedTo, subject, content);
}
return false;
}
/**
* 發送 html 的郵件
* @param to
* @param subject
* @param html
* @return
*/
@Override
public boolean sendWithHtml(String to, String subject, String html) {
logger.info("## Ready to send mail ...");
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = null;
try {
mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
// 郵件發送來源
mimeMessageHelper.setFrom(mailProperties.getUsername());
// 郵件發送目標
mimeMessageHelper.setTo(to);
// 設置標題
mimeMessageHelper.setSubject(subject);
// 設置內容,並設置內容 html 格式爲 true
mimeMessageHelper.setText(html, true);
javaMailSender.send(mimeMessage);
logger.info("## Send the mail with html success ...");
} catch (Exception e) {
e.printStackTrace();
logger.error("Send html mail error: ", e);
return false;
}
return true;
}
/**
* 發送帶有圖片的 html 的郵件
* @param to
* @param subject
* @param html
* @param cids
* @param filePaths
* @return
*/
@Override
public boolean sendWithImageHtml(String to, String subject, String html, String[] cids, String[] filePaths) {
logger.info("## Ready to send mail ...");
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = null;
try {
mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
// 郵件發送來源
mimeMessageHelper.setFrom(mailProperties.getUsername());
// 郵件發送目標
mimeMessageHelper.setTo(to);
// 設置標題
mimeMessageHelper.setSubject(subject);
// 設置內容,並設置內容 html 格式爲 true
mimeMessageHelper.setText(html, true);
// 設置 html 中內聯的圖片
for (int i = 0; i < cids.length; i++) {
FileSystemResource file = new FileSystemResource(filePaths[i]);
mimeMessageHelper.addInline(cids[i], file);
}
javaMailSender.send(mimeMessage);
logger.info("## Send the mail with image success ...");
} catch (Exception e) {
e.printStackTrace();
logger.error("Send html mail error: ", e);
return false;
}
return true;
}
/**
* 發送帶有附件的郵件
* @param to
* @param subject
* @param content
* @param filePaths
* @return
*/
@Override
public boolean sendWithWithEnclosure(String to, String subject, String content, String[] filePaths) {
logger.info("## Ready to send mail ...");
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = null;
try {
mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
// 郵件發送來源
mimeMessageHelper.setFrom(mailProperties.getUsername());
// 郵件發送目標
mimeMessageHelper.setTo(to);
// 設置標題
mimeMessageHelper.setSubject(subject);
// 設置內容
mimeMessageHelper.setText(content);
// 添加附件
for (int i = 0; i < filePaths.length; i++) {
FileSystemResource file = new FileSystemResource(filePaths[i]);
String attachementFileName = "附件" + (i + 1);
mimeMessageHelper.addAttachment(attachementFileName, file);
}
javaMailSender.send(mimeMessage);
logger.info("## Send the mail with enclosure success ...");
} catch (Exception e) {
logger.error("Send html mail error: ", e);
return false;
}
return true;
}
}
4.測試用例
package system;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import com.Application;
import com.config.mail.service.MailConService;
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = Application.class)
public class MailTests {
@Autowired
private MailConService mailService;
/**
* 測試簡單文本郵件發送
*/
@Test
public void send() {
String to = "[email protected]";
String title = "標題: 簡單文本郵件發送測試";
String content = "簡單文本 ...";
Assert.assertTrue(mailService.send(to, title, content));
}
// /**
// * 測試html郵件發送
// */
// @Test
// public void sendHtml() {
// String to = "[email protected]";
// String title = "標題: html郵件發送測試";
//
// String htmlContent = "<html><body><h1>歡迎關注微信公衆號: 小哈學Java</h1></body></html>";
//
// Assert.assertTrue(mailService.sendWithHtml(to, title, htmlContent));
// }
/**
* 測試html郵件發送
*/
@Test
public void sendImageHtml() {
String to = "[email protected]";
String title = "標題: 帶圖片的html郵件發送測試";
String htmlContent = "<html><body>" +
"<h1>歡迎關注微信公衆號: 小哈學Java</h1>" +
"<p><h2 style='color: red;'>圖片1</h2><img style='width: 280px; height: 280px;' src='cid:test'></p>" +
"<p><h2 style='color: red;'>圖片2</h2><img style='width: 280px; height: 280px;' src='cid:test2'></p>" +
"</body></html>";
// cid 要與上面 html 中的 cid 對應,否則設置圖片不成功
String[] cids = new String[]{
"test",
};
// 文件路徑
String[] filePaths = new String[]{
"D:\\1.jpg",
};
Assert.assertTrue(mailService.sendWithImageHtml(to, title, htmlContent, cids, filePaths));
}
// /**
// * 測試添加附件的郵件發送
// */
// @Test
// public void sendWithWithEnclosure() {
// String to = "[email protected]";
// String title = "標題: 帶有附件的郵件發送測試";
// String content = "帶有附件的郵件發送測試";
//
// // 添加兩個附件
// String[] filePaths = new String[]{
// "D:\\1.jpg"
//
// };
//
// Assert.assertTrue(mailService.sendWithWithEnclosure(to, title, content, filePaths));
// }
}
4.關鍵點說明
網上,很多博客說需要整合Thymeleaf或者freemark實現郵件模板。實則個人認爲沒有必要,因爲一旦模板設置死了,想改就很難,這裏我建議使用一個富文本來保存一些常用的模板。
5.自定義加載數據庫中的發送人信息
一般企業級郵箱,都是用的企業郵箱來發送的,那麼配置文件中寫死了也沒有關係,但是如果我們需要後面在數據庫中動態配置發送人郵箱,怎麼辦?我們來看一下源碼,這方法視線中有這樣一個Bean:
這個Bean的源碼,我們來看一下:
好吧大概是明白了,是從Yml配置文件中讀取spting mail先關的配置信息,那麼我們重寫一個子類重寫其方法:
package com.config.mail.model;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
/**
* 自定義加載郵箱配置,重寫加載配置文件,一般都從數據庫讀取
* @author Owner
*
*/
@Service
@Primary
public class MyMailProperties extends MailProperties {
public void setUsername(String username) {
super.setUsername("[email protected]");
}
}
我這裏是寫死了的,大家可以從數據庫或者緩存中記載過來。當然了發方法接口也要稍微修改一下:
// @Autowired
// private MailProperties mailProperties;
@Autowired
private MyMailProperties mailProperties;
6.定時任務
定時任務的邏輯已經分析過了,這裏就不做實現可。