[TOC]html
在談談代碼以前,先來了解下郵件的基本協議。java
電子郵件協議是基於TCP層定義的,主要有下面幾個:git
SMTP 是 Simple Mail Transfer Protocol 的簡稱,即簡單郵件傳輸協議,是發送協議。 它定義了一組從源地址到目的地址傳輸郵件的規範,並支持在傳送過程當中經過不一樣網絡主機實現中轉及傳送。github
POP3是 Post Office Protocol 3 的簡稱,屬於接收協議,POP3是即POP(郵局協議)的第3個版本,也是因特網電子郵件的第一個離線協議。 它規定了終端如何接入遠程的郵件服務器並下載電子郵件。spring
IMAP的全稱是 Internet Mail Access Protocol,即交互式郵件訪問協議,是一種支持同步接收的協議。 該協議由斯坦福大學在1986年研發,目前是最流行的郵件收取功能協議。 開啓IMAP功能以後,電子郵件客戶端可同步接收服務端的郵件,不管在客戶端仍是服務端上的操做都會反饋到另外一方,好比刪除、標記等; 此外IMAP還支持只對選中的部分郵件進行收取,這在POP協議上是作不到的。springboot
大多人都知道,電子郵件的傳輸採用了Base64編碼對郵件內容進行包裝,這是一種基於64個可打印字符來表示二進制數據的方法。服務器
如上是Base64編碼的字符映射表,64個字符可對應6個bit位。 一個字節是8個bit位,那麼3個字節恰好須要4個Base64的字符來表示,而3個字節(4個字符)也是Base64編碼的最小單位, 在編碼過程當中對於不足的部分採用"="號來補齊,以下:網絡
另一個須要知道的協議是MIME(Multipurpose Internet Mail Extensions),即多用途互聯網郵件擴展 在前面介紹SpringBoot-MiMe類型處理的文章中提到過,這是一種用來定義文檔性質及格式的標準。 一段內容,是文本、圖片、音頻,仍是二進制,都經過MIME類型來進行聲明和解析。併發
常見的MIMEapp
內容 | 後綴 | MIME |
---|---|---|
普通文本 | .txt | text/plain |
RTF文本 | .rtf | application/rtf |
PDF文檔 | application/pdf | |
Word文件 | .word | application/msword |
PNG圖像 | .png | image/png |
GIF圖形 | .gif | image/gif |
JPEG圖形 | .jpg | image/jpeg |
SpringBoot 是一個腳手架,郵件功能實際上是經過 JavaMail來實現的。 JavaMail是Java實現郵件收發功能的標準組件,其提供了一組簡便的API來實現郵件處理,同時也支持各種認證協議。 這裏不對JavaMail 作展開介紹,因爲有了SpringBoot,實現一個郵件發送功能變得很是簡單。
下面將展現幾個例子,包括:
spring-boot-starter-mail是一個封裝了郵件功能的組件,依賴以下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>${spring-boot.version}</version> </dependency>
按下面的配置設置SMTP服務器、用戶密碼、及收發人信息
//smtp 服務器 spring.mail.host=smtp.qq.com //smtp 端口 spring.mail.port=25 //發送用戶名 spring.mail.username=xxx //發送密碼 spring.mail.password=xxx //收發人 spring.mail.from=xxx@qq.com spring.mail.to=xxx@qq.com //啓用鑑權 spring.mail.properties.mail.smtp.auth=true //不使用tls spring.mail.properties.mail.smtp.starttls.enable=false spring.mail.properties.mail.smtp.starttls.required=false
編寫下面的代碼,實現簡單的文本發送:
@Service public class SimpleMailSender implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(SimpleMailSender.class); @Autowired private JavaMailSender mailSender; @Autowired private Environment environment; private void sendText() { String from = environment.getProperty("spring.mail.from"); String to = environment.getProperty("spring.mail.to"); SimpleMailMessage msg = new SimpleMailMessage(); msg.setFrom(from); msg.setTo(to); msg.setSubject("first email from yourself"); msg.setText("hello world!"); this.mailSender.send(msg); logger.info("send text done"); } @Override public void run(String... args) throws Exception { sendText(); }
JavaMailSender、SimpleMailMessage 都是對JavaMail接口的封裝,目的僅在於提供更簡易的使用方式。 SimpleMailSender 繼承了CommandLineRunner ,在SpringBoot啓動時會觸發sendText方法, 此時嘗試啓動SpringBoot應用,能夠看到日誌輸出:
o.h.s.m.SimpleMailSender : send text done
此時檢查收件箱,即可以看到對應的文本郵件。
基於前面發送文本的例子,實現附件發送的代碼以下:
private void sendAttachment() throws MessagingException { String from = environment.getProperty("spring.mail.from"); String to = environment.getProperty("spring.mail.to"); // 使用Mime消息體 MimeMessage message = mailSender.createMimeMessage(); // multipart參數爲true,表示須要發送附件 MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject("first file from yourself"); helper.setText("check the file"); //指定系統文件 File file = new File("D:\\temp\\attachment.xlsx"); FileSystemResource resource = new FileSystemResource(file); helper.addAttachment(file.getName(), resource); mailSender.send(message); logger.info("send attachment done"); }
一樣,啓動應用併發送郵件後,在收件郵件中得到了附件:
許多郵件都包含了豐富的文本樣式,這是經過HTML郵件實現的。 對於此類場景的通用作法是使用模板來發送,應用程序只關注模型數據的傳參便可。
SpringBoot 可利用 thymeleaf 頁面引擎來實現HTML的模板,首先須要引入thymeleaf
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>${spring-boot.version}</version> </dependency>
接着新建一個模板, /src/main/resources/templates/mail/template.html
<html> <body> <h4 th:text="|Hi, ${customer}, these're your pets|"></h4> <hr></hr> <table> <tr> <th>name</th> <th>type</th> <th>age</th> </tr> <tr th:each="p : ${pets}"> <td th:text="${p.name}"></td> <td th:text="${p.type}"></td> <td th:text="${p.age}"></td> </tr> </table> </body> </html>
上面的模板中是一個寵物列表的頁面(表格),寵物模型定義:
public static class Pet { private String name; private String type; private int age; public Pet(String name, String type, int age) { super(); this.name = name; this.type = type; this.age = age; } ...
咱們在發送郵件時,須要注入寵物列表數據, 代碼以下:
@Service public class SimpleMailSender { /** * 日誌工具 */ private static final Logger logger = LoggerFactory.getLogger(MailService.class); @Autowired private JavaMailSender mailSender; @Autowired private TemplateEngine templateEngine; @Autowired private Environment environment; private void sendTemplateMail() throws MessagingException { String from = environment.getProperty("spring.mail.from"); String to = environment.getProperty("spring.mail.to"); // 使用Mime消息體 MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject("first html report from yourself"); // 根據模板、變量生成內容 // 數據模型 List<Pet> pets = new ArrayList<Pet>(); pets.add(new Pet("Polly", "Bird", 2)); pets.add(new Pet("Tom", "Cat", 5)); pets.add(new Pet("Badboy", "Dog", 3)); Context context = new Context(); context.setVariable("customer", "LiLei"); context.setVariable("pets", pets); String text = templateEngine.process("mail/template", context); helper.setText(text, true); mailSender.send(message); } }
啓動應用,發送郵件後的效果:
使用 thymeleaf 能夠快速的製做出一個Html模板, 有時候咱們須要在郵件中顯示一張圖片,怎麼辦呢?
使用img標籤,並指定一個在線的圖片; 此方案比較通用,應該說大多數在線平臺都採用這種作法,但這麼作的前提是須要有一個統一的圖片存儲及訪問系統。
使用 Base64編碼,在頁面中嵌入編碼後的內容:
<img width="100" height="100" src="data:image/jpg;base64,/9dxxFEF8fEkqAAgAAAAL===" />
該方案非通用,在實測中發現Outlook 沒法展現這類標籤,客戶端並未支持。 下面列舉了支持內嵌圖片展現的一些郵件客戶端:
CID就是ContentID,是一種在MIME消息體中用於定義並引用內容塊的機制。 RFC2392 對這個進行了定義。
一個帶CID的消息體以下所示:
--boundary-example 1 Content-Type: Text/HTML; charset=US-ASCII to the other body part, for example through a statement such as: <IMG SRC="cid:foo4*foo1@bar.net" ALT="IETF logo"> --boundary-example-1 Content-ID: <foo4*foo1@bar.net> Content-Type: IMAGE/GIF Content-Transfer-Encoding: BASE64 R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5 NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A etc...
那麼,使用CID內嵌圖片的作法以下:
步驟一
在發送郵件時指定帶 CID 的 Resource
String text = templateEngine.process("mail/template", context); helper.setText(text, true); helper.addInline("soft", new FileSystemResource("D:/temp/soft.png")); mailSender.send(message);
步驟二 步驟:模板中引用對應的CID,以下:
<img src="cid:soft"></img>
最終,發送郵件可支持圖片的展現,以下
spring.io-mail springboot-mail.properties send-a-base64-image-in-html-email
歡迎繼續關注"美碼師的補習系列-springboot篇" ,期待更多精彩內容^-^