概述 {#概述}
- 邮件的使用场景
- 邮件发送原理
- 邮件发送历史
- 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);
}
- 效果
发送附件邮件 {#发送附件邮件}
- 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 认证失败
- 完整邮件系统
- 使用独立微服务
- 邮件异常处理
- 发送失败定时重试邮件
- 使用异步发送