郵件發送實際上是一個很是常見的需求,用戶註冊,找回密碼等地方,都會用到,使用 JavaSE 代碼發送郵件,步驟仍是挺繁瑣的,Spring Boot 中對於郵件發送,提供了相關的自動化配置類,使得郵件發送變得很是容易,本文咱們就來一探究竟!看看使用 Spring Boot 發送郵件的 5 中姿式。html
咱們常常會聽到各類各樣的郵件協議,好比 SMTP、POP三、IMAP ,那麼這些協議有什麼做用,有什麼區別?咱們先來討論一下這個問題。java
SMTP 是一個基於 TCP/IP 的應用層協議,江湖地位有點相似於 HTTP,SMTP 服務器默認監聽的端口號爲 25 。看到這裏,小夥伴們可能會想到既然 SMTP 協議是基於 TCP/IP 的應用層協議,那麼我是否是也能夠經過 Socket 發送一封郵件呢?回答是確定的。git
生活中咱們投遞一封郵件要通過以下幾個步驟:github
這是一個縮減版的生活中郵件發送過程。這三個步驟能夠分別對應咱們的郵件發送過程,假設從 aaa@qq.com 發送郵件到 111@163.com :web
郵件投遞大體就是這個過程,這個過程就涉及到了多個協議,咱們來分別看一下。spring
SMTP 協議全稱爲 Simple Mail Transfer Protocol,譯做簡單郵件傳輸協議,它定義了郵件客戶端軟件與 SMTP 服務器之間,以及 SMTP 服務器與 SMTP 服務器之間的通訊規則。後端
也就是說 aaa@qq.com 用戶先將郵件投遞到騰訊的 SMTP 服務器這個過程就使用了 SMTP 協議,而後騰訊的 SMTP 服務器將郵件投遞到網易的 SMTP 服務器這個過程也依然使用了 SMTP 協議,SMTP 服務器就是用來收郵件。服務器
而 POP3 協議全稱爲 Post Office Protocol ,譯做郵局協議,它定義了郵件客戶端與 POP3 服務器之間的通訊規則,那麼該協議在什麼場景下會用到呢?當郵件到達網易的 SMTP 服務器以後, 111@163.com 用戶須要登陸服務器查看郵件,這個時候就該協議就用上了:郵件服務商都會爲每個用戶提供專門的郵件存儲空間,SMTP 服務器收到郵件以後,就將郵件保存到相應用戶的郵件存儲空間中,若是用戶要讀取郵件,就須要經過郵件服務商的 POP3 郵件服務器來完成。app
最後,可能也有小夥伴們據說過 IMAP 協議,這個協議是對 POP3 協議的擴展,功能更強,做用相似,這裏再也不贅述。前後端分離
目前國內大部分的郵件服務商都不容許直接使用用戶名/密碼的方式來在代碼中發送郵件,都是要先申請受權碼,這裏以 QQ 郵箱爲例,向你們演示受權碼的申請流程:首先咱們須要先登陸 QQ 郵箱網頁版,點擊上方的設置按鈕:
而後點擊帳戶選項卡:
在帳戶選項卡中找到開啓POP3/SMTP選項,以下:
點擊開啓,開啓相關功能,開啓過程須要手機號碼驗證,按照步驟操做便可,不贅述。開啓成功以後,便可獲取一個受權碼,將該號碼保存好,一會使用。
接下來,咱們就能夠建立項目了,Spring Boot 中,對於郵件發送提供了自動配置類,開發者只須要加入相關依賴,而後配置一下郵箱的基本信息,就能夠發送郵件了。
建立完成後,項目依賴以下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
項目建立成功後,接下來在 application.properties 中配置郵箱的基本信息:
spring.mail.host=smtp.qq.com spring.mail.port=587 spring.mail.username=1510161612@qq.com spring.mail.password=ubknfzhjkhrbbabe spring.mail.default-encoding=UTF-8 spring.mail.properties.mail.smtp.socketFactoryClass=javax.net.ssl.SSLSocketFactory spring.mail.properties.mail.debug=true
配置含義分別以下:
若是不知道 smtp 服務器的端口或者地址的的話,能夠參考 騰訊的郵箱文檔
作完這些以後,Spring Boot 就會自動幫咱們配置好郵件發送類,相關的配置在 org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration
類中,部分源碼以下:
@Configuration @ConditionalOnClass({ MimeMessage.class, MimeType.class, MailSender.class }) @ConditionalOnMissingBean(MailSender.class) @Conditional(MailSenderCondition.class) @EnableConfigurationProperties(MailProperties.class) @Import({ MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class }) public class MailSenderAutoConfiguration { }
從這段代碼中,能夠看到,導入了另一個配置 MailSenderPropertiesConfiguration
類,這個類中,提供了郵件發送相關的工具類:
@Configuration @ConditionalOnProperty(prefix = "spring.mail", name = "host") class MailSenderPropertiesConfiguration { private final MailProperties properties; MailSenderPropertiesConfiguration(MailProperties properties) { this.properties = properties; } @Bean @ConditionalOnMissingBean public JavaMailSenderImpl mailSender() { JavaMailSenderImpl sender = new JavaMailSenderImpl(); applyProperties(sender); return sender; } }
能夠看到,這裏建立了一個 JavaMailSenderImpl
的實例, JavaMailSenderImpl
是 JavaMailSender
的一個實現,咱們將使用 JavaMailSenderImpl
來完成郵件的發送工做。
作完如上兩步,郵件發送的準備工做就算是完成了,接下來就能夠直接發送郵件了。
具體的發送,有 5 種不一樣的方式,咱們一個一個來看。
簡單郵件就是指郵件內容是一個普通的文本文檔:
@Autowired JavaMailSender javaMailSender; @Test public void sendSimpleMail() { SimpleMailMessage message = new SimpleMailMessage(); message.setSubject("這是一封測試郵件"); message.setFrom("1510161612@qq.com"); message.setTo("25xxxxx755@qq.com"); message.setCc("37xxxxx37@qq.com"); message.setBcc("14xxxxx098@qq.com"); message.setSentDate(new Date()); message.setText("這是測試郵件的正文"); javaMailSender.send(message); }
從上往下,代碼含義分別以下:
最後執行該方法,就能夠實現郵件的發送,發送效果圖以下:
郵件的附件能夠是圖片,也能夠是普通文件,都是支持的。
@Test public void sendAttachFileMail() throws MessagingException { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true); helper.setSubject("這是一封測試郵件"); helper.setFrom("1510161612@qq.com"); helper.setTo("25xxxxx755@qq.com"); helper.setCc("37xxxxx37@qq.com"); helper.setBcc("14xxxxx098@qq.com"); helper.setSentDate(new Date()); helper.setText("這是測試郵件的正文"); helper.addAttachment("javaboy.jpg",new File("C:\\Users\\sang\\Downloads\\javaboy.png")); javaMailSender.send(mimeMessage); }
注意這裏在構建郵件對象上和前文有所差別,這裏是經過 javaMailSender 來獲取一個複雜郵件對象,而後再利用 MimeMessageHelper 對郵件進行配置,MimeMessageHelper 是一個郵件配置的輔助工具類,建立時候的 true 表示構建一個 multipart message 類型的郵件,有了 MimeMessageHelper 以後,咱們針對郵件的配置都是由 MimeMessageHelper 來代勞。
最後經過 addAttachment 方法來添加一個附件。
執行該方法,郵件發送效果圖以下:
圖片資源和附件有什麼區別呢?圖片資源是放在郵件正文中的,即一打開郵件,就能看到圖片。可是通常來講,不建議使用這種方式,一些公司會對郵件內容的大小有限制(由於這種方式是將圖片一塊兒發送的)。
@Test public void sendImgResMail() throws MessagingException { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setSubject("這是一封測試郵件"); helper.setFrom("1510161612@qq.com"); helper.setTo("25xxxxx755@qq.com"); helper.setCc("37xxxxx37@qq.com"); helper.setBcc("14xxxxx098@qq.com"); helper.setSentDate(new Date()); helper.setText("<p>hello 你們好,這是一封測試郵件,這封郵件包含兩種圖片,分別以下</p><p>第一張圖片:</p><img src='cid:p01'/><p>第二張圖片:</p><img src='cid:p02'/>",true); helper.addInline("p01",new FileSystemResource(new File("C:\\Users\\sang\\Downloads\\javaboy.png"))); helper.addInline("p02",new FileSystemResource(new File("C:\\Users\\sang\\Downloads\\javaboy2.png"))); javaMailSender.send(mimeMessage); }
這裏的郵件 text 是一個 HTML 文本,裏邊涉及到的圖片資源先用一個佔位符佔着,setText 方法的第二個參數 true 表示第一個參數是一個 HTML 文本。
setText 以後,再經過 addInline 方法來添加圖片資源。
最後執行該方法,發送郵件,效果以下:
在公司實際開發中,第一種和第三種都不是使用最多的郵件發送方案。由於正常來講,郵件的內容都是比較的豐富的,因此大部分郵件都是經過 HTML 來呈現的,若是直接拼接 HTML 字符串,這樣之後很差維護,爲了解決這個問題,通常郵件發送,都會有相應的郵件模板。最具表明性的兩個模板就是 Freemarker
模板和 Thyemeleaf
模板了。
首先須要引入 Freemarker 依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
而後在 resources/templates
目錄下建立一個 mail.ftl
做爲郵件發送模板:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>hello 歡迎加入 xxx 你們庭,您的入職信息以下:</p> <table border="1"> <tr> <td>姓名</td> <td>${username}</td> </tr> <tr> <td>工號</td> <td>${num}</td> </tr> <tr> <td>薪水</td> <td>${salary}</td> </tr> </table> <div style="color: #ff1a0e">一塊兒努力創造輝煌</div> </body> </html>
接下來,將郵件模板渲染成 HTML ,而後發送便可。
@Test public void sendFreemarkerMail() throws MessagingException, IOException, TemplateException { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setSubject("這是一封測試郵件"); helper.setFrom("1510161612@qq.com"); helper.setTo("25xxxxx755@qq.com"); helper.setCc("37xxxxx37@qq.com"); helper.setBcc("14xxxxx098@qq.com"); helper.setSentDate(new Date()); //構建 Freemarker 的基本配置 Configuration configuration = new Configuration(Configuration.VERSION_2_3_0); // 配置模板位置 ClassLoader loader = MailApplication.class.getClassLoader(); configuration.setClassLoaderForTemplateLoading(loader, "templates"); //加載模板 Template template = configuration.getTemplate("mail.ftl"); User user = new User(); user.setUsername("javaboy"); user.setNum(1); user.setSalary((double) 99999); StringWriter out = new StringWriter(); //模板渲染,渲染的結果將被保存到 out 中 ,將out 中的 html 字符串發送便可 template.process(user, out); helper.setText(out.toString(),true); javaMailSender.send(mimeMessage); }
須要注意的是,雖然引入了 Freemarker
的自動化配置,可是咱們在這裏是直接 new Configuration
來從新配置 Freemarker
的,因此 Freemarker 默認的配置這裏不生效,所以,在填寫模板位置時,值爲 templates
。
調用該方法,發送郵件,效果圖以下:
推薦在 Spring Boot 中使用 Thymeleaf 來構建郵件模板。由於 Thymeleaf 的自動化配置提供了一個 TemplateEngine,經過 TemplateEngine 能夠方便的將 Thymeleaf 模板渲染爲 HTML ,同時,Thymeleaf 的自動化配置在這裏是繼續有效的 。
首先,引入 Thymeleaf 依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
而後,建立 Thymeleaf
郵件模板:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>hello 歡迎加入 xxx 你們庭,您的入職信息以下:</p> <table border="1"> <tr> <td>姓名</td> <td th:text="${username}"></td> </tr> <tr> <td>工號</td> <td th:text="${num}"></td> </tr> <tr> <td>薪水</td> <td th:text="${salary}"></td> </tr> </table> <div style="color: #ff1a0e">一塊兒努力創造輝煌</div> </body> </html>
接下來發送郵件:
@Autowired TemplateEngine templateEngine; @Test public void sendThymeleafMail() throws MessagingException { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setSubject("這是一封測試郵件"); helper.setFrom("1510161612@qq.com"); helper.setTo("25xxxxx755@qq.com"); helper.setCc("37xxxxx37@qq.com"); helper.setBcc("14xxxxx098@qq.com"); helper.setSentDate(new Date()); Context context = new Context(); context.setVariable("username", "javaboy"); context.setVariable("num","000001"); context.setVariable("salary", "99999"); String process = templateEngine.process("mail.html", context); helper.setText(process,true); javaMailSender.send(mimeMessage); }
調用該方法,發送郵件,效果圖以下:
好了,這就是咱們今天說的 5 種郵件發送姿式,不知道你掌握了沒有呢?
本文案例已經上傳到 GitHub:https://github.com/lenve/javaboy-code-samples。
有問題歡迎留言討論。
關注公衆號【江南一點雨】,專一於 Spring Boot+微服務以及先後端分離等全棧技術,按期視頻教程分享,關注後回覆 Java ,領取鬆哥爲你精心準備的 Java 乾貨!