线程池异步发送邮件之MimeMessageHelper邮件发送支持自定义发送人/图片/附件/多个接收人/抄送人/暗送人

本文主要是介绍线程池异步发送邮件之MimeMessageHelper邮件发送支持自定义发送人/图片/附件/多个接收人/抄送人/暗送人,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    项目中要发送邮件,写个工具类,小项目,并发量不高,但是要求:

    1.发件人是163邮箱或qq邮箱

    2.支持多个接收人/抄送人/暗送人

    3.支持正文中放图片

    4.支持附件

    5.线程池异步处理

    6.发送异常时,调用开发员自定义的异常处理类

    使用原生的java的mail.jar的API开发,需要自己调用组装很多API,MimeMessageHelper帮助类进行简化了很多步骤,用起来挺不错的。由于项目使用了spring boot,所以在pom.xml中只需添加

         <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>

即可。

  因为邮件发送有时耗时较长,所以代码中使用了线程池异步发送。下面先贴代码,再说需要注意的事项。

 异常接口,当邮件发送失败,需要做额外处理时,开发员实现该接口。

package com.nanhe.building.util;import com.alibaba.fastjson.JSONObject;/*** 邮件发送异常处理* @author Jfei**/
public interface MailSendExceptionHandler {/*** 当邮件发送出现异常时,调用此方法* @param e  异常类* @param params  调用邮件工具类发送是传的参数,便于日志记录跟踪*/void doForException(Exception e,JSONObject params);
}

 工具类

package com.nanhe.building.util;import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;import com.alibaba.fastjson.JSONObject;/*** 邮件发送(注意发送人的邮箱必须设置开通POP3/SMTP/IMAP,否则无法发送)* @author Jfei**/
public class MailUtil {/*** 线程池,最多同时3个线程在运行,其他的排队等候*/private static ExecutorService executor = Executors.newFixedThreadPool(3);/***  发送邮件(注意发送人的邮箱必须设置开通POP3/SMTP/IMAP,否则无法发送)* @param sendUserAccount 发送人email账号(163或者qq邮箱) (必填)* @param sendUserPassword 发送人email的授权码(必填)* @param sendUserNickName 发送人的昵称* @param receiveUsers 接收人 (必填)* @param copyUsers  抄送人* @param darkUsers  暗送人* @param title 标题 (必填)* @param text 文本* @param bodyImgs 正文图片* @param attachDocs 附件* @param exceptionHandler 邮件发送异常时,调用处理类处理*/public static void sendMail(String sendUserAccount,String sendUserPassword,String sendUserNickName,String[] receiveUsers,String[] copyUsers,String[] darkUsers,String title,String text,File[] bodyImgs,File[] attachDocs,MailSendExceptionHandler exceptionHandler){MailThread mail = new MailThread(sendUserAccount, sendUserPassword, sendUserNickName, receiveUsers, copyUsers, darkUsers, title, text,  bodyImgs, attachDocs,exceptionHandler);executor.execute(mail);executor.shutdown();}private static  class MailThread extends Thread{private String sendUserAccount;private String sendUserPassword;private String sendUserNickName;private String[] receiveUsers;private String[] copyUsers;private String[] darkUsers;private String title;private String text;private File[] bodyImgs;private File[] attachDocs;private MailSendExceptionHandler exceptionHandler;private JSONObject params;//参数集合public MailThread(String sendUserAccount, String sendUserPassword,String sendUserNickName, String[] receiveUsers,String[] copyUsers, String[] darkUsers, String title,String text, File[] bodyImgs,File[] attachDocs,MailSendExceptionHandler exceptionHandler) {super();this.sendUserAccount = sendUserAccount;this.sendUserPassword = sendUserPassword;this.sendUserNickName = sendUserNickName;this.receiveUsers = receiveUsers;this.copyUsers = copyUsers;this.darkUsers = darkUsers;this.text = text;this.title = title;this.bodyImgs = bodyImgs;this.attachDocs = attachDocs;this.exceptionHandler = exceptionHandler;setParams();}private void setParams(){params = new JSONObject();params.put("sendUserAccount", sendUserAccount);params.put("sendUserPassword", sendUserPassword);params.put("sendUserNickName", sendUserNickName);params.put("receiveUsers", receiveUsers);params.put("copyUsers", copyUsers);params.put("darkUsers", darkUsers);params.put("title", title);params.put("text", text);if(bodyImgs != null && bodyImgs.length > 0){List<String> list = new ArrayList<String>();for(File f : bodyImgs){list.add(f.getName());}params.put("bodyImgs", list);}if(attachDocs != null && attachDocs.length > 0){List<String> list = new ArrayList<String>();for(File f : attachDocs){list.add(f.getName());}params.put("attachDocs", list);}}public void run(){long startTime = System.currentTimeMillis();try {//获取邮件发送实例JavaMailSenderImpl mailSender = getJavaMailSenderImpl(sendUserAccount, sendUserPassword);//创建邮件帮助类MimeMessage mimeMessage = mailSender.createMimeMessage();MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true,"UTF-8");//必须true//设置邮件内容setMailContent(messageHelper, title, text, bodyImgs, attachDocs);//设置发送人setSenderUser(messageHelper, sendUserAccount,sendUserNickName);//设置接收人setReceiveUsers(messageHelper, receiveUsers, copyUsers, darkUsers);//发送mailSender.send(mimeMessage);} catch (Exception e) {//邮件发送失败,可以将发送失败日志记录到数据库进行相关处理e.printStackTrace();if(this.exceptionHandler != null){this.exceptionHandler.doForException(e, params);}}long endTime = System.currentTimeMillis();String t = ((endTime-startTime)/(60*1000))+" 分 " + (((endTime -startTime)/1000.0)%60) + "秒";System.out.println("邮件发送耗时:" + t);}private  JavaMailSenderImpl  getJavaMailSenderImpl(String sendUserAccount,String sendUserPassword){//连接邮件服务器的参数配置Properties props = new Properties();//开启tlsprops.setProperty("mail.smtp.auth","true");props.setProperty("mail.smtp.ssl.enable", "true");//    props.setProperty("smtp.starttls.required", "true");JavaMailSenderImpl impl = new JavaMailSenderImpl();impl.setHost(sendUserAccount.endsWith("163.com") ? "smtp.163.com":"smtp.qq.com");impl.setUsername(sendUserAccount);impl.setPassword(sendUserPassword);impl.setPort(465);impl.setDefaultEncoding("UTF-8");impl.setProtocol("smtp");impl.setJavaMailProperties(props);return impl;}/*** 设置邮件内容* @param help* @param title* @param plainText* @param htmlText* @param bodyImgs* @param attachDocs* @throws MessagingException* @throws UnsupportedEncodingException */private void setMailContent(MimeMessageHelper help,String title,String text,File[] bodyImgs,File[] attachDocs) throws MessagingException, UnsupportedEncodingException {//设置标题help.setSubject(title);//设置文本内容StringBuffer s = new StringBuffer("<html><body>");s.append(text );if(bodyImgs != null){for(int i = 0;i<bodyImgs.length;i++){s.append("<img src='cid:pic"+i+"' />");}}s.append("</body></html>");help.setText(s.toString(), true);//展示在正文的图片if(bodyImgs != null && bodyImgs.length > 0){for(int i = 0;i<bodyImgs.length;i++){help.addInline("pic"+i, bodyImgs[i]);}}//添加附件if(attachDocs != null && attachDocs.length > 0){for(File file : attachDocs){//解决附件中文乱码help.addAttachment(MimeUtility.encodeWord(file.getName()), file);}}}/*** 设置接收人,抄送人,暗送人* @param help* @param receiveUsers 接收人* @param copyUsers  抄送人* @param darkUsers  暗送人* @throws MessagingException*/private void setReceiveUsers(MimeMessageHelper help,String[] receiveUsers,String[] copyUsers,String[] darkUsers) throws MessagingException{if(receiveUsers != null){help.setTo(receiveUsers);}if(copyUsers != null && copyUsers.length > 0){help.setCc(copyUsers);}if(darkUsers != null && darkUsers.length > 0){help.setBcc(darkUsers);}}/*** 设置发送人* @param help* @param senderAccount 邮箱账号* @param userName  昵称* @throws MessagingException* @throws UnsupportedEncodingException */private void setSenderUser(MimeMessageHelper help,String senderAccount,String userName) throws MessagingException, UnsupportedEncodingException{if(userName != null){help.setFrom(senderAccount,userName);}else{help.setFrom(senderAccount);}}}/*** 测试* @param args*/public static void main(String[] args) {
//		String sendUserAccount = "XXX@163.com";
//		String sendUserPassword = "XXXX";//授权码String sendUserAccount = "XXXX@qq.com";String sendUserPassword = "zhnbgndydwuxbjdg";String sendUserNickName = "XXXX";String[] receiveUsers =new String[]{ "XXXX@163.com"};String[] copyUsers = new String[]{"XXXX@qq.com"};String[] darkUsers = new String[]{"XXXX@qq.com"};String title = "诗酒人生";String text = "落魄江南载酒行,楚腰肠断掌中轻。十年一觉扬州梦,赢得青楼薄幸名。";File[] bodyImgs = new File[]{new File("e:/1.jpg"),new File("e:/2.jpg")};
//		File[] bodyImgs = new File[]{new File("e:/1.jpg")};
//		File[] bodyImgs = null;//文件名不要出现空格File[] attachDocs = new File[]{new File("e:/文档2.docx"),new File("e:/文档.docx")};
//		File[] attachDocs = null;sendMail(sendUserAccount, sendUserPassword, sendUserNickName, receiveUsers, copyUsers, darkUsers, title, text, bodyImgs, attachDocs,null);System.out.println("已异步发送。。。");}
}

注意事项:

1.发送人的邮箱必须开通了SMTP服务,并把授权码记下

163授权

如果忘记了,可以在“客户端授权密码”通过短信找回。

qq授权码

在“设置”“账户”中找,qq的授权码是自动生成的,最好记下来。

2.如果发送人是qq邮箱的,则没遇到什么问题,但是如果是163邮箱,则经常出现554 DT异常。网上找到的解决方案是:

 (1)把邮件也抄送一份给发件人自己(经测试,没用)

 (2)在163的“设置”->“发垃圾/黑白名单”设置里,白名单添加上“smtp.163.com”,以及自己服务器的公网IP(直接百度IP,就可以看到自己的公网IP是多少了)(经测试,不稳定,仍然会有554 DT)

 

 

这篇关于线程池异步发送邮件之MimeMessageHelper邮件发送支持自定义发送人/图片/附件/多个接收人/抄送人/暗送人的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/245839

相关文章

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

python实现svg图片转换为png和gif

《python实现svg图片转换为png和gif》这篇文章主要为大家详细介绍了python如何实现将svg图片格式转换为png和gif,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录python实现svg图片转换为png和gifpython实现图片格式之间的相互转换延展:基于Py

使用Python从PPT文档中提取图片和图片信息(如坐标、宽度和高度等)

《使用Python从PPT文档中提取图片和图片信息(如坐标、宽度和高度等)》PPT是一种高效的信息展示工具,广泛应用于教育、商务和设计等多个领域,PPT文档中常常包含丰富的图片内容,这些图片不仅提升了... 目录一、引言二、环境与工具三、python 提取PPT背景图片3.1 提取幻灯片背景图片3.2 提取

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用

Redis消息队列实现异步秒杀功能

《Redis消息队列实现异步秒杀功能》在高并发场景下,为了提高秒杀业务的性能,可将部分工作交给Redis处理,并通过异步方式执行,Redis提供了多种数据结构来实现消息队列,总结三种,本文详细介绍Re... 目录1 Redis消息队列1.1 List 结构1.2 Pub/Sub 模式1.3 Stream 结