SpringBoot+mail 輕松實現各類郵件自動推送

一、簡介

在實際的項目開發過程中,經常需要用到郵件通知功能。例如,通過郵箱注冊,郵箱找回密碼,郵箱推送報表等等,實際的應用場景非常的多。

早期的時候,為了能實現郵件的自動發送功能,通常會使用 JavaMail 相關的 api 來完成。后來 Spring 推出的 JavaMailSender 工具,進一步簡化了郵件的自動發送過程,調用其 send 方法即可發送郵件。再之后, Spring Boot 針對郵件推送功能推出了spring-boot-starter-mail工具包,開發者可以通過它來快速實現郵件發送服務。

今天通過這篇文章,我們一起來學習如何在 Spring Boot 中快速實現一個自動發送郵件的功能。

二、環境準備

在介紹郵件推送實現之前,我們需要先準備一臺郵件推送的服務器,以便實現相關功能。

這里以騰訊郵箱為例,將其作為郵件發送的中轉平臺。

2.1、開啟 SMTP 服務

登陸騰訊郵箱,打開【設置】-》【收發信設置】,開啟 SMTP 服務,最后點擊【保存更改】。

2.2、生成客戶端專用密碼

點擊【設置】-》【賬戶】,進入頁面后點擊【開啟安全登陸】,點擊【生成新密碼】。

這個新密碼會用于郵箱的自動發送,因此需要記錄下來,最后點擊【保存更改】。

2.3、相關擴展知識
  • 什么是 SMTP?

SMTP(simple mail transfer protocol),也被稱為簡單郵件傳輸協議,主要用于發送電子郵件的,通過它可以實現郵件的發送或者中轉。遵循 SMTP 協議的服務器,通常稱為發送郵件服務器。

  • 什么是 POP3?

POP3(Post Office Protocol),一種郵局通信協議。主要用于接受電子郵件的,POP3 允許用戶從服務器上把郵件存儲到自己的計算機上,同時刪除保存在郵件服務器上的郵件。同理,遵循 POP3 協議的服務器,通常稱為接收郵件服務器。

  • 什么是 IMAP?

IMAP(Internet Mail Access Protocol),一種交互式郵件存取協議。與 POP3 協議類似,主要用于接收電子郵件,稍有不同的是:IMAP 允許電子郵件客戶端收取的郵件仍然保留在服務器上,同時在客戶端上的操作都會反饋到服務器上,例如刪除郵件,標記已讀等,服務器上的郵件也會做相應的動作。所以無論從瀏覽器登錄郵箱或者客戶端軟件登錄郵箱,看到的郵件以及狀態都是一致的。

總結下來就是:SMTP 負責發送郵件,POP3/IMAP 負責接收郵件。

常見郵箱發、收服務器如下!

三、郵件推送實現

用于發送郵件的服務器、賬戶和密碼準備好了之后,就可以正式使用了。下面我們以 Spring Boot 的 2.1.0版本為基礎,實現過程如下。

2.1、添加依賴包

pom.xml文件中,添加spring-boot-starter-mail依賴包。

<!--mail 支持-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.2、添加相關配置

application.properties中添加郵箱相關配置。

# 配置郵件發送主機地址
spring.mail.host=smtp.exmail.qq.com
# 配置郵件發送服務端口號
spring.mail.port=465
# 配置郵件發送服務協議
spring.mail.protocol=smtp
# 配置郵件發送者用戶名或者賬戶
spring.mail.username=xxx@qq.com
# 配置郵件發送者密碼或者授權碼
spring.mail.password=xxxxxxx
# 配置郵件默認編碼
spring.mail.default-encoding=UTF-8
# 配置smtp相關屬性
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、簡單發送一封郵件

通過單元測試來實現一封簡單郵件的發送,示例如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MailSimpleTest {@Autowiredprivate JavaMailSender mailSender;@Testpublic void sendSimpleMail() throws Exception {SimpleMailMessage message = new SimpleMailMessage();// 配置發送者郵箱message.setFrom("xxxx@qq.com");// 配置接受者郵箱message.setTo("xxxxxx@qq.com");// 配置郵件主題message.setSubject("主題:簡單郵件");// 配置郵件內容message.setText("測試郵件內容");// 發送郵件mailSender.send(message);}
}

運行單元測試之后,如果不出意外的話,接受者會收到這樣的一封郵件。

至此,郵件發送成功!

2.4、發送 HTML 格式郵件

在實際的業務開發中,郵件的內容通常會要求豐富,比如會發送一些帶有圖片的內容,包括字體大小,各種超鏈接等,這個時候如何實現呢?

實際上,郵件內容支持 HTML 格式,因此可以借助頁面模板引擎來實現絢麗多彩的內容。

下面我們以freemarker模板引擎為例,發送一封內容為 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目錄下,創建一個demo.ftl文件,示例如下!

<html>
<head><meta charset="utf-8"><title></title>
</head>
<body>
<div>您好:${userName}</div>
<div>這是html文本內容</div>
<img src="https://rescdn.qqmail.com/zh_CN/htmledition/images/logo/logo_0_0@2X1f1937.png" />
</body>
</html>
2.4.3、編寫一個郵件推送服務

雖然采用 Spring Boot 提供的自動配置屬性來實現郵件推送,可以極大的簡化開發過程。而實際開發的時候,通常更推薦自定義一個郵件統一推送服務,這樣更便于靈活的控制代碼實現以及排查相關問題。

郵件統一發送服務,示范如下。

@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;@Autowiredprivate JavaMailSender mailSender;/*** 發送郵件(簡單模式)* @param toEmail* @param subject* @param content*/public void sendMail(String toEmail, String subject,String content)  {try {final Properties props = new Properties();//服務器props.put("mail.smtp.host", host);//端口props.put("mail.smtp.port", port);//協議props.setProperty("mail.transport.protocol", protocol);//用戶名props.put("mail.user", username);//密碼props.put("mail.password", password);//使用smtp身份驗證props.put("mail.smtp.auth", "true");//開啟安全協議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() {@Overrideprotected 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();//發送消息Transport.send(mimeMessage);LOGGER.info("簡單郵件已經發送。");} catch (Exception e) {LOGGER.error("發送簡單郵件時發生異常!", e);}}
}

代碼中相關自定義的全局參數配置如下:

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=發送者昵稱
2.4.4、測試服務的正確性

最后,編寫一個單元測試來驗證服務的正確性,示例如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MailTest {@Autowiredprivate MailPushService mailPushService;@Testpublic void testSendHtmlMail() throws Exception {String sendHtml = buildHtmlContent("張三");mailPushService.sendMail("xxxxx@qq.com","簡單標題", 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");// 動態變量替換Map<String,Object> map = new HashMap<>();map.put("userName", userName);String htmlStr = FreeMarkerTemplateUtils.processTemplateIntoString(template,map);return htmlStr;}}

運行單元測試之后,如果沒有報錯,接受者會收到這樣的一封郵件。

2.5、發送帶附件的郵件

某些業務場景,用戶希望發送的郵件中能帶上附件,比如上文中,在發送 HTML 格式的郵件時,同時也帶上文件附件,這個時候如何實現呢?

2.5.1、編寫帶附件的郵件發送

此時可以在郵件推送服務中,新增一個支持帶附件的方法,實現邏輯如下。

/*** 發送郵件(復雜模式)* @param toEmail    接受者郵箱* @param subject    主題* @param sendHtml   內容* @param attachment 附件*/
public void sendMail(String toEmail, String subject, String sendHtml, File attachment) {try {//設置了附件名過長問題System.setProperty("mail.mime.splitlongparameters", "false");final Properties props = new Properties();//服務器props.put("mail.smtp.host", host);//端口props.put("mail.smtp.port", port);//協議props.setProperty("mail.transport.protocol", protocol);//用戶名props.put("mail.user", username);//密碼props.put("mail.password", password);//使用smtp身份驗證props.put("mail.smtp.auth", "true");//開啟安全協議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() {@Overrideprotected 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);// 定義郵件內容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();//發送消息Transport.send(mimeMessage);LOGGER.info("郵件已經發送。");} catch (Exception e) {LOGGER.error("發送郵件時發生異常!", e);}
}
2.5.2、測試服務的正確性

最后,編寫一個單元測試來驗證服務的正確性,示例如下:

@Test
public void doSendHtmlEmail() throws Exception {// 獲取正文內容String sendHtml = buildHtmlContent("張三");// 獲取附件File file = new File( "~/doc/Java開發手冊.pdf");// 發送郵件mailPushService.sendMail("xxxxx@qq.com","帶附件的郵件推送", sendHtml, file);
}

運行單元測試之后,如果沒有報錯,接受者會收到這樣的一封郵件。

三、小結

最后總結一下,郵件自動推送功能在實際的業務系統中應用非常廣,在發送過程中也可能會因為網絡問題出現各種失敗現象,因此推薦采用異步的方式來發送郵件,例如采用異步編程或者消息隊列來實現,以便加快主流程的執行速度。

想要獲取項目源代碼的小伙伴,可以訪問如下地址獲取!

https://gitee.com/pzblogs/spring-boot-example-demo

四、參考

1.https://blog.csdn.net/qq_26383975/article/details/121957917

1.http://www.ityouknow.com/springboot/2017/05/06/spring-boot-mail.html

寫到最后

不會有人刷到這里還想白嫖吧?點贊對我真的非常重要!在線求贊。加個關注我會非常感激!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39632.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39632.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39632.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端期末1111

前端期末 超文本標記語言&#xff08;英語&#xff1a;HyperText Markup Language&#xff0c;簡稱&#xff1a;HTML&#xff09; body&#xff1a;在網頁文檔中&#xff0c;所有文本&#xff0c;圖像&#xff0c;音頻和視頻等代碼只能放在標簽內才能呈現給用戶。 HTML中的標…

【STM32入門教學】——串口、定時器與參考資料

機器人工程系列文章目錄 這里羅列了系列文章鏈接 概念總述 STM入門教學 還沒寫完組里急用 文章目錄 機器人工程系列文章目錄概念總述STM入門教學 前言串口串口的概念cubemxkeil5實物實驗關于cubemx生成邏輯printf升級usart.cmain.hretarget.c 定時器定時器的概念cubemxkeil5…

帶電池監控功能的恒流直流負載組

EAK的交流和直流工業電池負載組測試儀對于測試和驗證關鍵電力系統的能力至關重要&#xff0c;旨在實現最佳精度。作為一家客戶至上的公司&#xff0c;我們繼續盡我們所能應對供應鏈挑戰&#xff0c;以提供出色的交貨時間&#xff0c;大約是行業其他公司的一半。 交流負載組 我…

時鐘切換的代碼

目錄 描述 輸入描述&#xff1a; 輸出描述&#xff1a; 參考代碼 描述 題目描述&#xff1a; 存在兩個同步的倍頻時鐘clk0 clk1,已知clk0是clk1的二倍頻&#xff0c;現在要設計一個切換電路&#xff0c;sel選擇時候進行切換&#xff0c;要求沒有毛刺。 信號示意圖&…

學習springMVC

第四章 Spring MVC 第一節 Spring MVC 簡介 1. Spring MVC SpringMVC是一個Java 開源框架&#xff0c; 是Spring Framework生態中的一個獨立模塊&#xff0c;它基于 Spring 實現了Web MVC&#xff08;數據、業務與展現&#xff09;設計模式的請求驅動類型的輕量級Web框架&am…

車云匯的元宇宙之旅

在汽車行業持續迎來數字化和科技革新的今天&#xff0c;車云匯作為一個領先的汽車服務平臺&#xff0c;正通過探索元宇宙這一新興概念&#xff0c;將傳統服務與虛擬現實技術相結合&#xff0c;為車主提供全新的互動體驗和服務模式。這一創新不僅有望改變汽車行業的服務面貌&…

匿名內部類在Java編程中的應用與限制

匿名內部類在Java編程中的應用與限制 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 匿名內部類在Java編程中的應用與限制 1. 什么是匿名內部類&#xff1f;…

什么叫創世區塊、創世區塊有什么用、為什么需要創世區塊

創世區塊&#xff08;Genesis Block&#xff09;是任何區塊鏈技術中的第一個區塊&#xff0c;它是區塊鏈的起點&#xff0c;標志著該區塊鏈的誕生。在創世區塊之前沒有任何區塊存在&#xff0c;因此它沒有前一個區塊的哈希值&#xff0c;通常這個位置會被設置為零或者一個預定義…

vue3源碼(六)渲染原理-runtime-dom

1、從入口文件看實現 項目入口文件 import { createApp } from vue import ./style.css import App from ./App.vuecreateApp(App).mount(#app)文件位置core\packages\runtime-dom\src\index.ts 保證了render的唯一性 // // rendererOptions 是patchProp 和nodeOps的合集&a…

可視化低代碼平臺之:RayData光啟元的震撼作品。

RayData家的可視化作品&#xff0c;貝格前端工場是經常碰到&#xff0c;制作十分的精良&#xff0c;業內很有影響力。他們也有自己的低代碼平臺&#xff0c;分為了桌面版和網頁版&#xff0c;本期分享一下他們的作品。

徹底掌握 Git:從零基礎到高級實戰的全方位教程

文章目錄 一、Git 簡介二、安裝 Git1. Windows2. macOS3. Linux 三、Git 基本概念四、初次使用 Git1. 配置 Git2. 創建一個新的 Git 倉庫3. 克隆一個遠程倉庫4. 跟蹤文件5. 提交變更6. 查看歷史記錄 五、Git 分支管理1. 創建和切換分支2. 合并分支3. 分支沖突 六、遠程倉庫1. 添…

to_json 出現亂碼的解決方案

大家好,我是愛編程的喵喵。雙985碩士畢業,現擔任全棧工程師一職,熱衷于將數據思維應用到工作與生活中。從事機器學習以及相關的前后端開發工作。曾在阿里云、科大訊飛、CCF等比賽獲得多次Top名次。現為CSDN博客專家、人工智能領域優質創作者。喜歡通過博客創作的方式對所學的…

國產分布式數據庫災備高可用實現

最近在進行核心業務系統的切換演練測試&#xff0c;就在想一個最佳的分布式數據庫高可用部署方案是如何保證數據不丟、系統可用的&#xff0c;做到故障時候可切換、可回切&#xff0c;并且業務數據的一致性。本文簡要介紹了OceanBase數據庫和GoldenDB數據庫在災備高可用的部署方…

kafka的架構

一、架構圖 Broker&#xff1a;一臺 kafka 服務器就是一個 broker。一個kakfa集群由多個 broker 組成。一個 broker 可以容納多個 topic。 Producer&#xff1a;消息生產者&#xff0c;就是向 kafka broker 發消息的客戶端 Consumer&#xff1a;消息消費者&#xff0c;向 kafk…

深海電波,智能駕馭:海上發電系統中的先進網關技術

隨著技術的不斷演進&#xff0c;海上風電場逐漸走向深海&#xff0c;隨之而來的高速通信保障成為一大難題。同時&#xff0c;海上風電特殊的環境與部署技術&#xff0c;也給運維帶來了作業難、成本高、響應慢等困難。通過在沿海岸邊建立高站&#xff0c;結合超遠覆蓋、載波聚合…

springboot java.lang.ClassNotFoundException: dm.jdbc.driver.DmDriver 應該如何解決

遇到的問題&#xff1a;項目中引用了外部的達夢jar包 在idea中正常使用 也能找到dm.jdbc.driver.DmDriver 驅動 但是當通過jenkins 構建部署到服務器上 總是報 ClassNotFoundException: dm.jdbc.driver.DmDriver 找不到驅動 應用到的驅動代碼如下格式 排查步驟 1.首先看你的項…

ROS2仿真工具-gazebo

gazebo獨立于ROS2&#xff0c;就像插件一樣&#xff0c;需要安裝。 1.安裝 sudo apt install gazebo sudo apt install ros-humble-gazebo-* 2.運行測試demo gazebo /opt/ros/humble/share/gazebo_plugins/worlds/gazebo_ros_diff_drive_demo.world 查看所有話題 ros2 top…

0052__windows下實現socketpair函數

windows下實現socketpair函數_socketpair windows 實現-CSDN博客 socketpair函數介紹及使用-CSDN博客

使用css做一個旋轉的八卦圖

使用css做一個旋轉的八卦圖 1, html部分 <div class"tai"><div class"bai"></div><div class"hei"></div> </div>2, css部分 .tai{width: 200px;height: 200px;border: 1px solid #000;background: linea…

工業路由器的應用

上文講了工業路由器與家用路由器的區別, 家用路由器的使用場景想必大家都不陌生&#xff0c;那么工業路由器可以具體應用在哪些領域呢&#xff1f; 工業路由器憑借其多接口、多協議、寬溫寬壓等工業設計特性&#xff0c;可以廣泛應用于各類工業化場景&#xff0c;為各類工業傳…