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

相关文章

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

使用Python的requests库来发送HTTP请求的操作指南

《使用Python的requests库来发送HTTP请求的操作指南》使用Python的requests库发送HTTP请求是非常简单和直观的,requests库提供了丰富的API,可以发送各种类型的HT... 目录前言1. 安装 requests 库2. 发送 GET 请求3. 发送 POST 请求4. 发送

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Python批量替换多个Word文档的多个关键字的方法

《Python批量替换多个Word文档的多个关键字的方法》有时,我们手头上有多个Excel或者Word文件,但是领导突然要求对某几个术语进行批量的修改,你是不是有要崩溃的感觉,所以本文给大家介绍了Py... 目录工具准备先梳理一下思路神奇代码来啦!代码详解激动人心的测试结语嘿,各位小伙伴们,大家好!有没有想

基于Python编写自动化邮件发送程序(进阶版)

《基于Python编写自动化邮件发送程序(进阶版)》在数字化时代,自动化邮件发送功能已成为企业和个人提升工作效率的重要工具,本文将使用Python编写一个简单的自动化邮件发送程序,希望对大家有所帮助... 目录理解SMTP协议基础配置开发环境构建邮件发送函数核心逻辑实现完整发送流程添加附件支持功能实现htm