SpringBoot+mail 輕松實現(xiàn)各類郵件自動推送
一、簡介
在實際的項目開發(fā)過程中,經(jīng)常需要用到郵件通知功能。例如,通過郵箱注冊,郵箱找回密碼,郵箱推送報表等等,實際的應(yīng)用場景非常的多。
早期的時候,為了能實現(xiàn)郵件的自動發(fā)送功能,通常會使用 JavaMail 相關(guān)的 api 來完成。后來 Spring 推出的 JavaMailSender 工具,進一步簡化了郵件的自動發(fā)送過程,調(diào)用其 send 方法即可發(fā)送郵件。再之后, Spring Boot 針對郵件推送功能推出了spring-boot-starter-mail
工具包,開發(fā)者可以通過它來快速實現(xiàn)郵件發(fā)送服務(wù)。
今天通過這篇文章,我們一起來學(xué)習(xí)如何在 Spring Boot 中快速實現(xiàn)一個自動發(fā)送郵件的功能。
二、環(huán)境準(zhǔn)備
在介紹郵件推送實現(xiàn)之前,我們需要先準(zhǔn)備一臺郵件推送的服務(wù)器,以便實現(xiàn)相關(guān)功能。
這里以騰訊郵箱為例,將其作為郵件發(fā)送的中轉(zhuǎn)平臺。
2.1、開啟 SMTP 服務(wù)
登陸騰訊郵箱,打開【設(shè)置】-》【收發(fā)信設(shè)置】,開啟 SMTP 服務(wù),最后點擊【保存更改】。
2.2、生成客戶端專用密碼
點擊【設(shè)置】-》【賬戶】,進入頁面后點擊【開啟安全登陸】,點擊【生成新密碼】。
這個新密碼會用于郵箱的自動發(fā)送,因此需要記錄下來,最后點擊【保存更改】。
2.3、相關(guān)擴展知識
- 什么是 SMTP?
SMTP(simple mail transfer protocol),也被稱為簡單郵件傳輸協(xié)議,主要用于發(fā)送電子郵件的,通過它可以實現(xiàn)郵件的發(fā)送或者中轉(zhuǎn)。遵循 SMTP 協(xié)議的服務(wù)器,通常稱為發(fā)送郵件服務(wù)器。
- 什么是 POP3?
POP3(Post Office Protocol),一種郵局通信協(xié)議。主要用于接受電子郵件的,POP3 允許用戶從服務(wù)器上把郵件存儲到自己的計算機上,同時刪除保存在郵件服務(wù)器上的郵件。同理,遵循 POP3 協(xié)議的服務(wù)器,通常稱為接收郵件服務(wù)器。
- 什么是 IMAP?
IMAP(Internet Mail Access Protocol),一種交互式郵件存取協(xié)議。與 POP3 協(xié)議類似,主要用于接收電子郵件,稍有不同的是:IMAP 允許電子郵件客戶端收取的郵件仍然保留在服務(wù)器上,同時在客戶端上的操作都會反饋到服務(wù)器上,例如刪除郵件,標(biāo)記已讀等,服務(wù)器上的郵件也會做相應(yīng)的動作。所以無論從瀏覽器登錄郵箱或者客戶端軟件登錄郵箱,看到的郵件以及狀態(tài)都是一致的。
總結(jié)下來就是:SMTP 負(fù)責(zé)發(fā)送郵件,POP3/IMAP 負(fù)責(zé)接收郵件。
常見郵箱發(fā)、收服務(wù)器如下!
三、郵件推送實現(xiàn)
用于發(fā)送郵件的服務(wù)器、賬戶和密碼準(zhǔn)備好了之后,就可以正式使用了。下面我們以 Spring Boot 的 2.1.0
版本為基礎(chǔ),實現(xiàn)過程如下。
2.1、添加依賴包
在pom.xml
文件中,添加spring-boot-starter-mail
依賴包。
<!--mail 支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
2.2、添加相關(guān)配置
在application.properties
中添加郵箱相關(guān)配置。
# 配置郵件發(fā)送主機地址 spring.mail.host=smtp.exmail.qq.com # 配置郵件發(fā)送服務(wù)端口號 spring.mail.port=465 # 配置郵件發(fā)送服務(wù)協(xié)議 spring.mail.protocol=smtp # 配置郵件發(fā)送者用戶名或者賬戶 spring.mail.username=xxx@qq.com # 配置郵件發(fā)送者密碼或者授權(quán)碼 spring.mail.password=xxxxxxx # 配置郵件默認(rèn)編碼 spring.mail.default-encoding=UTF-8 # 配置smtp相關(guān)屬性 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.ssl.enable=true spring.mail.properties.mail.smtp.ssl.required=true
2.3、簡單發(fā)送一封郵件
通過單元測試來實現(xiàn)一封簡單郵件的發(fā)送,示例如下:
@RunWith(SpringRunner.class) @SpringBootTest public class MailSimpleTest { @Autowired private JavaMailSender mailSender; @Test public void sendSimpleMail() throws Exception { SimpleMailMessage message = new SimpleMailMessage(); // 配置發(fā)送者郵箱 message.setFrom("xxxx@qq.com"); // 配置接受者郵箱 message.setTo("xxxxxx@qq.com"); // 配置郵件主題 message.setSubject("主題:簡單郵件"); // 配置郵件內(nèi)容 message.setText("測試郵件內(nèi)容"); // 發(fā)送郵件 mailSender.send(message); } }
運行單元測試之后,如果不出意外的話,接受者會收到這樣的一封郵件。
至此,郵件發(fā)送成功!
2.4、發(fā)送 HTML 格式郵件
在實際的業(yè)務(wù)開發(fā)中,郵件的內(nèi)容通常會要求豐富,比如會發(fā)送一些帶有圖片的內(nèi)容,包括字體大小,各種超鏈接等,這個時候如何實現(xiàn)呢?
實際上,郵件內(nèi)容支持 HTML 格式,因此可以借助頁面模板引擎來實現(xiàn)絢麗多彩的內(nèi)容。
下面我們以freemarker
模板引擎為例,發(fā)送一封內(nèi)容為 HTML 格式的郵件。
2.4.1、引入 freemarker 依賴包
首先,在pom.xml
文件中,添加freemarker
依賴包。
<!--freemarker 支持--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency>
???????2.4.2、編寫郵件頁面模板
然后,在resources/templates
目錄下,創(chuàng)建一個demo.ftl
文件,示例如下!
<html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div>您好:${userName}</div> <div>這是html文本內(nèi)容</div> <img src="https://rescdn.qqmail.com/zh_CN/htmledition/images/logo/logo_0_0@2X1f1937.png" /> </body> </html>
雖然采用 Spring Boot 提供的自動配置屬性來實現(xiàn)郵件推送,可以極大的簡化開發(fā)過程。而實際開發(fā)的時候,通常更推薦自定義一個郵件統(tǒng)一推送服務(wù),這樣更便于靈活的控制代碼實現(xiàn)以及排查相關(guān)問題。
郵件統(tǒng)一發(fā)送服務(wù),示范如下。
@Component public class MailPushService { private final Logger LOGGER = LoggerFactory.getLogger(MailPushService.class); @Value("${mail.host}") private String host; @Value("${mail.port}") private String port; @Value("${mail.protocol}") private String protocol; @Value("${mail.username}") private String username; @Value("${mail.password}") private String password; @Value("${mail.fromEmail}") private String fromEmail; @Value("${mail.fromPersonal}") private String fromPersonal; @Autowired private JavaMailSender mailSender; /** * 發(fā)送郵件(簡單模式) * @param toEmail * @param subject * @param content */ public void sendMail(String toEmail, String subject,String content) { try { final Properties props = new Properties(); //服務(wù)器 props.put("mail.smtp.host", host); //端口 props.put("mail.smtp.port", port); //協(xié)議 props.setProperty("mail.transport.protocol", protocol); //用戶名 props.put("mail.user", username); //密碼 props.put("mail.password", password); //使用smtp身份驗證 props.put("mail.smtp.auth", "true"); //開啟安全協(xié)議 MailSSLSocketFactory sf = new MailSSLSocketFactory(); sf.setTrustAllHosts(true); props.put("mail.smtp.ssl.enable", "true"); props.put("mail.smtp.ssl.socketFactory", sf); Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(props.getProperty("mail.user"), props.getProperty("mail.password")); } }; Session session = Session.getDefaultInstance(props, authenticator); session.setDebug(true); MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.setFrom(new InternetAddress(fromEmail, MimeUtility.encodeText(fromPersonal))); mimeMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(toEmail)); mimeMessage.setSubject(subject); mimeMessage.setContent(content, "text/html;charset=UTF-8"); //保存信息 mimeMessage.saveChanges(); //發(fā)送消息 Transport.send(mimeMessage); LOGGER.info("簡單郵件已經(jīng)發(fā)送。"); } catch (Exception e) { LOGGER.error("發(fā)送簡單郵件時發(fā)生異常!", e); } } }
代碼中相關(guān)自定義的全局參數(shù)配置如下:
??????? mail.host=smtp.exmail.qq.com mail.port=465 mail.protocol=smtp mail.username=xxx@qq.com mail.password=xxxxxx mail.fromEmail=xxxxxx@qq.com mail.fromPersonal=發(fā)送者昵稱
???????2.4.4、測試服務(wù)的正確性
最后,編寫一個單元測試來驗證服務(wù)的正確性,示例如下:
@RunWith(SpringRunner.class) @SpringBootTest public class MailTest { @Autowired private MailPushService mailPushService; @Test public void testSendHtmlMail() throws Exception { String sendHtml = buildHtmlContent("張三"); mailPushService.sendMail("xxxxx@qq.com","簡單標(biāo)題", sendHtml); } /** * 封裝html頁面 * @return * @throws Exception */ private static String buildHtmlContent(String userName) throws Exception { Configuration configuration = new Configuration(Configuration.VERSION_2_3_23); configuration.setDefaultEncoding(Charset.forName("UTF-8").name()); configuration.setClassForTemplateLoading(MailTest.class, "/templates"); // 獲取頁面模版 Template template = configuration.getTemplate("demo.ftl"); // 動態(tài)變量替換 Map<String,Object> map = new HashMap<>(); map.put("userName", userName); String htmlStr = FreeMarkerTemplateUtils.processTemplateIntoString(template,map); return htmlStr; } }
運行單元測試之后,如果沒有報錯,接受者會收到這樣的一封郵件。
2.5、發(fā)送帶附件的郵件
某些業(yè)務(wù)場景,用戶希望發(fā)送的郵件中能帶上附件,比如上文中,在發(fā)送 HTML 格式的郵件時,同時也帶上文件附件,這個時候如何實現(xiàn)呢?
2.5.1、編寫帶附件的郵件發(fā)送
此時可以在郵件推送服務(wù)中,新增一個支持帶附件的方法,實現(xiàn)邏輯如下。
/** * 發(fā)送郵件(復(fù)雜模式) * @param toEmail 接受者郵箱 * @param subject 主題 * @param sendHtml 內(nèi)容 * @param attachment 附件 */ public void sendMail(String toEmail, String subject, String sendHtml, File attachment) { try { //設(shè)置了附件名過長問題 System.setProperty("mail.mime.splitlongparameters", "false"); final Properties props = new Properties(); //服務(wù)器 props.put("mail.smtp.host", host); //端口 props.put("mail.smtp.port", port); //協(xié)議 props.setProperty("mail.transport.protocol", protocol); //用戶名 props.put("mail.user", username); //密碼 props.put("mail.password", password); //使用smtp身份驗證 props.put("mail.smtp.auth", "true"); //開啟安全協(xié)議 MailSSLSocketFactory sf = new MailSSLSocketFactory(); sf.setTrustAllHosts(true); props.put("mail.smtp.ssl.enable", "true"); props.put("mail.smtp.ssl.socketFactory", sf); Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(props.getProperty("mail.user"), props.getProperty("mail.password")); } }; Session session = Session.getDefaultInstance(props, authenticator); session.setDebug(true); MimeMessage mimeMessage = new MimeMessage(session); // 發(fā)送者郵箱 mimeMessage.setFrom(new InternetAddress(fromEmail, MimeUtility.encodeText(fromPersonal))); // 接受者郵箱 mimeMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(toEmail)); // 郵件主題 mimeMessage.setSubject(subject); // 定義郵件內(nèi)容 Multipart multipart = new MimeMultipart(); // 添加郵件正文 BodyPart contentPart = new MimeBodyPart(); contentPart.setContent(sendHtml, "text/html;charset=UTF-8"); multipart.addBodyPart(contentPart); // 添加附件 if (attachment != null) { BodyPart attachmentBodyPart = new MimeBodyPart(); // MimeUtility.encodeWord可以避免文件名亂碼 FileDataSource fds=new FileDataSource(attachment); attachmentBodyPart.setDataHandler(new DataHandler(fds)); attachmentBodyPart.setFileName(MimeUtility.encodeText(fds.getName())); multipart.addBodyPart(attachmentBodyPart); } // 將multipart對象放到message中 mimeMessage.setContent(multipart); //保存信息 mimeMessage.saveChanges(); //發(fā)送消息 Transport.send(mimeMessage); LOGGER.info("郵件已經(jīng)發(fā)送。"); } catch (Exception e) { LOGGER.error("發(fā)送郵件時發(fā)生異常!", e); } }
???????2.5.2、測試服務(wù)的正確性
最后,編寫一個單元測試來驗證服務(wù)的正確性,示例如下:
@Test public void doSendHtmlEmail() throws Exception { // 獲取正文內(nèi)容 String sendHtml = buildHtmlContent("張三"); // 獲取附件 File file = new File( "~/doc/Java開發(fā)手冊.pdf"); // 發(fā)送郵件 mailPushService.sendMail("xxxxx@qq.com","帶附件的郵件推送", sendHtml, file); }
運行單元測試之后,如果沒有報錯,接受者會收到這樣的一封郵件。
三、小結(jié)
最后總結(jié)一下,郵件自動推送功能在實際的業(yè)務(wù)系統(tǒng)中應(yīng)用非常廣,在發(fā)送過程中也可能會因為網(wǎng)絡(luò)問題出現(xiàn)各種失敗現(xiàn)象,因此推薦采用異步的方式來發(fā)送郵件,例如采用異步編程或者消息隊列來實現(xiàn),以便加快主流程的執(zhí)行速度。
想要獲取項目源代碼的小伙伴,可以訪問如下地址獲取!
四、參考資料
1.https://blog.csdn.net/qq_26383975/article/details/121957917
1.http://www.ityouknow.com/springboot/2017/05/06/spring-boot-mail.html
到此這篇關(guān)于SpringBoot+mail 輕松實現(xiàn)各類郵件自動推送的文章就介紹到這了,更多相關(guān)SpringBoot郵件自動推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA MyBatis Plugins自動生成實體類和mapper.xml
這篇文章主要介紹了IDEA MyBatis Plugins自動生成實體類和mapper.xml,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Mybatis注解方式操作Oracle數(shù)據(jù)庫詳解
這篇文章主要介紹了Mybatis注解方式操作Oracle數(shù)據(jù)庫詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11EDI中JAVA通過FTP工具實現(xiàn)文件上傳下載實例
這篇文章主要介紹了EDI中JAVA通過FTP工具實現(xiàn)文件上傳下載實例,具有一定的參考價值,有需要的可以了解一下。2016-11-11mybatis條件語句中帶數(shù)組參數(shù)的處理
這篇文章主要介紹了mybatis條件語句中帶數(shù)組參數(shù)的處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09SpringBoot2零基礎(chǔ)到精通之?dāng)?shù)據(jù)庫專項精講
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時也是簡化Spring的一種快速開發(fā)的腳手架,本篇我們來學(xué)習(xí)如何連接數(shù)據(jù)庫進行操作2022-03-03