邮件发送的整合与使用
1. 基础协议及邮件配置整合
一、名词概念解释
什么是 POP3、SMTP 和 IMAP?
简单的说:POP3 和 IMAP 是⽤来从服务器上下载邮件的。SMTP 适⽤于发送或中转信件时找到下⼀个⽬的地。所以我们发送邮件应该使⽤ SMTP 协议。
什么是免费邮箱客户端授权码功能?
邮箱客户端授权码是为了避免您的邮箱密码被盗后,盗号者通过客户端登录邮箱⽽独特设计的安防功能。可以理解为客户端授权码为邮件发送的⼆次密码。
⼆、 整合邮件发送功能
2.1 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.2 邮箱配置
QQ 系邮箱配置
官方配置说明:参考官方帮助中心
获取客户端授权码:参考官方帮助中心
详细的配置如下:
spring:
mail:
host: smtp.qq.com #发送邮件服务器
username: xx@qq.com #QQ邮箱
password: xxxxxxxxxxx #客户端授权码
protocol: smtp #发送邮件协议
properties.mail.smtp.auth: true
properties.mail.smtp.port: 465 #端⼝号465或587
properties.mail.display.sendmail: Javen #可以任意
properties.mail.display.sendname: Spring Boot Guide Email #可以任意
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
说明:开启 SSL 时使⽤587端⼝时⽆法连接 QQ 邮件服务器
⽹易系(126/163/yeah)邮箱配置
网易邮箱客户端授码:参考官方帮助中心
客户端端口配置说明:参考官方帮助中心
详细的配置如下:
spring:
mail:
host: smtp.126.com
username: xx@126.com
password: xxxxxxxx
protocol: smtp
properties.mail.smtp.auth: true
properties.mail.smtp.port: 994 #465或者994
properties.mail.display.sendmail: Javen
properties.mail.display.sendname: Spring Boot Guide Email
properties.mail.smtp.starttls.enable: true
properties.mail.smtp.starttls.required: true
properties.mail.smtp.ssl.enable: true
default-encoding: utf-8
from: xx@126.com
特别说明:
- 126 邮箱 SMTP 服务器地址:smtp.126.com,端⼝号:465 或者 994
- 163 邮箱 SMTP 服务器地址:smtp.163.com,端⼝号:465 或者 994
- yeah 邮箱 SMTP 服务器地址:smtp.yeah.net,端⼝号:465 或者 994
有的邮件服务器接受使⽤客户端授权码发邮件,有的邮件服务器接受使⽤邮箱密码来发送邮件,所以 password 的配置不能⼀概⽽论。客户端授权码不⾏,就试试⽤邮箱密码;邮箱密码不⾏,就试试客户 端授权码。
三、发送简单邮件
这⾥的简单邮件就是指邮件的内容只是普通⽂字的这种邮件。
@Service
public class MailService {
@Resource
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String fromEmail;
/**
* 发送⽂本邮件
*/
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(fromEmail);
message.setTo(to);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
}
sendSimpleMail 的三个参数依次是:邮件的发送⽬标,邮件的标题,邮件的内容.
测试代码:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MailServiceTest {
@Resource
MailService mailService;
@Test
public void sendSimpleMail() {
mailService.sendSimpleMail("16422802@qq.com",
"普通⽂本邮件",
"普通⽂本邮件内容测试");
}
}
测试结果:
附录:QQ 邮箱发邮件设置
1.开启 SMTP 服务
2.在配置开启 SMTP 之后,会返回给我们⼀个客户端授权码。这个授权码就是上⽂中⽤来发邮件的 password。
2. 发送 html 和基于模板的邮件
⼀、发送 html 邮件服务
sendHtmlMail 函数的第⼀个参数是发送⽬标邮箱,第⼆个参数是邮件标题,第三个参数是邮件的正⽂(html)。
- 上⼀节中发送普通的⽂本⽂件邮件,使⽤的是 SimpleMailMessage
- 下⽂代码中发送的正⽂是 HTML 的邮件,使⽤的是 MimeMessage
/**
* 发送html邮件
*/
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
//注意这⾥使⽤的是MimeMessage
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
//第⼆个参数是否是html,true表示发送的邮件正⽂是html⽂本
helper.setText(content, true);
mailSender.send(message);
}
测试⽤例,我们将 HTML 以字符串拼接的⽅式写在 Java 代码⾥⾯,这样对于开发者⽽⾔不太友好。可以 结合 Java 模板引擎,如 Freemarker 来来发送 HTML 邮件。
@Test
public void sendHtmlMail() throws MessagingException {
mailService.sendHtmlMail(
"2470752581@qq.com",
"一封HTML测试邮件",
"""
<body>
<div style="width:600px;height:400px;margin:auto;background:#bdd8f6;color:#fff;text-align:center;">
<h3>涵的邮件</h3>
<img src="https://syhan.oss-cn-hangzhou.aliyuncs.com/img/me.png"\040
style="width:100px;height:100px;">
<p>
<a style="text-decoration: none;color: #fff;" href="http://syhan.top" target="_bank">
<strong>我的博客主页</strong>
</a>
</p>
</div>
</body>
"""
);
}
测试结果:
⼆、基于 freemarker 模板的邮件
基于 freemarker 模板邮件本质上,还是发送 html 邮件,只不过是有⼀个把模板转换成 html 字符串的过程。
- 先添加 freemarker 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
- application.yml 配置 freemarker
spring:
freemarker:
cache: false # 缓存配置 开发阶段应该配置为false 因为经常会改
suffix: .ftl # 模版⽂件后缀名
charset: UTF-8 # ⽂件编码
template-loader-path: classpath:/templates/
- Article 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Article {
private Long id;
private String author;
private String title;
private String content;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}
- 编写模板邮件发送测试代码
@Test
public void sendTemplateMail() throws Exception {
// 添加动态数据,替换模版里面的占位符
List<Article> articles = new ArrayList<>();
articles.add(new Article(1L, "syhan", "今天星期一", "内容一", new Date()));
articles.add(new Article(2L, "syhan", "今天下雨天", "内容二", new Date()));
Template template = freeMarkerConfigurer.getConfiguration().getTemplate("freemarker-temp.ftl");
//将模版文件及数据渲染完成后,转换为html字符串
Map<String, Object> model = new HashMap<>();
model.put("articles", articles);
String templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
// 发送邮件
mailService.sendHtmlMail("2470752581@qq.com", "这是一封freemarker模版的html测试邮件",templateHtml);
}
- templates ⽬录新建 freemarker-temp.ftl 模板⽂件
<!DOCTYPE html>
<html lang="en"> <head lang="en">
<meta charset="UTF-8"/>
<title>freemarker简单示例</title>
</head> <body> <h1>Hello Freemarker</h1> <table class="">
<tr>
<td>作者</td>
<td>教程名称</td>
<td>内容</td>
</tr>
<#list articles as article>
<tr>
<td>${article.author}</td>
<td>${article.title}</td>
<td>${article.content}</td>
</tr>
</#list>
</table>
</body>
</html>
- 测试结果:
3. 发送带附件和内联附件邮件
⼀、发送带附件的邮件
/**
* 发送带附件的邮件
*/
public void sendAttachmentsMail(String to, String subject, String
content, String filePath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
//带附件第⼆个参数true
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
//添加附件资源
FileSystemResource file = new FileSystemResource(new File(filePath));
String fileName =
filePath.substring(filePath.lastIndexOf(File.separator));
helper.addAttachment(fileName, file);
//发送邮件
mailSender.send(message);
}
sendAttachmentsMail 的第⼀个参数是发送⽬标邮箱,第⼆个参数是邮件的内容,第三个参数是邮件的附件。
运⾏如下的测试⽤例进⾏测试:
@Test
public void sendAttachmentsMailTest() throws MessagingException {
String filePath = "/Users/apple/Desktop/me.png";
mailService.sendAttachmentsMail(
"2470752581@qq.com",
"这是一封带附件的邮件--来自syhan",
"邮件中有附件,请注意查收!",
filePath);
}
测试结果:
⼆、发送内联附件的邮件
所谓的内联附件就是附件⽂件在邮件正⽂内显示,通常是⼀图⽚资源。
/**
* 发送正⽂中有静态资源的邮件
*/
public void sendResourceMail(String to, String subject, String content,
String rscPath, String rscId) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);
//添加内联附件,指定⼀个资源id:rscId
FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
mailSender.send(message);
}
sendResourceMail ⽅法的参数说明:
参数⼀:发送邮件的⽬标邮箱
参数⼆:⽂件的标题
参数三:邮件的正⽂:html(含图⽚资源 id:rscId)
参数四:图⽚资源⽂件本地磁盘路径 res
参数五:图⽚资源⽂件的资源 Id:rscId
参数三 HTML ⽂本发现正⽂中包含<img src=cid: rscId>
,就会根据参数五 helper.addInline(rscId, res);,找 到参数四对应的资源⽂件 res,并渲染到 HTML ⾥⾯。
测试⽤例,执⾏之后看结果
@Test
public void sendResourceMail() throws MessagingException {
String rscId = "syhan";
String content = "<html><body>这是有图片的邮件<br/><img src='cid:" + rscId + "'></body></html>";
String imgPath = "/Users/apple/Desktop/vlog.png";
mailService.sendResourceMail(
"2470752581@qq.com",
"这邮件中包含图片",
content,
imgPath,
rscId);
}
测试结果: