1.在pom.xml中导入相关依赖
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 邮件 spring-boot-starter-mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
2.配置application.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spring
mail:
port: 465
host: smtp.exmail.qq.com
# 这里使用的是腾讯企业邮箱,使用其他邮箱port与host配置可能不同,密码有的还可以是授权码
username: xxxxx@xxxx.com
password: xxxxxx
default-encoding: UTF-8
# 自定义配置,邮件发送人,昵称
nickname: XX系统
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
socketFactory:
port: 465
class: com.bhy702.utils.email.MailSSLSocketFactory
fallback: false

发布服务器时注意开放465端口号

3.封装参数实体:

EmailProperties:

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
/**
* @author: brbai
* @create: 2020-11-03 10:42:50
* @description:
*/
@Data
public class EmailProperties {

//收件邮箱地址数组
private String[] emailArrays;

//抄送邮箱地址数组
private String[] ccArrays;

//邮件主题
private String subject;

//模板路径
private String template;

//模板填充参数
private Map<String,Object> params;

// 附件
private File file;

// 附件名称
private String attachmentName;

public EmailProperties(){};

public EmailProperties(String[] emailArrays,String[] ccArrays,String subject,String template,Map<String,Object> params){
this.emailArrays = emailArrays;
this.ccArrays = ccArrays;
this.subject = subject;
this.template = template;
this.params = params;
}

public EmailProperties(String[] emailArrays,String subject,String template,Map<String,Object> params){
this.emailArrays = emailArrays;
this.subject = subject;
this.template = template;
this.params = params;
}

public EmailProperties(String[] emailArrays,String subject,String template,Map<String,Object> params,File file,String attachmentName){
this.emailArrays = emailArrays;
this.subject = subject;
this.template = template;
this.params = params;
this.file = file;
this.attachmentName = attachmentName;
}
}
4.EMailUtils :
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
@Component
public class EMailUtils {

@Autowired
private JavaMailSender javaMailSender;

@Autowired
private TemplateEngine templateEngine;

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

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

// 发送普通格式邮件
public void sendSimpleMail(String email, String subject, String content) {

SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(nickname + "<" + fromAddress + ">");
simpleMailMessage.setTo(email);
simpleMailMessage.setSubject(subject);
simpleMailMessage.setText(content);

javaMailSender.send(simpleMailMessage);
}

// 发送html格式邮件
public void sendHtmlMail(EmailProperties properties) {

MimeMessage message = javaMailSender.createMimeMessage();
try {
//true表示需要创建一个multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(fromAddress, nickname, "UTF-8"));
helper.setTo(properties.getEmailArrays());
helper.setSubject(properties.getSubject());

String[] ccArrays = properties.getCcArrays();
if (ccArrays != null && ccArrays.length > 0) {
helper.setCc(properties.getCcArrays());
}

Context ctx = new Context();
// 给模板的参数的上下文
ctx.setVariable("params", properties.getParams());
// 执行模板引擎,执行模板引擎传入模板名、上下文对象,Thymeleaf的默认配置期望所有HTML文件都放在 **resources/templates ** 目录下,以.html扩展名结尾。
String emailText = templateEngine.process(properties.getTemplate(), ctx);

helper.setText(emailText, true);

if (properties.getFile() != null && !ValidateKit.checkNull(properties.getAttachmentName())) {
helper.addAttachment(properties.getAttachmentName(), properties.getFile());
}
message.setHeader("X-Priority", "3");


message.setHeader("X-MSMail-Priority", "Normal");

//以outlook名义发送邮件,不会被当作垃圾邮件
message.setHeader("X-Mailer", "Microsoft Outlook Express 6.00.2900.5512");

message.setHeader("X-MimeOLE", "Produced By Microsoft MimeOLE V6.00.2900.5512");

message.setHeader("ReturnReceipt", "1");


javaMailSender.send(message);
} catch (Exception e) {
e.printStackTrace();
throw new BizException("邮件发送失败");
}
}

//多线程异步发送
@Async("taskExecutor")
public void sendHtmlMailForAyc(EmailProperties properties) {

MimeMessage message = javaMailSender.createMimeMessage();

try {
//true表示需要创建一个multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(fromAddress, nickname, "UTF-8"));
helper.setTo(properties.getEmailArrays());
helper.setSubject(properties.getSubject());

String[] ccArrays = properties.getCcArrays();
if (ccArrays != null && ccArrays.length > 0) {
helper.setCc(properties.getCcArrays());
}

Context ctx = new Context();
// 给模板的参数的上下文
ctx.setVariable("params", properties.getParams());
// 执行模板引擎,执行模板引擎传入模板名、上下文对象,Thymeleaf的默认配置期望所有HTML文件都放在 **resources/templates ** 目录下,以.html扩展名结尾。
String emailText = templateEngine.process(properties.getTemplate(), ctx);

helper.setText(emailText, true);
//
// // FileSystemResource logoImage= new FileSystemResource("D:\\image\\logo.jpg");
// //绝对路径
// FileSystemResource logoImage = new FileSystemResource(imgPath);
// //相对路径,项目的resources路径下
// //ClassPathResource logoImage = new ClassPathResource("static/image/logonew.png");
// // 添加附件,第一个参数表示添加到 Email 中附件的名称,第二个参数是图片资源
// //一般图片调用这个方法
// helper.addInline("logoImage", logoImage);
// //一般文件附件调用这个方法
// helper.addAttachment("logoImage", resource);

if (properties.getFile() != null && !ValidateKit.checkNull(properties.getAttachmentName())) {
helper.addAttachment(properties.getAttachmentName(), properties.getFile());
}
message.setHeader("X-Priority", "3");


message.setHeader("X-MSMail-Priority", "Normal");

//以outlook名义发送邮件,不会被当作垃圾邮件
message.setHeader("X-Mailer", "Microsoft Outlook Express 6.00.2900.5512");

message.setHeader("X-MimeOLE", "Produced By Microsoft MimeOLE V6.00.2900.5512");

message.setHeader("ReturnReceipt", "1");


javaMailSender.send(message);
} catch (Exception e) {
e.printStackTrace();
throw new BizException("邮件发送失败");
}

}

// 发送带附件的邮件
public void sendAttachmentsMail(JavaMailSender javaMailSender, String email, String subject, String content, String filePath) {
MimeMessage message = javaMailSender.createMimeMessage();

try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(fromAddress, nickname, "UTF-8"));
helper.setTo(email);
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);

javaMailSender.send(message);

} catch (Exception e) {
e.printStackTrace();
}
}

// 发送带静态资源的邮件
public void sendInlineResourceMail(JavaMailSender javaMailSender, String email, String subject, String content, String rscPath, String rscId) {
MimeMessage message = javaMailSender.createMimeMessage();

try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(fromAddress, nickname, "UTF-8"));
helper.setTo(email);
helper.setSubject(subject);
helper.setText(content, true);

FileSystemResource res = new FileSystemResource(new File(rscPath));
helper.addInline(rscId, res);
javaMailSender.send(message);
} catch (Exception e) {
e.printStackTrace();
}
}

}
5.定义异步任务执行线程池TaskPoolConfig
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
/**
* 定义异步任务执行线程池
*/
@Configuration
public class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor () {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数10:线程池创建时候初始化的线程数
executor.setCorePoolSize(3);
// 最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(5);
// 缓冲队列200:用来缓冲执行任务的队列
executor.setQueueCapacity(300);
// 允许线程的空闲时间60秒:当超过了核心线程数之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
// 线程池名的前缀:设置好了之后可以方便定位处理任务所在的线程池
executor.setThreadNamePrefix("taskExecutor-");
/*
线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
如果执行程序已关闭,则会丢弃该任务
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
executor.setWaitForTasksToCompleteOnShutdown(true);
// 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
executor.setAwaitTerminationSeconds(600);
return executor;
}
}
6.邮件ssl
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
public class MailSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory factory;

public MailSSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[] { new MailTrustManager() }, null);
factory = sslcontext.getSocketFactory();
} catch (Exception ex) {
// ignore
}
}

public static SocketFactory getDefault() {
return new MailSSLSocketFactory();
}

@Override
public Socket createSocket() throws IOException {
return factory.createSocket();
}

@Override
public Socket createSocket(Socket socket, String s, int i, boolean flag) throws IOException {
return factory.createSocket(socket, s, i, flag);
}

@Override
public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException {
return factory.createSocket(inaddr, i, inaddr1, j);
}

@Override
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
return factory.createSocket(inaddr, i);
}

@Override
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
return factory.createSocket(s, i, inaddr, j);
}

@Override
public Socket createSocket(String s, int i) throws IOException {
return factory.createSocket(s, i);
}

@Override
public String[] getDefaultCipherSuites() {
return factory.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return factory.getSupportedCipherSuites();
}
}
7.邮箱信证管理配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 邮箱信证管理
*/
public class MailTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] cert, String authType) {
// everything is trusted
}

public void checkServerTrusted(X509Certificate[] cert, String authType) {
// everything is trusted
}

public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

8.测试:
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
@RequestMapping(value = "/mail")
public void sendMail() {


List<Order> list = new ArrayList<>();
Map<String,Object> params = new HashMap<>();

EmailProperties properties = new EmailProperties();

String[] sendArr = {"xxxxxxxx@qq.com"};
String[] ccArr = { "xxxxxx@qq.com"};

Order Order1 = new Order();
Order1.setOrderCode("D00002");
Order1.setOrderLine("3");
Order1.setReleaseId("20200302-002");
list.add(Order1);


Order Order2 = new Order();
Order2.setOrderCode("D00002");
Order2.setOrderLine("1");
Order2.setReleaseId("20200302-003");
list.add(Order2);

Order Order3 = new Order();
Order3.setOrderCode("D00002");
Order3.setOrderLine("2");
Order3.setReleaseId("20200302-002");
list.add(Order3);

Order Order4 = new Order();
Order4.setOrderCode("D00003");
Order4.setOrderLine("2");
Order4.setReleaseId("20200402-001");
list.add(Order4);

Order Order5 = new Order();
Order5.setOrderCode("D00001");
Order5.setOrderLine("3");
Order5.setReleaseId("20200612-005");
list.add(Order5);

Comparator<Order> bya = Comparator.comparing(Order::getOrderCode);//按照订单号排序
Comparator<Order> byb = Comparator.comparing(Order::getOrderLine);//按照行号排序
Collections.sort(list,bya.thenComparing(byb));

params.put("list", list);

params.put("companyName", "xx股份有限公司");

properties.setEmailArrays(sendArr);
properties.setCcArrays(ccArr);

properties.setSubject("【系统通知】:您有新的订单计划信息,请及时处理!");
properties.setTemplate("EmailTemplate.html");

properties.setParams(params);
try {
eMailUtils.sendHtmlMailForAyc(properties);
}catch (Exception e){
log.error("邮件发送失败");
}

}
效果图:

在这里插入图片描述
以上html邮件模板分享,可参考博客:Java发送邮件,优美html邮件模板分享