Skip to content

Commit 4d75e7b

Browse files
committed
Springboot 系列(十三)使用邮件服务
1 parent 08a70da commit 4d75e7b

1 file changed

Lines changed: 360 additions & 0 deletions

File tree

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
---
2+
title: Springboot 系列(十三)使用邮件服务
3+
toc_number: true
4+
date: 2019-03-12 00:20:22
5+
url: springboot/springboot-13-email
6+
tags:
7+
- Springboot
8+
- 邮件
9+
- E-mail
10+
categories:
11+
- Springboot
12+
---
13+
14+
![桌面生活(来自网络)](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/00a2b4768bf601da67118c0acb347876.jpg)我们这个时代,邮件服务不管是对于工作上的交流,还是平时的各种邮件通知,都是一个十分重要的存在。Java 从很早时候就可以通过 Java mail 支持邮件服务。Spring 更是对 Java mail 进行了进一步的封装,抽象出了 `JavaMailSender`. 后来随着 Springboot 的出现,理所当然的出现了 `spring-boot-starter-mail`. 不管怎么说,每次的封装都让使用变得越来越简单。
15+
<!-- more -->
16+
## Springboot mail 依赖
17+
18+
创建 Springboot 项目不提,先看一下总体目录结构。
19+
![项目结构](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/87989c22d455e3d428811562649c840d.jpg)
20+
21+
直接引入 Springboot 邮件服务所需的依赖。
22+
```xml
23+
<dependencies>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-web</artifactId>
27+
</dependency>
28+
<!-- 邮件服务 -->
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-mail</artifactId>
32+
</dependency>
33+
<!-- Thymeleaf 模版,用于发送模版邮件 -->
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-starter-thymeleaf</artifactId>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>org.projectlombok</groupId>
41+
<artifactId>lombok</artifactId>
42+
<optional>true</optional>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-starter-test</artifactId>
48+
<scope>test</scope>
49+
</dependency>
50+
</dependencies>
51+
```
52+
53+
## Springboot mail 配置
54+
使用邮件服务需要配置自己可以使用的邮箱信息,一般需要配置发送协议 SMTP、邮箱帐号(本次以126邮箱为例)、邮箱密码以及编码格式。
55+
```properties
56+
spring.mail.host=smtp.126.com
57+
spring.mail.port=25
58+
# 你的邮箱地址
59+
spring.mail.username[email protected]
60+
# 你的授权码(126 和 163 以及 qq 邮箱 都需要授权码登录,没有授权码的直接登录网页版邮箱设置里设置)
61+
spring.mail.password=password
62+
spring.mail.default-encoding=UTF-8
63+
```
64+
## Springboot mail 文本邮件
65+
文本邮件是最简单也是最基础的一种邮件,使用 Spring 封装的 `JavaMailSender` 直接发送就可以了。
66+
67+
创建 `MailService` 类,注入 `JavaMailSender` 用于发送邮件,使用 `@Value("${spring.mail.username}")` 绑定配置文件中的参数用于设置邮件发送的来邮箱。使用 `@Service` 注解把 `MailService` 注入到 Spring 容器,使用 `Lombok``@Slf4j` 引入日志。
68+
```java
69+
/**
70+
* <p>
71+
* 邮件服务
72+
*
73+
* @Author niujinpeng
74+
* @Date 2019/3/10 21:45
75+
*/
76+
@Service
77+
@Slf4j
78+
public class MailService {
79+
80+
@Value("${spring.mail.username}")
81+
private String from;
82+
83+
@Autowired
84+
private JavaMailSender mailSender;
85+
86+
/**
87+
* 发送简单文本邮件
88+
*
89+
* @param to
90+
* @param subject
91+
* @param content
92+
*/
93+
public void sendSimpleTextMail(String to, String subject, String content) {
94+
SimpleMailMessage message = new SimpleMailMessage();
95+
message.setTo(to);
96+
message.setSubject(subject);
97+
message.setText(content);
98+
message.setFrom(from);
99+
mailSender.send(message);
100+
log.info("【文本邮件】成功发送!to={}", to);
101+
}
102+
}
103+
```
104+
创建 Springboot 的单元测试类测试文本邮件,实验中的收信人为了方便,都设置成了自己的邮箱。
105+
```java
106+
@RunWith(SpringRunner.class)
107+
@SpringBootTest
108+
public class MailServiceTest {
109+
110+
@Autowired
111+
private MailService mailService;
112+
@Autowired
113+
private TemplateEngine templateEngine;
114+
115+
@Test
116+
public void sendSimpleTextMailTest() {
117+
String to = "[email protected]";
118+
String subject = "Springboot 发送简单文本邮件";
119+
String content = "<p>第一封 Springboot 简单文本邮件</p>";
120+
mailService.sendSimpleTextMail(to, subject, content);
121+
}
122+
}
123+
```
124+
运行单元测试,测试文本邮件的发送。
125+
126+
PS:如果运行报出异常 `AuthenticationFailedException: 535 Error`. 一般都是用户名和密码有误。
127+
```log
128+
Caused by: javax.mail.AuthenticationFailedException: 535 Error: authentication failed
129+
130+
at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:965)
131+
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:876)
132+
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
133+
at javax.mail.Service.connect(Service.java:366)
134+
at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:517)
135+
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:436)
136+
... 34 more
137+
```
138+
正常运行输出成功发送的日志。
139+
```log
140+
2019-03-11 23:35:14.743 INFO 13608 --- [ main] n.codingme.boot.service.MailServiceTest : Started MailServiceTest in 3.964 seconds (JVM running for 5.749)
141+
2019-03-11 23:35:24.718 INFO 13608 --- [ main] net.codingme.boot.service.MailService : 【文本邮件】成功发送![email protected]
142+
```
143+
查看邮箱中的收信。
144+
145+
![文本邮件](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/e391dbce4b614779ae9a024908ef0275.jpg)
146+
147+
文本邮件正常收到,同时可见文本邮件中的 HTML 标签也不会被解析。
148+
149+
## Springboot mail HTML 邮件
150+
在上面的 `MailService` 类里新加一个方法 `sendHtmlMail`,用于测试 HTML 邮件。
151+
```java
152+
/**
153+
* 发送 HTML 邮件
154+
*
155+
* @param to
156+
* @param subject
157+
* @param content
158+
* @throws MessagingException
159+
*/
160+
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
161+
MimeMessage message = mailSender.createMimeMessage();
162+
MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
163+
messageHelper.setFrom(from);
164+
messageHelper.setTo(to);
165+
messageHelper.setSubject(subject);
166+
// true 为 HTML 邮件
167+
messageHelper.setText(content, true);
168+
mailSender.send(message);
169+
log.info("【HTML 邮件】成功发送!to={}", to);
170+
}
171+
```
172+
在测试方法中增加 HTML 邮件测试方法。
173+
```java
174+
@Test
175+
public void sendHtmlMailTest() throws MessagingException {
176+
String to = "[email protected]";
177+
String subject = "Springboot 发送 HTML 邮件";
178+
String content = "<h2>Hi~</h2><p>第一封 Springboot HTML 邮件</p>";
179+
mailService.sendHtmlMail(to, subject, content);
180+
}
181+
```
182+
运行单元测试,查看收信情况。
183+
184+
![HTML 邮件](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/147b7f68d12e0080b408a581414fb92a.jpg)
185+
186+
HTML 邮件正常收到,HTML 标签也被解析成对应的样式。
187+
188+
## Springboot mail 附件邮件
189+
在上面的 `MailService` 类里新加一个方法 `sendAttachmentMail`,用于测试 附件邮件。
190+
```java
191+
/**
192+
* 发送带附件的邮件
193+
*
194+
* @param to
195+
* @param subject
196+
* @param content
197+
* @param fileArr
198+
*/
199+
public void sendAttachmentMail(String to, String subject, String content, String... fileArr)
200+
throws MessagingException {
201+
MimeMessage mimeMessage = mailSender.createMimeMessage();
202+
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
203+
messageHelper.setFrom(from);
204+
messageHelper.setTo(to);
205+
messageHelper.setSubject(subject);
206+
messageHelper.setText(content, true);
207+
208+
// 添加附件
209+
for (String filePath : fileArr) {
210+
FileSystemResource fileResource = new FileSystemResource(new File(filePath));
211+
if (fileResource.exists()) {
212+
String filename = fileResource.getFilename();
213+
messageHelper.addAttachment(filename, fileResource);
214+
}
215+
}
216+
mailSender.send(mimeMessage);
217+
log.info("【附件邮件】成功发送!to={}", to);
218+
}
219+
```
220+
在测试方法中增加附件邮件测试方法。
221+
```java
222+
@Test
223+
public void sendAttachmentTest() throws MessagingException {
224+
String to = "[email protected]";
225+
String subject = "Springboot 发送 HTML 附件邮件";
226+
String content = "<h2>Hi~</h2><p>第一封 Springboot HTML 附件邮件</p>";
227+
String filePath = "pom.xml";
228+
mailService.sendAttachmentMail(to, subject, content, filePath, filePath);
229+
}
230+
```
231+
运行单元测试,查看收信情况。
232+
233+
![附件邮件](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/0ab42e65ae35c7970d7954bf5a985a79.jpg)
234+
235+
带附件的邮件正常收到,多个附件的实现方式同理。
236+
237+
## Springboot mail 图片邮件
238+
图片邮件和其他的邮件方式略有不同,图片邮件需要先在内容中定义好图片的位置并出给一个记录 ID ,然后在把图片加到邮件中的对于的 ID 位置。
239+
240+
在上面的 `MailService` 类里新加一个方法 `sendImgMail`,用于测试 附件邮件。
241+
```java
242+
/**
243+
* 发送带图片的邮件
244+
*
245+
* @param to
246+
* @param subject
247+
* @param content
248+
* @param imgMap
249+
*/
250+
public void sendImgMail(String to, String subject, String content, Map<String, String> imgMap)
251+
throws MessagingException {
252+
MimeMessage mimeMessage = mailSender.createMimeMessage();
253+
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
254+
messageHelper.setFrom(from);
255+
messageHelper.setTo(to);
256+
messageHelper.setSubject(subject);
257+
messageHelper.setText(content, true);
258+
// 添加图片
259+
for (Map.Entry<String, String> entry : imgMap.entrySet()) {
260+
FileSystemResource fileResource = new FileSystemResource(new File(entry.getValue()));
261+
if (fileResource.exists()) {
262+
String filename = fileResource.getFilename();
263+
messageHelper.addInline(entry.getKey(), fileResource);
264+
}
265+
}
266+
mailSender.send(mimeMessage);
267+
log.info("【图片邮件】成功发送!to={}", to);
268+
}
269+
```
270+
在测试方法中增加图片邮件测试方法,测试方法中使用的 apple.png 是项目里的一个图片。可以看上面的项目结构。
271+
```java
272+
@Test
273+
public void sendImgTest() throws MessagingException {
274+
String to = "[email protected]";
275+
String subject = "Springboot 发送 HTML 图片邮件";
276+
String content =
277+
"<h2>Hi~</h2><p>第一封 Springboot HTML 图片邮件</p><br/><img src=\"cid:img01\" /><img src=\"cid:img02\" />";
278+
String imgPath = "apple.png";
279+
Map<String, String> imgMap = new HashMap<>();
280+
imgMap.put("img01", imgPath);
281+
imgMap.put("img02", imgPath);
282+
mailService.sendImgMail(to, subject, content, imgMap);
283+
}
284+
```
285+
运行单元测试,查看收信情况。
286+
287+
![图片邮件](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/a676fadf6b40195c7de746adff0700bc.jpg)
288+
289+
两个图片正常显示在邮件里。
290+
291+
## Springboot mail 模版邮件
292+
模版邮件的用处很广泛,像经常收到的注册成功邮件或者是操作通知邮件等都是模版邮件,模版邮件往往只需要更改其中的几个变量。Springboot 中的模版邮件首选需要选择一款模版引擎,在引入依赖的时候已经增加了模版引擎 `Thymeleaf`.
293+
294+
模版邮件首先需要一个邮件模版,我们在 `Templates` 下新建一个 `HTML` 文件 `RegisterSuccess.html`. 其中的 username 是给我们自定义的。
295+
```html
296+
<!DOCTYPE html>
297+
<html lang="en" xmlns:th="http://www.thymeleaf.org">
298+
<head>
299+
<meta charset="UTF-8">
300+
<title>注册成功通知</title>
301+
</head>
302+
<body>
303+
<p>[[${username}]],您好!
304+
</p>
305+
<p>
306+
新的公钥已添加到你的账户:<br/>
307+
标题: HP-WIN10 <br/>
308+
如果公钥无法使用,你可以在这里重新添加: SSH Keys
309+
</p>
310+
</body>
311+
</html>
312+
```
313+
在邮件服务 `MailService` 中注入模版引擎,然后编写邮件模版发送代码。
314+
```java
315+
@Autowired
316+
private TemplateEngine templateEngine;
317+
318+
/**
319+
* 发送模版邮件
320+
*
321+
* @param to
322+
* @param subject
323+
* @param paramMap
324+
* @param template
325+
* @throws MessagingException
326+
*/
327+
public void sendTemplateMail(String to, String subject, Map<String, Object> paramMap, String template)
328+
throws MessagingException {
329+
Context context = new Context();
330+
// 设置变量的值
331+
context.setVariables(paramMap);
332+
String emailContent = templateEngine.process(template, context);
333+
sendHtmlMail(to, subject, emailContent);
334+
log.info("【模版邮件】成功发送!paramsMap={},template={}", paramMap, template);
335+
}
336+
```
337+
在单元单元测试中增加模版邮件测试方法,然后发送邮件测试。
338+
```java
339+
@Test
340+
public void sendTemplateMailTest() throws MessagingException {
341+
String to = "[email protected]";
342+
String subject = "Springboot 发送 模版邮件";
343+
Map<String, Object> paramMap = new HashMap();
344+
paramMap.put("username", "Darcy");
345+
mailService.sendTemplateMail(to, subject, paramMap, "RegisterSuccess");
346+
}
347+
```
348+
查看收信情况。
349+
350+
![模版邮件](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2019/8244d50efe797cfa3ceb14aab7b7b461.jpg)
351+
352+
可以发现模版邮件已经正常发送了。
353+
354+
## Springboot mail 补充
355+
上面的例子中,是 Springboot 邮件服务的基本用法,代码也有很多重复,和实际的使用情况相比还有很多不足,比如缺少`异常处理机制`,在发送失败时的`重试机制`也没有,实际情况中邮件服务往往对实时性不高,多说情况下会用于`异步请求`
356+
357+
文章相关代码已经上传 Github [Spring Boot 相关整合 - 邮件服务](https://github.com/niumoo/springboot/tree/master/springboot-mail)
358+
359+
<完>
360+
本文原发于个人博客:[https://www.wdbyte.com](https://www.wdbyte.com) 转载请注明出处。

0 commit comments

Comments
 (0)