springboot多线程异步发送email,html模板渲染

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模板渲染

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
引用\[1\]:在Spring Boot中实现多线程异步可以通过使用注解来实现。首先,在启动类上加上注解@EnableAsync,这样就开启了异步功能。然后,在想要异步执行的方法上加上注解@Async,表示该方法是异步的。最后,在主函数中调用该方法即可实现异步执行。Spring Boot真的很方便,只需要这两个注解就可以完成异步操作。\[1\] 引用\[2\]:另外,可以通过设置corePoolSize来控制线程池的大小,从而实现更好的线程管理。例如,将corePoolSize设置为10,重启Spring Boot后,可以使用Jmeter同时调用接口多次,观察控制台日志可以看到多个线程同时执行,这样可以提高程序的运行效率。\[2\] 总结起来,Spring Boot实现多线程异步的步骤如下: 1. 在启动类上加上注解@EnableAsync,开启异步功能。 2. 在想要异步执行的方法上加上注解@Async,表示该方法是异步的。 3. 在主函数中调用该方法即可实现异步执行。 4. 可以通过设置corePoolSize来控制线程池的大小,以优化线程管理。\[1\]\[2\] #### 引用[.reference_title] - *1* [springboot实现线程异步](https://blog.csdn.net/qq_38403590/article/details/119729294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Springboot异步多线程编程](https://blog.csdn.net/baidu_28340727/article/details/122310314)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值