SpringBoot實現發送電子郵件

SpringBoot知識體系

目錄html


從1969年10月世界上的第一封電子郵件發出,到2019年,已通過去將近半個世紀了。雖然即時通信和視頻會議,甚至全息投影都變得日益普及,但電子郵件依然有着普遍的使用場景和不可撼動的歷史地位。java

SpringBoot擁有強大的生態鏈,幾乎能夠鏈接全部主流的開源庫。git

下面咱們就從電子郵件發送的歷史再到原理,而後如何本身配置郵件服務器併發送郵件,一步步講解。github

本文實現源碼能夠在這裏找到: SpringBoot發送電子郵件源碼web

電子郵件與Java發送郵件的歷史

  1. 1969年10月,世界上的第一封電子郵件

1969年10月世界上的第一封電子郵件是由計算機科學家Leonard K.教授發給他的同事的一條簡短消息。第一條網上信息就是‘LO’,意思是‘你好!’。spring

  1. 1987年9月14日中國的第一封電子郵件

在此以後,1987年9月14日中國的第一封電子郵件,這封郵件是由德國維爾納·措恩與中國的王運豐在北京計算機應用技術研究所,發往德國一個大學的,郵件內容頗具深意,「Across the Great Wall we can reach every corner in the world.(越過長城,走向世界)」,這是中國經過北京與德國大學之間的網絡鏈接,向全球科學網發出的第一封電子郵件。瀏覽器

  1. 30年代發展歷程

接下來中國的電子郵件進入了30年的發展期,雖然在1987年就有了電子郵件,可是,真正的郵件興起,應該在90年代到2000年之間,由於在1987的時候中國網速特別慢,真正能接觸到互聯網的用戶是很是少的,到了90年代中期,互聯網瀏覽器的誕生,使得全民上網人數激增,電子郵件被普遍使用,此時,中國的部分學生在研究中使用到電子郵件,真正普及的時間是在2000年左右。安全

  1. Java發送郵件

Java在發明之初,就開始支持發送郵件,經過java mail包方式去操做郵件發送的內容和協議,可是,這種發送方式稍微比較複雜,須要配置各類參數、協議、內容,以後產生了Spring框架。springboot

  1. Spring發送郵件

Spring在java mail的基礎上進行了一些封裝,使發送郵件的過程的複雜大大減小。服務器

  1. SpringBoot發送郵件

SpringBoot Mail在Spring Mail的基礎上,再次進行一次封裝,使得發送郵件的便利度上,更爲簡單。

電子郵件原理

電子郵件服務器

用戶要在Internet上提供電子郵件功能,必須有專門的電子郵件服務器。這些郵件服務器就相似於現實生活中的郵局,它主要負責接收用戶投遞過來的郵件,並把郵件投遞到郵件接收者的電子郵箱中。

郵件服務器就好像是互聯網世界的郵局。按照功能劃分,郵件服務器能夠劃分爲兩種類型:

  1. SMTP郵件服務器:用戶替用戶發送郵件和接收外面發送給本地用戶的郵件。
  2. POP3/IMAP郵件服務器:用戶幫助用戶讀取SMTP郵件服務器接收進來的郵件。

電子郵箱

電子郵箱也稱爲E-mail地址,用戶能夠經過E-mail地址來標識本身發送的電子郵件,也能夠經過這個地址接收別人發來的電子郵件。電子郵箱須要到郵件服務器進行申請,也就是說,電子郵箱其實就是用戶在郵件服務器上申請的帳戶。郵件服務器會把接收到的郵件保存到爲該帳戶所分配的郵箱空間中,用戶經過用戶名密碼登陸到郵件服務器查收該地址已經收到的郵件。通常來說,郵件服務器爲用戶分配的郵箱空間是有限的。

郵件客戶端

咱們能夠直接在網站上進行郵件收發,也可使用常見的FoxMail、Outlook等郵件客戶端軟件接受郵件。郵件客戶端軟件一般集郵件撰寫、發送和收發功能於一體,主要用於幫助用戶將郵件發送給SMTP郵件服務器和從POP3/IMAP郵件服務器讀取用戶的電子郵件。

郵件傳輸協議

電子郵件須要在郵件客戶端和郵件服務器之間,以及兩個郵件服務器之間進行郵件傳遞,那就必需要遵照必定的規則,這個規則就是郵件傳輸協議。下面咱們分別簡單介紹幾種協議:

  1. SMTP協議:全稱爲 Simple Mail Transfer Protocol,簡單郵件傳輸協議。它定義了郵件客戶端軟件和SMTP郵件服務器之間,以及兩臺SMTP郵件服務器之間的通訊規則。
  2. POP3協議:全稱爲 Post Office Protocol,郵局協議。它定義了郵件客戶端軟件和POP3郵件服務器的通訊規則。
  3. IMAP協議:全稱爲 Internet Message Access Protocol,Internet消息訪問協議,它是對POP3協議的一種擴展,也是定義了郵件客戶端軟件和IMAP郵件服務器的通訊規則。

郵件格式

要想各類郵件處理程序能識別咱們所寫的電子郵件,能從咱們所書寫的電子郵件中分析和提取出發件人、收件人、郵件主題和郵件內容以及附件等信息,那麼咱們所寫的電子郵件必需要遵循必定的格式要求,而這種郵件內容的基本格式和具體細節分別是由 RFC822 文檔和 MIME 協議定義的。

  1. RFC822 文檔中定義的文件格式包括兩個部分:郵件頭和郵件體。
  2. MIME協議(Multipurpose Internet Mail Extensions )用於定義複雜郵件體的格式,它能夠表達多段平行的文本內容和非文本的郵件內容,例如,在郵件體中內嵌的圖像數據和郵件附件等。另外,MIME協議的數據格式也能夠避免郵件內容在傳輸過程當中發生信息丟失。MIME協議不是對RFC822郵件格式的升級和替代,而是基於RFC822郵件格式的擴展應用。一言以蔽之,RFC822定義了郵件內容的格式和郵件頭字段的詳細細節,MIME協議則是定義瞭如何在郵件體部分表達出的豐富多樣的數據內容。

電子郵件發送和接收流程

電子郵件發送和接收流程

圖示的六個步驟分別進行以下的說明:

①用戶A的電子郵箱爲:xx@qq.com,經過郵件客戶端軟件寫好一封郵件,交到QQ的郵件服務器,這一步使用的協議是SMTP,對應圖示的①;

②QQ郵箱會根據用戶A發送的郵件進行解析,也就是根據收件地址判斷是不是本身管轄的帳戶,若是收件地址也是QQ郵箱,那麼會直接存放到本身的存儲空間。這裏咱們假設收件地址不是QQ郵箱,而是163郵箱,那麼QQ郵箱就會將郵件轉發到163郵箱服務器,轉發使用的協議也是SMTP,對應圖示的②;

③163郵箱服務器接收到QQ郵箱轉發過來的郵件,也會判斷收件地址是不是本身,發現是本身的帳戶,那麼就會將QQ郵箱轉發過來的郵件存放到本身的內部存儲空間,對應圖示的③;

④用戶A將郵件發送了以後,就會通知用戶B去指定的郵箱收取郵件。用戶B會經過郵件客戶端軟件先向163郵箱服務器請求,要求收取本身的郵件,對應圖示的④;

⑤163郵箱服務器收到用戶B的請求後,會從本身的存儲空間中取出B未收取的郵件,對應圖示⑤;

⑥163郵箱服務器取出用戶B未收取的郵件後,將郵件發給用戶B,對應圖示的⑥;最後三步用戶B收取郵件的過程,使用的協議是POP3;

電子郵件的使用場景

在系統中電子郵件的使用場景:

  1. 註冊驗證

  2. 營銷推送

  3. 觸發機制

  4. 監控報警

電子郵件是業務和安全的最後一道防線 —— 當系統沒法自動處理的時候,經過郵件提醒相關支持人員。

SpringBoot實現發送電子郵件

準備帳號

註冊發件郵箱並設置客戶端受權碼,這裏以163免費郵箱爲例:

163郵箱協議設置-1

163郵箱協議設置-2

構建項目並配置

搭建完項目之後,進行下面的兩步配置。

application.properties配置參數:

# 郵箱配置
spring.mail.host=smtp.163.com
# 你的163郵箱
spring.mail.username=ispringboot@163.com
# 注意這裏不是郵箱密碼,而是SMTP受權密碼
spring.mail.password=isb001
spring.mail.port=25
spring.mail.protocol=smtp
spring.mail.default-encoding=UTF-8
複製代碼

pom.xml依賴spring-boot-starter-mail模塊:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
</dependency>
複製代碼

實現服務端代碼

MailService.java:

package org.ijiangtao.tech.spring.boot.mail.imail.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@Service
public class MailService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${spring.mail.username}")
    private String from;

    @Autowired
    private JavaMailSender mailSender;

    /** * 簡單文本郵件 * @param to 接收者郵件 * @param subject 郵件主題 * @param contnet 郵件內容 */
    public void sendSimpleMail(String to, String subject, String contnet){

        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(contnet);
        message.setFrom(from);

        mailSender.send(message);
    }

    /** * HTML 文本郵件 * @param to 接收者郵件 * @param subject 郵件主題 * @param contnet HTML內容 * @throws MessagingException */
    public void sendHtmlMail(String to, String subject, String contnet) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(contnet, true);
        helper.setFrom(from);

        mailSender.send(message);
    }

    /** * 附件郵件 * @param to 接收者郵件 * @param subject 郵件主題 * @param contnet HTML內容 * @param filePath 附件路徑 * @throws MessagingException */
    public void sendAttachmentsMail(String to, String subject, String contnet, String filePath) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(contnet, true);
        helper.setFrom(from);

        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName = file.getFilename();
        helper.addAttachment(fileName, file);

        mailSender.send(message);
    }

    /** * 圖片郵件 * @param to 接收者郵件 * @param subject 郵件主題 * @param contnet HTML內容 * @param rscPath 圖片路徑 * @param rscId 圖片ID * @throws MessagingException */
    public void sendInlinkResourceMail(String to, String subject, String contnet, String rscPath, String rscId) {
        logger.info("發送靜態郵件開始: {},{},{},{},{}", to, subject, contnet, rscPath, rscId);

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = null;

        try {

            helper = new MimeMessageHelper(message, true);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(contnet, true);
            helper.setFrom(from);

            FileSystemResource res = new FileSystemResource(new File(rscPath));
            helper.addInline(rscId, res);
            mailSender.send(message);
            logger.info("發送靜態郵件成功!");

        } catch (MessagingException e) {
            logger.info("發送靜態郵件失敗: ", e);
        }

    }

}
複製代碼

新建郵件模板

咱們使用thymeleaf做爲模板引擎。

emailTeplate.html:

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>註冊-測試郵件模板</title>
</head>
<body>
    你好,感謝你的註冊,這是一封驗證郵件,請點擊下面的鏈接完成註冊,感謝您的支持。
    <a href="#" th:href="@{https://github.com/{id}(id=${id})}">激活帳戶</a>
</body>
</html>
複製代碼

測試發送郵件

測試發送郵件,使用單元測試MailServiceTest.java:

package org.ijiangtao.tech.spring.boot.mail.imail.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.annotation.Resource;
import javax.mail.MessagingException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MailServiceTest {

    @Autowired
    private MailService mailService;

    @Resource
    private TemplateEngine templateEngine;

    @Test
    public void sendSimpleMail() {
        mailService.sendSimpleMail("ispringboot@163.com","測試spring boot imail-主題","測試spring boot imail - 內容");
    }

    @Test
    public void sendHtmlMail() throws MessagingException {

        String content = "<html>\n" +
                "<body>\n" +
                "<h3>hello world</h3>\n" +
                "<h1>html</h1>\n" +
                "<body>\n" +
                "</html>\n";

        mailService.sendHtmlMail("ispringboot@163.com","這是一封HTML郵件",content);
    }

    @Test
    public void sendAttachmentsMail() throws MessagingException {
        String filePath = "/ijiangtao/軟件開發前景.docx";
        String content = "<html>\n" +
                "<body>\n" +
                "<h3>hello world</h3>\n" +
                "<h1>html</h1>\n" +
                "<h1>附件傳輸</h1>\n" +
                "<body>\n" +
                "</html>\n";
        mailService.sendAttachmentsMail("ispringboot@163.com","這是一封HTML郵件",content, filePath);
    }

    @Test
    public void sendInlinkResourceMail() throws MessagingException {
        //TODO 改成本地圖片目錄
        String imgPath = "/ijiangtao/img/blob/dd9899b4cf95cbf074ddc4607007046c022564cb/blog/animal/dog/dog-at-work-with-computer-2.jpg?raw=true";
        String rscId = "admxj001";
        String content = "<html>" +
                "<body>" +
                "<h3>hello world</h3>" +
                "<h1>html</h1>" +
                "<h1>圖片郵件</h1>" +
                "<img src='cid:"+rscId+"'></img>" +
                "<body>" +
                "</html>";

        mailService.sendInlinkResourceMail("ispringboot@163.com","這是一封圖片郵件",content, imgPath, rscId);
    }

    @Test
    public void testTemplateMailTest() throws MessagingException {
        Context context = new Context();
        context.setVariable("id","ispringboot");

        String emailContent = templateEngine.process("emailTeplate", context);
        mailService.sendHtmlMail("ispringboot@163.com","這是一封HTML模板郵件",emailContent);

    }
}

複製代碼

測試結果,收到了電子郵件:

總結

SpringBoot-Email

在生產環境,通常郵件服務會單獨部署,並經過HTTP或MQ等方式暴露出來。

郵件部署架構

相關連接

相關文章
相關標籤/搜索