補習系列(12)-springboot 與郵件發送

[TOC]html

1、郵件協議

在談談代碼以前,先來了解下郵件的基本協議。java

電子郵件協議是基於TCP層定義的,主要有下面幾個:git

  • SMTP協議

SMTP 是 Simple Mail Transfer Protocol 的簡稱,即簡單郵件傳輸協議,是發送協議。 它定義了一組從源地址到目的地址傳輸郵件的規範,並支持在傳送過程當中經過不一樣網絡主機實現中轉及傳送。github

  • POP3協議

POP3是 Post Office Protocol 3 的簡稱,屬於接收協議,POP3是即POP(郵局協議)的第3個版本,也是因特網電子郵件的第一個離線協議。 它規定了終端如何接入遠程的郵件服務器並下載電子郵件。spring

  • IMAP協議

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文檔 .pdf application/pdf
Word文件 .word application/msword
PNG圖像 .png image/png
GIF圖形 .gif image/gif
JPEG圖形 .jpg image/jpeg

2、SpringBoot 與郵件

SpringBoot 是一個腳手架,郵件功能實際上是經過 JavaMail來實現的。 JavaMail是Java實現郵件收發功能的標準組件,其提供了一組簡便的API來實現郵件處理,同時也支持各種認證協議。 這裏不對JavaMail 作展開介紹,因爲有了SpringBoot,實現一個郵件發送功能變得很是簡單。

下面將展現幾個例子,包括:

  • 使用springboot 發送文本郵件;
  • 如何發送帶附件的郵件;
  • 如何使用 thymeleaf 發送模板郵件,支持HTML格式。

A. 添加依賴

spring-boot-starter-mail是一個封裝了郵件功能的組件,依賴以下:

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-mail</artifactId>
 <version>${spring-boot.version}</version>
</dependency>

B. 配置文件

按下面的配置設置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

C. 發送文本郵件

編寫下面的代碼,實現簡單的文本發送:

@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

此時檢查收件箱,即可以看到對應的文本郵件。

D.發送附件

基於前面發送文本的例子,實現附件發送的代碼以下:

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");
    }

一樣,啓動應用併發送郵件後,在收件郵件中得到了附件:

E. 發送Html郵件

許多郵件都包含了豐富的文本樣式,這是經過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);
    }

}

啓動應用,發送郵件後的效果:

3、CID與圖片

使用 thymeleaf 能夠快速的製做出一個Html模板, 有時候咱們須要在郵件中顯示一張圖片,怎麼辦呢?

  1. 使用img標籤,並指定一個在線的圖片; 此方案比較通用,應該說大多數在線平臺都採用這種作法,但這麼作的前提是須要有一個統一的圖片存儲及訪問系統。

  2. 使用 Base64編碼,在頁面中嵌入編碼後的內容:

<img width="100" height="100" src="data:image/jpg;base64,/9dxxFEF8fEkqAAgAAAAL===" />

該方案非通用,在實測中發現Outlook 沒法展現這類標籤,客戶端並未支持。 下面列舉了支持內嵌圖片展現的一些郵件客戶端:

  1. 採用CID 方案,圖片做爲內嵌資源

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篇" ,期待更多精彩內容^-^

相關文章
相關標籤/搜索