51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

【WEB 系列】SpringBoot 实现邮件发送

概述 {#概述}

  • 邮件的使用场景
  • 邮件发送原理
  • 邮件发送历史
  • SpringBoot 介绍
  • 前置知识
  • 发送文本邮件
  • 发送 html 邮件
  • 发送附件邮件
  • 发送带图片的邮件
  • 邮件模板
  • 邮件系统

邮件的使用场景 {#邮件的使用场景}

  • 注册验证

注册网站的邮件验证

  • 网站营销

发送网站活动, 链接等......

  • 安全的最后一道防线

根据邮件地址重置账号密码等....

  • 提醒, 邮件告警

实时监控系统, 发送邮件告警....

  • 触发机制

定时发送.......

邮件发送原理 {#邮件发送原理}

  • 邮件传输协议

    • SMTP 协议:

    SMTP 全称为 Simple Mail Transfer Protocol(简单邮件传输协议),它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。

    • POP3 协议:

    POP3 全称为 Post Office Protocol 3(邮局协议),POP3 支持客户端远程管理服务器端的邮件。POP3 常用于"离线"邮件处理,即允许客户端下载服务器邮件,然后服务器上的邮件将会被删除。目前很多 POP3 的邮件服务器只提供下载邮件功能,服务器本身并不删除邮件,这种属于改进版的 POP3 协议。

  • 内容不断发展, 增加了 IMAP 协议和 Mime 协议

    • IMAP 协议

    IMAP 全称为 Internet Message Access Protocol(互联网邮件访问协议),IMAP 允许从邮件服务器上获取邮件的信息、下载邮件等。IMAP 与 POP 类似,都是一种邮件获取协议。

    • Mime 协议:

    MIME, 全称为"MultipurposeInternetMailExtensions", 比较确切的中文名称为"多用途互联网邮件扩展"。它是当前广泛应用的一种电子邮件技术规范,基本内容定义于 RFC2045-2049(注意 RFC1521 和 RFC1522 是它的过时版本)。MIME 试图在不改变 SMTP 协议和 RFC822(邮件格式标准)的基础上,使得邮件可以传送任意二进制文件。

邮件收发流程

邮件发送历史 {#邮件发送历史}

  • 1969 年 10 月, 世界上的第一封电子邮件诞生

  • 1987 年 9 月 14 日中国的第一封电子邮件诞生

  • 30 年发展历程

    • Java 发送邮件
    • Spring 发送邮件
    • SpringBoot 发送邮件

开发流程 {#开发流程}

  • 基础配置
  • 集成依赖包
  • 发送 html 邮件
  • 发送附件邮件
  • 发送图片邮件
  • 发送模板邮件
  • 异常处理
  • 邮件系统

常见邮箱服务器地址 {#常见邮箱服务器地址}

QQ 邮箱(mail.qq.com)
POP3 服务器地址:pop.qq.com(端口:110)
SMTP 服务器地址:smtp.qq.com(端口:25)
SMTP 服务器需要身份验证。

网易邮箱(163.com):
POP3 服务器地址:pop.163.com(端口:110)
SMTP 服务器地址:smtp.163.com(端口:25)


谷歌邮箱(google.com):
POP3 服务器地址:pop.gmail.com(SSL 启用端口:995)
SMTP 服务器地址:smtp.gmail.com(SSL 启用端口:587)


阿里云邮箱(mail.aliyun.com):
POP3 服务器地址:pop3.aliyun.com(SSL 加密端口:995;非加密端口:110)
SMTP 服务器地址:smtp.aliyun.com(SSL 加密端口:465;非加密端口:25)
IMAP 服务器地址:imap.aliyun.com(SSL 加密端口:993;非加密端口:143)

新浪邮箱(sina.com):`
`POP3 服务器地址:pop3.sina.com.cn(端口:110)`
`SMTP 服务器地址:smtp.sina.com.cn(端口:25)

邮件发送 {#邮件发送}

基础配置 {#基础配置}

  • 创建 SpringBoot 项目, 导入相关依赖
  • spring-boot-starter-test
  • spring-boot-devtools
  • spring-boot-starter-web
  • spring-boot-starter-thymeleaf
<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.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
  • 启动引导类测试
@SpringBootApplication
public class MailApplication {
    public static void main(String[] args) {
        SpringApplication.run(MailApplication.class, args);
    }
}
  • 创建 HelloService 接口
/**
 * Software:IntelliJ IDEA 2020.1 x64
 * Author: MoBai·杰
 * ClassName:SayService
 * 类描述: 测试类
 */
@Service
public class MailService {
    /**
     * 注入用户名
     */
    @Value("${spring.mail.username}")
    private String from;

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Hello SpringBoot"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>



}

  • 测试类测试接口
@SpringBootTest
public class HelloWorldApplicationTests {
    @Resource
    private MailService mailService;

    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">void</span> <span class="token function">contextLoads</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        mailService<span class="token punctuation">.</span><span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>



}

实现简单文本邮件 {#实现简单文本邮件}

  • 引入核心依赖包

官网地址: 传送门

<dependency>
  <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
  • 配置邮箱参数
# 邮箱配置
spring:
  mail:
    # 发送邮件服务器
    host: smtp.163.com
    # 用户名
    username: mobaijun8@163.com
    # 授权码
    password: *********************
    # 编码
    default-encoding: UTF-8
  • 封装 SimlpleMailMessage
/**
 * Software:IntelliJ IDEA 2020.1 x64
 * Author: MoBai·杰
 * ClassName:SayService
 * 类描述: 测试类
 */
@Service
public class MailService {
    /**
     * 注入用户名
     */
    @Value("${spring.mail.username}")
    private String from;

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Hello SpringBoot"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * to: 发送给谁, 邮件接收者
     * subject: 邮件主题
     * content: 邮件内容
     *
     * @param to
     * @param subject
     * @param content
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sendSimpleMail</span><span class="token punctuation">(</span><span class="token class-name">String</span> <span class="token keyword">to</span><span class="token punctuation">,</span> <span class="token class-name">String</span> subject<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 1. 创建邮件发送对象</span>
        <span class="token class-name">SimpleMailMessage</span> message <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleMailMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 2. 邮件接收者</span>
        message<span class="token punctuation">.</span><span class="token function">setTo</span><span class="token punctuation">(</span><span class="token keyword">to</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 3. 邮件主题</span>
        message<span class="token punctuation">.</span><span class="token function">setSubject</span><span class="token punctuation">(</span>subject<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 4. 邮件内容</span>
        message<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 5. 邮件发送者</span>
        message<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span>from<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>



}

  • 使用 JavaMailSender 进行发送
@Service
public class MailService {

    <span class="token comment">/**
     * 注入用户名
     */</span>
    <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${spring.mail.username}"</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> from<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">JavaMailSender</span> mailSender<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"Hello SpringBoot"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * to: 发送给谁, 邮件接收者
     * subject: 邮件主题
     * content: 邮件内容
     *
     * @param to
     * @param subject
     * @param content
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sendSimpleMail</span><span class="token punctuation">(</span><span class="token class-name">String</span> <span class="token keyword">to</span><span class="token punctuation">,</span> <span class="token class-name">String</span> subject<span class="token punctuation">,</span> <span class="token class-name">String</span> content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 1. 创建邮件发送对象</span>
        <span class="token class-name">SimpleMailMessage</span> message <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleMailMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 2. 邮件接收者</span>
        message<span class="token punctuation">.</span><span class="token function">setTo</span><span class="token punctuation">(</span><span class="token keyword">to</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 3. 邮件主题</span>
        message<span class="token punctuation">.</span><span class="token function">setSubject</span><span class="token punctuation">(</span>subject<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 4. 邮件内容</span>
        message<span class="token punctuation">.</span><span class="token function">setText</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 5. 邮件发送者</span>
        message<span class="token punctuation">.</span><span class="token function">setFrom</span><span class="token punctuation">(</span>from<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 6. 传入 message</span>
        mailSender<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>



}

  • 使用 junit 测试
@SpringBootTest
class HelloworldApplicationTests {
    @Resource
    private MailService mailService;

    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">void</span> <span class="token function">contextLoads</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        mailService<span class="token punctuation">.</span><span class="token function">sayHello</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">/**
     * 测试邮件发送
     */</span>
    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sendSimpleMail</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        mailService<span class="token punctuation">.</span><span class="token function">sendSimpleMail</span><span class="token punctuation">(</span><span class="token string">"mobaijun8@163.com"</span><span class="token punctuation">,</span><span class="token string">"第一封测试邮件"</span><span class="token punctuation">,</span><span class="token string">"墨白君你好, 我是第一封测试邮件"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>



}

  • 效果

测试效果

发送 Html 邮件 {#发送 Html 邮件}

  • service 添加方法 sendHtmlMail
/**
 * 发送 html 邮件
 * to: 发送给谁, 邮件接收者
 * subject: 邮件主题
 * content: 邮件内容
 */
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
    // 1. 创建:MimeMessage
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    // 2. 创建 MimeMessageHelper, 封装 mimeMessage
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    // 3. 邮件接收者
    helper.setTo(to);
    // 4. 邮件主题
    helper.setSubject(subject);
    // 5. 邮件内容:String text, boolean html
    helper.setText(content, true);
    // 6. 邮件发送者
    helper.setFrom(from);
    // 7. 传入 message
    mailSender.send(mimeMessage);
}
  • jinit 测试
/**
 * 测试 Html 邮件
 */
@Test
public void sendHtmlMail() throws MessagingException {
    // 封装 content 参数
    String content = "<html>\n" +
            "<body>\n" +
            "<h1> hello world, 这是一封 html 邮件!" +
            "</h1>\n" +
            "</body>\n" +
            "</html>";
    // 调用 service 方法测试
    mailService.sendHtmlMail("mobaijun8@163.com", "第一封测试邮件", content);
}
  • 效果

html 效果

发送附件邮件 {#发送附件邮件}

  • service 添加方法 sendAttachmentsMail
/**
 * 发送附件邮件
 * to: 发送给谁, 邮件接收者
 * subject: 邮件主题
 * content: 邮件内容
 */
public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException {
    // 1. 创建:MimeMessage
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    // 2. 创建 MimeMessageHelper, 封装 mimeMessage
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    // 3. 邮件接收者
    helper.setTo(to);
    // 4. 邮件主题
    helper.setSubject(subject);
    // 5. 邮件内容:String text, boolean html
    helper.setText(content, true);
    // 6. 邮件发送者
    helper.setFrom(from);
    // 7. 读取附件
    FileSystemResource file = new FileSystemResource(new File(filePath));
    // 8. 获取文件名称
    String fileName = file.getFilename();
    // 9. 传入文件名称和路径
    helper.addAttachment(fileName, file);
    // 10. 发送
    mailSender.send(mimeMessage);
}
  • junit 测试类
/**
 * 发送附件邮件
 */
@Test
public void sendAttachmentsMail() throws MessagingException {
    // 1. 创建附件路径
    String filePath = "G:\\IdeaProject\\springboot-email\\HELP.md";
    // 2. 调用 service 发送
    mailService.sendAttachmentsMail("mobaijun8@163.com", "第一封附件邮件", "墨白君你好, 我是第一封附件邮件", filePath);
}
  • 效果

附件邮件

发送图片邮件 {#发送图片邮件}

  • service 添加 sendInlineResourceMail 方法
/**
 * 发送图片邮件
 */
public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException {
    // 1. 创建:MimeMessage
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    // 2. 创建 MimeMessageHelper, 封装 mimeMessage
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    // 3. 邮件接收者
    helper.setTo(to);
    // 4. 邮件主题
    helper.setSubject(subject);
    // 5. 邮件内容:String text, boolean html
    helper.setText(content, true);
    // 6. 邮件发送者
    helper.setFrom(from);
    // 7. 读取附件
    FileSystemResource file = new FileSystemResource(new File(rscPath));
    helper.addInline(rscId, file);
    // 8. 发送
    mailSender.send(mimeMessage);
}
  • junit 测试方法
/**
 * 发送图片邮件
 */
@Test
public void sendInlineResourceMail() throws MessagingException {
    // 1. 创建图片路径
    String imagePath = "F:\\Users\\Administrator\\Pictures\\1.jpg";
    // 2. 构建图片 ID
    String rscId = "01";
    // 3. 构建正文主体
    String content = "<html><body>这是有图片的邮件:<img src=\'cid:" + rscId + "\'> </img></body></html>";
    // 4. 调用 service 发送
    mailService.sendInlineResourceMail("mobaijun8@163.com", "第一封图片邮件", content, imagePath, rscId);
}
  • 效果

图片邮件

发送模板邮件 {#发送模板邮件}

  • 新建 mailIndex.html 页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>框架师入职邀请邮件</title>
</head>
<body>
<p>hello 欢迎加入 [框架师] 大家庭,您的入职信息如下:</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>
<!--/*@thymesVar id="id" type="ch"*/-->
<a href="#" th:href="@{https://www.mobaijun.com/{id}(id=${id})}">验证链接</a>
<div style="color: #ff1a0e">让我们一起努力创造辉煌</div>
</body>
</html>
  • 添加 TemplateEngine, 注入
@Resource
private TemplateEngine templateEngine;
  • 测试方法
/**
 * 发送模板邮件
 */
@Test
public void sendThymeleafMail() throws MessagingException {
    // 1. 构建 import org.thymeleaf.context.Context; 模板
    Context context = new Context();
    context.setVariable("username", "MoBai");
    context.setVariable("id", "1");
    context.setVariable("num", "001");
    context.setVariable("salary", "3800");
    // 2. 使用 templateEngine.process 方法注入构建的参数
    String mailIndex = templateEngine.process("mailIndex", context);
    // 3. 调用 service 测试
    mailService.sendHtmlMail("mobaijun8@163.com", "第一封测试邮件", mailIndex);
}
  • 效果

模板邮件

邮件异常处理 {#邮件异常处理}

  • 定义唯一日志变量
// 设置唯一日志变量
private final Logger logger = LoggerFactory.getLogger(this.getClass());
  • 改造发送图片邮件
/**
 * 发送图片邮件
 */
public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) {
    // 9. 添加日志
    logger.info("发送静态邮件开始:{},{},{},{},{}", to, subject, content, rscPath, rscId);
    // 1. 创建:MimeMessage
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    try {
        // 2. 创建 MimeMessageHelper, 封装 mimeMessage
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        // 3. 邮件接收者
        helper.setTo(to);
        // 4. 邮件主题
        helper.setSubject(subject);
        // 5. 邮件内容:String text, boolean html
        helper.setText(content, true);
        // 6. 邮件发送者
        helper.setFrom(from);
        // 7. 读取附件
        FileSystemResource file = new FileSystemResource(new File(rscPath));
        helper.addInline(rscId, file);
        // 8. 发送
        mailSender.send(mimeMessage);
        // 11. 成功提示
        logger.info("发送静态邮件成功!!!");
    } catch (MessagingException e) {
        // 10. 失败提示
        logger.error("发送静态邮件失败:" + e);
    }
}
  • junit 测试
/**
 * 发送图片邮件
 */
@Test
public void sendInlineResourceMail() {
    // 1. 创建图片路径
    String imagePath = "F:\\Users\\Administrator\\Pictures\\1.jpg";
    // 2. 构建图片 ID
    String rscId = "01";
    // 3. 构建正文主体
    String content = "<html><body>这是有图片的邮件:<img src=\'cid:" + rscId + "\'> </img></body></html>";
    // 4. 调用 service 发送
    mailService.sendInlineResourceMail("mobaijun8@163.com", "第一封图片邮件", content, imagePath, rscId);
}
  • 查看方法日志

日志内容

  • 邮件效果

图片邮件

常见邮件程序错误:

  • 421:HL:ICC 该 IP 同时并发连接数过大
  • 451:Requested mail action not taken: too muck fail...登录失败次数过多, 被临时禁止登录
  • 553: authentication is required 认证失败
  • 完整邮件系统
  • 使用独立微服务
  • 邮件异常处理
  • 发送失败定时重试邮件
  • 使用异步发送
赞(1)
未经允许不得转载:工具盒子 » 【WEB 系列】SpringBoot 实现邮件发送