1.在pom.xml中导入相关依赖
<!-- 邮件 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
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:
/**
* @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 :
@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
/**
* 定义异步任务执行线程池
*/
@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
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.邮箱信证管理配置
/**
* 邮箱信证管理
*/
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];
}
}
测试:
@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邮件模板分享
欢迎访问本文的个人博客链接: https://br-bai.github.io/2020/12/03/SpringBoot多线程异步发送Email,HTML模板渲染