在Spring Boot中来发送邮件是很方便的事情,只需要添加对应的依赖jar,然后配置邮箱服务器地址和账号就可以实现邮件的发送。本示例使用JDK1.8, Spring Boot 1.5.9.RELEASE来演示邮件的发送。

1.创建项目

可以通过 http://start.spring.io/ 来快速创建项目,选择mail模块。或者手动创建,并添加对应的依赖。
所需的mail jar:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

2.配置信息

本测试实例以阿里的邮箱来演示,不同邮箱服务器的host需要修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
mail:
properties:
mail:
smtp:
connectiontimeout: 5000
timeout: 3000
writetimeout: 5000
auth: true
starttls:
enable: true
efault-encoding: UTF-8 #设置编码 防止乱码
protocol: smtp
host: smtp.mxhichina.com
port: 25
username: #邮箱帐号
password: #邮箱密码
messages:
encoding: UTF-8
basename: com/devnp/message/MailMessage

3.发送一般邮件

发送邮件使用 org.springframework.mail.javamail.JavaMailSender 来完成, 首先注入JavaMailSender,完整代码 com.devnp.springbootemaildemo.email.SimpleMailSend.java

1
2
3
4
5
6
7
8
@Autowired
private JavaMailSender mailSender;

@Value("${spring.mail.username}")
private String sender; //发送地址

@Autowired
private ResourceLoader resourceLoader;

发送给单一的用户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 发送给单一的用户
* @param toMail
* @param content
*/
public void simpleSend(String toMail, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();

message.setTo(toMail);
message.setSubject(subject);
message.setText(content);
message.setFrom(sender); //确保发送邮件地址与认证地址,如果不一致, 一些邮箱服务器会退信

this.mailSender.send(message);
}

发送 给多个地址,并且抄送多人,同时隐身抄送给多个人:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 发送 给多个地址,并且抄送多人,同时隐身抄送给多个人
* @param toMails 收件人地址
* @param ccMails 抄送人地址
* @param bccMails 隐形抄送地址 不会出现在地址栏
* @param subject 标题
* @param content 内容
*/
public void simpleSend(String [] toMails, String [] ccMails, String [] bccMails, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();

message.setTo(toMails);
message.setCc(ccMails);
message.setBcc(bccMails);
message.setSubject(subject);
message.setText(content);
message.setFrom(sender); //确保发送邮件地址与认证地址,如果不一致, 一些邮箱服务器会退信

this.mailSender.send(message);
}
使用 MimeMessagePreparator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 使用 MimeMessagePreparator 回掉接口來发送html 同时 也可以使用 MimeMessageHelper
* @param toMail
* @param subject
* @param content html
*/
public void sendWithHtml(String toMail, String subject, String content) {

MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(toMail));
mimeMessage.setSubject(subject);
mimeMessage.setFrom(new InternetAddress(sender));
mimeMessage.setText(content, StandardCharsets.UTF_8.name(), "html");
}
};

this.mailSender.send(preparator);
}

4.发送带有附件的邮件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 发送带有附件的邮件
* @param toMail
* @param subject
* @param content
* @param files
* @throws MessagingException
*/
public void sendWithAttachemnt(String toMail, String subject, String content, List<String> files) throws MessagingException{
MimeMessage message = mailSender.createMimeMessage();

MimeMessageHelper helper = new MimeMessageHelper(message, true);

helper.setTo(toMail);
helper.setSubject(subject);
helper.setText(content); //支持发送html setText(String text, boolean html)
helper.setFrom(sender);

for (int i = 0; i < files.size(); i++) {

Resource resource = resourceLoader.getResource(files.get(i));

helper.addAttachment(resource.getFilename() , resource);
}

this.mailSender.send(message);
}

5.发送模板邮件

使用模板来发送邮件,和普通邮件的不同之处在于需要设计模板,然后使用模板引擎对模板进行渲染,渲染的之后的数据在发送,以thymeleaf为例:
首先添加对应的依赖jar:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在Spring Boot 1.5.9.RELEASE的版本中,默认引入的thymeleaf的版本为2.1.6.RELEASE,为了适应text形式的模板,所以需要将thymeleaf提高到3.X,所以在properties中增加如下:

1
2
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>

1.模板配置

Spring Boot 默认有配置模板引擎和解析器,这里为了不冲突默认的,单独来配置模板引擎和解析器, 完整配置代码 com.devnp.springbootemaildemo.email.config.SpringMailConfig

HTML 模板引擎和解析器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Bean
public TemplateEngine htmlEmailTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
// Resolver for TEXT emails
//templateEngine.addTemplateResolver(textTemplateResolver());
// Resolver for HTML emails (except the editable one)
templateEngine.addTemplateResolver(htmlTemplateResolver());
// Resolver for HTML editable emails (which will be treated as a String)
//templateEngine.addTemplateResolver(stringTemplateResolver());
// Message source, internationalization specific to emails
//templateEngine.setTemplateEngineMessageSource(emailMessageSource());

return templateEngine;
}

/**
* html 模板解析器
* @return
*/
private ITemplateResolver htmlTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
//templateResolver.setOrder(Integer.valueOf(2));
//templateResolver.setResolvablePatterns(Collections.singleton("html/*"));
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
templateResolver.setCacheable(false);
return templateResolver;
}

TEXT 模板引擎和解析器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Bean
public TemplateEngine textEmailTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
// Resolver for TEXT emails
templateEngine.addTemplateResolver(textTemplateResolver());
// Resolver for HTML emails (except the editable one)
//templateEngine.addTemplateResolver(htmlTemplateResolver());
// Resolver for HTML editable emails (which will be treated as a String)
// templateEngine.addTemplateResolver(stringTemplateResolver());
// Message source, internationalization specific to emails
//templateEngine.setTemplateEngineMessageSource(emailMessageSource());

return templateEngine;
}

/**
* TEXT 模板解析器
* @return
*/
private ITemplateResolver textTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
//templateResolver.setOrder(Integer.valueOf(1)); //优先级
//templateResolver.setResolvablePatterns(Collections.singleton("text/*")); //文件类型
templateResolver.setPrefix("/templates/"); //模板文件开始
templateResolver.setSuffix(".txt"); //模板文件结尾
templateResolver.setTemplateMode(TemplateMode.TEXT); //模板模型
templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name()); //编码
templateResolver.setCacheable(false); //缓存
return templateResolver;
}

2.html模板

templates\mail\html\mail-hello.html

[code lang=”html”]

http://www.denvp.com
,
<div>
    <p th:text="#{msg.content}"></p>
</div>

<div>
    <p th:text="#{msg.thank}"></p>
    <em><a href="http://www.denvp.com">www.denvp.com</a></em>
</div>
1
2
3
4
5
6
7
8

设置资源文件,用于对静态信息的展示, 同时也可以对多语言的支持,关于<a href="http://www.devnp.com/2018/04/03/spring-boot-%e5%9b%bd%e9%99%85%e5%8c%96-spring-boot-internationalization-demo/" rel="noopener" target="_blank">Spring Boot 国际化</a> :
<em>com\devnp\message\MailMessage_zh_CN.properties</em>

```text
msg.hello = 你好
msg.thank = 感谢
msg.content = 这是一封测试来自模板的邮件

3.text模板

templates\mail\text\mail-hello.txt

1
2
3
4
5
6
7
8
9
10
11
12
[(#{msg.hello})] [( ${name} )],

[# th:if="${name.length() gt 10}"] 你的名字太长啦 [/]

[( ${#dates.format(subscriptionDate)} )]

你的爱好:
[# th:each="hobby : ${hobbies}"]
- [( ${hobby} )]
[/]

[(#{msg.content})]

4.发送邮件

com.devnp.springbootemaildemo.email.TemplateMailSend.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
*
*/
package com.devnp.springbootemaildemo.email;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

/**
* @author duliu
*
*/
@Component
public class TemplateMailSend {

public Logger log = LoggerFactory.getLogger(getClass());

@Autowired
private TemplateEngine textEmailTemplateEngine;

@Autowired
private TemplateEngine htmlEmailTemplateEngine;

@Autowired
private JavaMailSender mailSender;

@Value("${spring.mail.username}")
private String sender;

@Autowired
private ResourceLoader resourceLoader;

/**
* 使用Html模板来生产发送消息
* @param toMail
* @param subject
* @param file
* @throws MessagingException
*/
public void sendWithThymeleafHtmlTemplate(String toMail, String subject, String file, String recipientName, String imageResourceName) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();

MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());

helper.setTo(toMail);
helper.setSubject(subject);
helper.setFrom(sender);

//设置方言环境
final Context ctx = new Context(Locale.SIMPLIFIED_CHINESE);

ctx.setVariable("name", recipientName);
ctx.setVariable("imageResourceName", imageResourceName);

String htmlContent = this.htmlEmailTemplateEngine.process(file, ctx);

Resource resource = resourceLoader.getResource("classpath:static/logo.png");

helper.setText(htmlContent, true);

helper.addInline(imageResourceName, resource);

log.info(htmlContent);

this.mailSender.send(message);
}

/**
* 使用Text模板来生产发送消息
* @param toMail
* @param subject
* @param file
* @param recipientName
* @throws MessagingException
*/
public void sendWithThymeleafTextTemplate(String toMail, String subject, String file, String recipientName) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();

MimeMessageHelper helper = new MimeMessageHelper(message, true, StandardCharsets.UTF_8.name());

helper.setTo(toMail);
helper.setSubject(subject);
helper.setFrom(sender);

//设置方言环境
final Context ctx = new Context(Locale.SIMPLIFIED_CHINESE);

ctx.setVariable("name", recipientName);
ctx.setVariable("subscriptionDate", new Date());
ctx.setVariable("hobbies", Arrays.asList("吃", "吃", "吃"));

String txtContent = this.textEmailTemplateEngine.process(file, ctx);

helper.setText(txtContent);

log.info(txtContent);

this.mailSender.send(message);
}
}

5.测试

编写相应的单元测试代码,为了不显示过多的代码篇幅:

com.devnp.springbootemaildemo.email.SimpleMailSendTests.java
com.devnp.springbootemaildemo.email.TemplateMailSendTests.java

6.参考

https://docs.spring.io/spring/docs/4.3.16.RELEASE/spring-framework-reference/htmlsingle/#mail
https://www.thymeleaf.org/doc/articles/springmail.html

7.代码下载

spring-boot-email-demo.zip