线程池异步发送邮件之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

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

Spring MVC 图片上传

引入需要的包 <dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-

Prompt - 将图片的表格转换成Markdown

Prompt - 将图片的表格转换成Markdown 0. 引言1. 提示词2. 原始版本 0. 引言 最近尝试将图片中的表格转换成Markdown格式,需要不断条件和优化提示词。记录一下调整好的提示词,以后在继续优化迭代。 1. 提示词 英文版本: You are an AI assistant tasked with extracting the content of

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

线程的四种操作

所属专栏:Java学习        1. 线程的开启 start和run的区别: run:描述了线程要执行的任务,也可以称为线程的入口 start:调用系统函数,真正的在系统内核中创建线程(创建PCB,加入到链表中),此处的start会根据不同的系统,分别调用不同的api,创建好之后的线程,再单独去执行run(所以说,start的本质是调用系统api,系统的api