# EmailTemplate **Repository Path**: wrencai/email-template.html ## Basic Information - **Project Name**: EmailTemplate - **Description**: html邮件模板分享 - **Primary Language**: HTML/CSS - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2021-08-19 - **Last Updated**: 2021-08-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README CSDN博客: [springboot多线程异步发送email,html模板渲染](http://https://blog.csdn.net/LittleBlackyoyoyo/article/details/101277268) 基于spring boot,html邮件模板对应的html邮件发送代码可参考以下: ###### 1.在pom.xml中导入相关依赖 ```xml org.springframework.boot spring-boot-starter-mail 2.2.6.RELEASE org.springframework.boot spring-boot-starter-thymeleaf 2.1.9.RELEASE ``` ###### 2.配置application.properties ```yml 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: ```java /** * @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 params; // 附件 private File file; // 附件名称 private String attachmentName; public EmailProperties(){}; public EmailProperties(String[] emailArrays,String[] ccArrays,String subject,String template,Map 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 params){ this.emailArrays = emailArrays; this.subject = subject; this.template = template; this.params = params; } public EmailProperties(String[] emailArrays,String subject,String template,Map 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 : ```java @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 ```java /** * 定义异步任务执行线程池 */ @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 ```java 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.邮箱信证管理配置 ```java /** * 邮箱信证管理 */ 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]; } } ``` *** ###### 测试: ```java @RequestMapping(value = "/mail") public void sendMail() { List list = new ArrayList<>(); Map 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 bya = Comparator.comparing(Order::getOrderCode);//按照订单号排序 Comparator 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("邮件发送失败"); } } ``` ###### 效果图: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201203095903688.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0xpdHRsZUJsYWNreW95b3lv,size_16,color_FFFFFF,t_70) 以上html邮件模板分享,可参考博客:[Java发送邮件,优美html邮件模板分享](https://blog.csdn.net/LittleBlackyoyoyo/article/details/101277268)