Spring Boot 发送邮件的几种方式
准备工作(以QQ邮箱为例)
SMTP 协议全称为 Simple Mail Transfer Protocol,译作简单邮件传输协议,它定义了邮件客户端软件与 SMTP 服务器之间,以及 SMTP 服务器与 SMTP 服务器之间的通信规则。
也就是说 aaa@qq.com 用户先将邮件投递到腾讯的 SMTP 服务器这个过程就使用了 SMTP 协议,然后腾讯的 SMTP 服务器将邮件投递到网易的 SMTP 服务器这个过程也依然使用了 SMTP 协议,SMTP 服务器就是用来收邮件。
而 POP3 协议全称为 Post Office Protocol ,译作邮局协议,它定义了邮件客户端与 POP3 服务器之间的通信规则,那么该协议在什么场景下会用到呢?当邮件到达网易的 SMTP 服务器之后, 111@163.com 用户需要登录服务器查看邮件,这个时候就该协议就用上了:邮件服务商都会为每一个用户提供专门的邮件存储空间,SMTP 服务器收到邮件之后,就将邮件保存到相应用户的邮件存储空间中,如果用户要读取邮件,就需要通过邮件服务商的 POP3 邮件服务器来完成。
所以在使用springboot发送邮件之前,要开启POP3和SMTP协议,需要获得邮件服务器的授权码,这里以qq邮箱为例,展示获取授权码的过程:
在账户的下面有一个开启SMTP协议的开关并进行密码验证:
以下就是你的授权码:
创建项目
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置邮箱基本信息
spring:
mail:
# 配置 SMTP 服务器地址
host: smtp.qq.com
# 发送者邮箱
username: ## 自己的邮箱
# 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
password: ## 自己的密钥
# 端口号465或587
port: 587
# 默认的邮件编码为UTF-8
default-encoding: UTF-8
# 配置SSL 加密工厂
properties:
mail:
smtp:
socketFactoryClass: javax.net.ssl.SSLSocketFactory
#表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
debug: true
- 126邮箱SMTP服务器地址: smtp.126.com, 端口号: 465或者994
- 2163邮箱SMTP服务器地址: smtp.163.com, 端口号: 465或者994
- yeah邮箱SMTP服务器地址: smtp.yeah.net, 端口号: 465或者994
- qq邮箱SMTP服务器地址:smtp.qq.com, 端口号: 465或587
配置好这些后,springboot会自动帮我们配置好相关的邮件发送类。
发送普通邮件
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String fromMail;
@Test
void testSendSimpleMail() {
// 构建一个邮件对象
SimpleMailMessage message = new SimpleMailMessage();
// 设置邮件主题
message.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
message.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
message.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
message.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
message.setSentDate(new Date());
// 设置邮件的正文
message.setText("这是测试邮件的正文");
// 发送邮件
mailSender.send(message);
}
抄送:将邮件同时送给收信人以外的人,用户所写的邮件抄送一份给别人,对方可以看见该用户的E-mail发送给了谁。
密送:将邮件同时送给收信人以外的人,用户所写的邮件抄送一份给别人,但是对方不能查看到这封邮件同时还发送给了哪些人。
发送的效果如下:
发送带附件的邮件
@Test
void testSendAttachFileMail() throws Exception {
MimeMessage mimeMessage = mailSender.createMimeMessage();
// true表示构建一个可以带附件的邮件对象
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
// 设置邮件主题
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// 设置邮件的正文
helper.setText("这是测试邮件的正文");
// 第一个参数是自定义的名称,后缀需要加上,第二个参数是文件的位置
helper.addAttachment("资料.txt", new File("D:\\data\\附件.txt"));
// 发送邮件
mailSender.send(mimeMessage);
}
注意这里的构建邮件对象的方式跟上面有一点不同,因为这里是需要带附件上传,所以先使用javaMailSender创建一个复杂的邮件对象,然后使用MimeMessageHelper对邮件进行配置,MimeMessageHelper 是一个邮件配置的辅助工具类,创建时候的 true 表示构建一个 multipart message 类型的邮件,有了 MimeMessageHelper 之后,我们针对邮件的配置都是由 MimeMessageHelper 来代劳。然后通过addAttachment()方法添加附件。
发送的效果如下:
发送带图片资源的邮件
/**
* 正文中带图片的邮件
*
* @throws MessagingException 邮件异常
*/
@Test
void testSendImgResMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// src='cid:image01' 占位符写法 ,第二个参数true表示这是一个html文本
helper.setText("<p>hello 大家好,这是一封测试邮件,这封邮件包含两种图片,分别如下</p><p>第一张图片:</p><img src='cid:image01'/><p>第二张图片:</p><img src='cid:image02'/>", true);
// 第一个参数指的是html中占位符的名字,第二个参数就是文件的位置
helper.addInline("image01", new FileSystemResource(new File("D:\\image\\test01.jpg")));
helper.addInline("image02", new FileSystemResource(new File("D:\\image\\test02.jpg")));
mailSender.send(mimeMessage);
}
发送的效果如下:
在公司实际开发中,第一种和第三种都不是使用最多的邮件发送方案。因为正常来说,邮件的内容都是比较的丰富的,所以大部分邮件都是通过 HTML 来呈现的,如果直接拼接 HTML 字符串,这样以后不好维护,为了解决这个问题,一般邮件发送,都会有相应的邮件模板。
使用 Thymeleaf 作邮件模板
推荐在 Spring Boot 中使用 Thymeleaf 来构建邮件模板。因为 Thymeleaf 的自动化配置提供了一个 TemplateEngine,通过 TemplateEngine 可以方便的将 Thymeleaf 模板渲染为 HTML ,同时,Thymeleaf 的自动化配置在这里是继续有效的 。
首先,引入 Thymeleaf 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
创建模板:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8">
<title>发送验证码</title>
<base target="_blank"/>
<style type="text/css">::-webkit-scrollbar {
display: none;
}</style>
<style id="cloudAttachStyle" type="text/css">#divNeteaseBigAttach, #divNeteaseBigAttach_bak {
display: none;
}</style>
<style id="blockquoteStyle" type="text/css">blockquote {
display: none;
}</style>
<style type="text/css">
body {
font-size: 14px;
font-family: arial, verdana, sans-serif;
line-height: 1.666;
padding: 0;
margin: 0;
overflow: auto;
white-space: normal;
word-wrap: break-word;
min-height: 100px
}
td, input, button, select, body {
font-family: Helvetica, 'Microsoft Yahei', verdana
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: 95%
}
th, td {
font-family: arial, verdana, sans-serif;
line-height: 1.666
}
img {
border: 0
}
header, footer, section, aside, article, nav, hgroup, figure, figcaption {
display: block
}
blockquote {
margin-right: 0px
}
</style>
</head>
<body tabindex="0" role="listitem">
<table width="700" border="0" align="center" cellspacing="0" style="width:700px;">
<tbody>
<tr>
<td>
<div style="width:700px;margin:0 auto;border-bottom:1px solid #ccc;margin-bottom:30px;">
<table border="0" cellpadding="0" cellspacing="0" width="700" height="39"
style="font:12px Tahoma, Arial, 宋体;">
<tbody>
<tr>
<td width="210"></td>
</tr>
</tbody>
</table>
</div>
<div style="width:680px;padding:0 10px;margin:0 auto;">
<div style="line-height:1.5;font-size:14px;margin-bottom:25px;color:#4d4d4d;">
<strong style="display:block;margin-bottom:15px;">尊敬的用户:<span
style="color:#f60;font-size: 16px;"></span>您好!</strong>
<strong style="display:block;margin-bottom:15px;">
您的验证码为:<span style="color:#f60;font-size: 16px" th:text="${code}"></span>。
</strong>
</div>
<div style="margin-bottom:30px;">
<small style="display:block;margin-bottom:20px;font-size:12px;">
<p style="color:#747474;">
注意:此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作,请及时登录并修改密码以保证帐户安全
<br>(工作人员不会向你索取此验证码,请勿泄漏!)
</p>
</small>
</div>
</div>
<div style="width:700px;margin:0 auto;">
<div style="padding:10px 10px 0;border-top:1px solid #ccc;color:#747474;margin-bottom:20px;line-height:1.3em;font-size:12px;">
<p>此为系统邮件,请勿回复<br>
请保管好您的邮箱,避免账号被他人盗用
</p>
<p>公司名称</p>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
发送邮件:
@Autowired
private TemplateEngine templateEngine;
@Test
void testSendThymeleafMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// 这里引入的是Template的Context
Context context = new Context();
// 设置模板中的变量
context.setVariable("code", "123456");
// 第一个参数为模板的名称
String process = templateEngine.process("mailTemplate.html", context);
// 第二个参数true表示这是一个html文本
helper.setText(process, true);
mailSender.send(mimeMessage);
}
发送的效果如下:
完整代码:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
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.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Date;
@SpringBootTest
public class MailSenderTest {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String fromMail;
@Autowired
private TemplateEngine templateEngine;
@Test
void testSendSimpleMail() {
// 构建一个邮件对象
SimpleMailMessage message = new SimpleMailMessage();
// 设置邮件主题
message.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
message.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
message.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
message.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
message.setSentDate(new Date());
// 设置邮件的正文
message.setText("这是测试邮件的正文");
// 发送邮件
mailSender.send(message);
}
@Test
void testSendAttachFileMail() throws Exception {
MimeMessage mimeMessage = mailSender.createMimeMessage();
// true表示构建一个可以带附件的邮件对象
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
// 设置邮件主题
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// 设置邮件的正文
helper.setText("这是测试邮件的正文");
// 第一个参数是自定义的名称,后缀需要加上,第二个参数是文件的位置
helper.addAttachment("资料.txt", new File("D:\\data\\附件.txt"));
// 发送邮件
mailSender.send(mimeMessage);
}
/**
* 正文中带图片的邮件
*
* @throws MessagingException 邮件异常
*/
@Test
void testSendImgResMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// src='cid:image01' 占位符写法 ,第二个参数true表示这是一个html文本
helper.setText("<p>hello 大家好,这是一封测试邮件,这封邮件包含两种图片,分别如下</p><p>第一张图片:</p><img src='cid:image01'/><p>第二张图片:</p><img src='cid:image02'/>", true);
// 第一个参数指的是html中占位符的名字,第二个参数就是文件的位置
helper.addInline("image01", new FileSystemResource(new File("D:\\image\\test01.jpg")));
helper.addInline("image02", new FileSystemResource(new File("D:\\image\\test02.jpg")));
mailSender.send(mimeMessage);
}
@Test
void testSendThymeleafMail() throws MessagingException {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("这是一封测试邮件");
// 设置邮件发送者,这个跟application.yml中设置的要一致
helper.setFrom(fromMail);
// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
// message.setTo("10*****16@qq.com","12****32*qq.com");
helper.setTo("1367256434@qq.com");
// 设置邮件抄送人,可以有多个抄送人
helper.setCc("728578649@qq.com");
// 设置隐秘抄送人,可以有多个
// message.setBcc("");
// 设置邮件发送日期
helper.setSentDate(new Date());
// 这里引入的是Template的Context
Context context = new Context();
// 设置模板中的变量
context.setVariable("code", "123456");
// 第一个参数为模板的名称
String process = templateEngine.process("mailTemplate.html", context);
// 第二个参数true表示这是一个html文本
helper.setText(process, true);
mailSender.send(mimeMessage);
}
}