项目场景:

项目场景:
通过定时任务调用解析邮件,获取附件,上传到文件服务器(协助客户上传文件),将邮件移动到相应的文件夹。以下是简单的邮件操作逻辑


本地demo代码贴贴:

由于业务场景需要,这里使用的是IMAP协议,java mail 版本是1.6.2,使用腾讯企业邮箱

package com.didadiandi.email;import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPStore;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;/*** TODO** @author wj* @date 2021/9/18 10:56**/
public class EmailTest {public static void main(String[] args) throws Exception {try (IMAPStore store = connectStore()) {Map<String, IMAPFolder> folderMap = folderMap(store);try (IMAPFolder newComingFolder = folderMap.get("NEW COMING");IMAPFolder autoUploadedFolder = folderMap.get("AUTO UPLOADED");IMAPFolder pendingCheckFolder = folderMap.get("PENDING CHECK");IMAPFolder notMatchedFolder = folderMap.get("NOT MATCHED");) {Message[] messages = newComingFolder.getMessages();Map<String, MimeMessage> mimeMessageMap = new HashMap<>();for (Message message : messages) {MimeMessage mimeMessage = (MimeMessage) message;if (mimeMessage == null) {continue;}String messageId = mimeMessage.getMessageID();mimeMessageMap.put(messageId, mimeMessage);}System.out.println(mimeMessageMap.size());for (Map.Entry<String, MimeMessage> mimeMessageEntry : mimeMessageMap.entrySet()) {MimeMessage message = mimeMessageEntry.getValue();System.out.println("\n");System.out.println(" subject:" + message.getSubject());if (!isContainAttachment(message)) {continue;}saveAttachment(message);moveMessage(newComingFolder, autoUploadedFolder, message);}} catch (Exception e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}}/*** 设置配置,且连接邮箱** @return com.sun.mail.imap.IMAPStore* @author wj* @date 15:16 2022/1/6*/public static IMAPStore connectStore() throws MessagingException {Properties props = new Properties();// 协议props.put("mail.store.protocol", "imap");// 要连接的imap服务器props.put("mail.imap.host", "imap.exmail.qq.com");// 端口props.put("mail.imap.port", "993");// 是否使用ssl连接并使用ssl端口(imap协议默认为false)props.put("mail.imap.ssl.enable", true);// 设置超时时间(默认无超时时间)props.put("mail.imap.timeout", "30000");// 连接超时时间(默认无超时时间)props.put("mail.imap.connectiontimeout", "30000");// 缓存消息的最大大小props.put("mail.imap.appendbuffersize", "6291456");// 是否开启分段加载功能(默认为true),附件大于100K需要加这个配置,能加快读取附件的时间props.put("mail.imap.partialfetch", "false");Session session = Session.getInstance(props, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication("userName", "PASSWORD");}});Store store = session.getStore();store.connect();return (IMAPStore) store;}/*** 获取邮箱** @return java.util.Map<java.lang.String,com.sun.mail.imap.IMAPFolder>* @author wj* @date 15:17 2022/1/6*/public static Map<String, IMAPFolder> folderMap(IMAPStore store) throws MessagingException {Map<String, IMAPFolder> folderMap = new HashMap<>();// 带附件的邮箱文件夹IMAPFolder attachmentFolder = (IMAPFolder) openFolder(store, "NEW COMING", false);folderMap.put("NEW COMING", attachmentFolder);// 未匹配文件夹IMAPFolder unmatchedFolder = (IMAPFolder) openFolder(store, "NOT MATCHED", false);folderMap.put("NOT MATCHED", unmatchedFolder);// 上传失败文件夹IMAPFolder uploadFailedFolder = (IMAPFolder) openFolder(store, "PENDING CHECK", false);folderMap.put("PENDING CHECK", uploadFailedFolder);// 上传成功文件夹IMAPFolder uploadSuccessFolder = (IMAPFolder) openFolder(store, "AUTO UPLOADED", false);folderMap.put("AUTO UPLOADED", uploadSuccessFolder);return folderMap;}/*** 判断是否存在附件** @return boolean* @author wj* @date 15:17 2022/1/6*/public static boolean isContainAttachment(Part part) throws MessagingException, IOException, InterruptedException {// 是否包含multipart内容if (part.isMimeType("multipart/*")) {// 转换content为MimeMultipart对象MimeMultipart multipart = (MimeMultipart) part.getContent();// 获取bodyPart的数量int partCount = multipart.getCount();for (int i = 0; i < partCount; i++) {BodyPart bodyPart = multipart.getBodyPart(i);// 返回bodyPart的配置String disp = bodyPart.getDisposition();// 是否包含附件if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) {return true;}}}return false;}/*** 保存附件** @param part 邮件中多个组合体中的其中一个组合体* @throws UnsupportedEncodingException* @throws MessagingException* @throws IOException*/private static void saveAttachment(Part part) throws UnsupportedEncodingException, MessagingException,IOException {System.out.println(" hashCode :" + part.hashCode());if (part.isMimeType("multipart/*")) {Multipart multipart = (Multipart) part.getContent();int partCount = multipart.getCount();for (int i = 0; i < partCount; i++) {BodyPart bodyPart = multipart.getBodyPart(i);String disp = bodyPart.getDisposition();if (disp != null) {String fileName = decodeText(bodyPart.getFileName());System.out.println(" fileName :" + fileName);// 通过getInputStream方法下载附件// bodyPart.getInputStream();}}}}/*** 获取邮箱** @return javax.mail.Folder* @author wj* @date 15:19 2022/1/6*/public static Folder openFolder(Store store, String folderName, boolean isDefaultFolder) throws MessagingException {Folder folder;try {// 获取收件箱文件夹if (isDefaultFolder) {folder = store.getFolder(folderName);} else {// 自定义邮箱文件夹Folder[] folders = store.getDefaultFolder().list();folder = findFolderByName(folders, folderName);}folder.open(Folder.READ_WRITE);return folder;} catch (MessagingException e) {store.close();e.printStackTrace();}return null;}/*** 寻找邮箱文件夹** @return javax.mail.Folder* @author wj* @date 15:00 2021/9/15*/public static Folder findFolderByName(Folder[] sourceFolder, String folderName) throws MessagingException {for (Folder folder : sourceFolder) {if (folder.getName().equals(folderName)) {return folder;} else if (folder.list().length > 0) {return findFolderByName(folder.list(), folderName);}}return null;}/*** 解析文件名称** @return java.lang.String* @author wj* @date 15:20 2022/1/6*/private static String decodeText(String encodeText) throws UnsupportedEncodingException {if (encodeText == null || "".equals(encodeText)) {return "";} else {return MimeUtility.decodeText(encodeText).replaceAll("/", "_");}}/*** 移动邮件** @return void* @author wj* @date 15:21 2022/1/6*/public static void moveMessage(IMAPFolder sourceFolder, IMAPFolder targetFolder, Message messages) throws MessagingException {if (messages == null) {return;}try {sourceFolder.moveMessages(new Message[]{messages}, targetFolder);} catch (Exception e) {throw e;}}}

问题描述:

遇到的问题:附件获取重复(测试的邮件附件名称都不一样)

// BUG原因是,for循环中调用该方法 moveMessage(newComingFolder, autoUploadedFolder, message);/*** 移动邮件** @return void* @author wj* @date 15:21 2022/1/6*/public static void moveMessage(IMAPFolder sourceFolder, IMAPFolder targetFolder, Message messages) throws MessagingException {if (messages == null) {return;}try {sourceFolder.moveMessages(new Message[]{messages}, targetFolder);} catch (Exception e) {throw e;}}

原因分析:

有两个可能:第一个可能是java mail 本身存在问题;第二个可能是腾讯企业邮箱存在问题,不支持这样操作


解决方案:

将其批量走完业务之后,再一次性调用移动邮件方法。代码如下:

    public static void main(String[] args) throws Exception {try (IMAPStore store = connectStore()) {Map<String, IMAPFolder> folderMap = folderMap(store);try (IMAPFolder newComingFolder = folderMap.get("NEW COMING");IMAPFolder autoUploadedFolder = folderMap.get("AUTO UPLOADED");IMAPFolder pendingCheckFolder = folderMap.get("PENDING CHECK");IMAPFolder notMatchedFolder = folderMap.get("NOT MATCHED");) {Message[] messages = newComingFolder.getMessages();Map<String, MimeMessage> mimeMessageMap = new HashMap<>();for (Message message : messages) {MimeMessage mimeMessage = (MimeMessage) message;if (mimeMessage == null) {continue;}String messageId = mimeMessage.getMessageID();mimeMessageMap.put(messageId, mimeMessage);}// 新增邮件处理后保存的集合List<MimeMessage> autoUploadedMessageList = Lists.newArrayList();System.out.println(mimeMessageMap.size());for (Map.Entry<String, MimeMessage> mimeMessageEntry : mimeMessageMap.entrySet()) {MimeMessage message = mimeMessageEntry.getValue();System.out.println("\n");System.out.println(" subject:" + message.getSubject());if (!isContainAttachment(message)) {continue;}saveAttachment(message);// 根据业务需求,加入集合中autoUploadedMessageList.add(message);}// 这批邮件都执行完毕之后,再移动邮件moveMessage(newComingFolder, autoUploadedFolder, autoUploadedMessageList);} catch (Exception e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}}/*** 移动邮件(调整过后)** @return void* @author wj* @date 15:21 2022/1/6*/public static void moveMessage(IMAPFolder sourceFolder, IMAPFolder targetFolder, List<MimeMessage> messages) throws MessagingException {if (messages == null) {return;}try {sourceFolder.moveMessages(messages.toArray(new Message[0]), targetFolder);} catch (Exception e) {throw e;}}// 也可以这样调整,但是经过评估还是使用的上面那个方法。这个方法可以在循环中调用(处理完一封邮件就"移动一封")public static void moveMessage(IMAPFolder sourceFolder, IMAPFolder targetFolder,MimeMessage messages) throws MessagingException {if (messages == null) {return;}try {sourceFolder.copyMessages(new Message[]{messages}, targetFolder);messages.setFlag(Flags.Flag.DELETED, true);} catch (Exception e) {throw e;}}

java mail 踩坑 >>> 批量读取附件,附件重复相关推荐

  1. 【Java笔记+踩坑】SpringBoot基础3——开发。热部署+配置高级+整合NoSQL/缓存/任务/邮件/监控

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  2. 【Java笔记+踩坑】SpringBoot基础2——运维实用

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  3. 【Java笔记+踩坑】SpringBoot——基础

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  4. 在 Java 中,如何批量读取本项目资源目录下的所有文件

    在 Java 中,如何批量读取本项目资源目录下的所有文件 读取资源目录下的指定文件 方法 1:使用 JDK 中原始 API 方法 2:借助 Spring 附录 将 InputStream 转化为 by ...

  5. 西安交通大学915考研--编程题Java代码踩坑(2020年真题)

    西安交通大学915考研–编程题Java代码踩坑(2020年真题) 目录 西安交通大学915考研--编程题Java代码踩坑(2020年真题) 2020.1--寻找方程组的解 2020.2--几组数中筛选 ...

  6. Java Mail多人群发与多附件发送

    最近公司的项目用到了Java Mail来发送注册邮件,不过,开发的时候都是使用封装好的JAR,以前也不是很了解Java Mail的使用原理.网上很多代码都是只有一部分,看一看也跑不起来,今天正好有时间 ...

  7. 【黑马Java笔记+踩坑】Maven高级

    用于复习快速回顾. Maven基础: JavaWeb基础3--Maven&MyBatis_vincewm的博客-CSDN博客 目录 0,解除端口调用 1,分模块开发 1.1 分模块开发设计 1 ...

  8. 【黑马Java笔记+踩坑】MyBatisPlus基础

    用于复习快速回顾. 目录 1,MyBatisPlus简介 1.1 回顾SpringBoot整合Mybatis 1.2 快速入门,实体类注解总结 1.3 MybatisPlus特性 2,标准数据层开发 ...

  9. java foreach 原理_一不小心就让Java开发者踩坑的failfast是个什么鬼?

    1 什么是fail-fast 首先我们看下维基百科中关于fail-fast的解释: 在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统.快速失效系统通常设计用于停止正常操作,而不是 ...

  10. 一不小心就让Java开发者踩坑的fail-fast是个什么鬼?

    我在<为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作>一文中曾经介绍过Java中的fail-fast机制,但是并没有深入介绍,本文,就来深入介绍一下fa ...

最新文章

  1. php数组保存txt,php将数组存储为文本文件方法汇总,_PHP教程
  2. n分频器 verilog_基于Verilog的分频器实现
  3. 【数据结构与算法】之给Nx3网格图涂色的方案数的求解算法
  4. 易助工资总额管控上市说明
  5. matlab 功率谱分析函数psd用法
  6. python实验三答案_20192116 实验三《Python程序设计》实验报告
  7. 微信JS-SDK开发 入门指南
  8. 字节跳动第三轮技术面,Java篇
  9. java 线程栈大小配置,JVM运行时数据区详解-Stack栈(优化配置、代码样例)
  10. 计算机专业简述,简述计算机专业毕业论文完整版.doc
  11. 工程项目进度表excel模板_救命,每天都要做工作报告!Excel一键生成精美报告的技巧,必学!...
  12. echarts源码打包_Echarts模块v1.5更新【更新支持多线程,封装大量快速方法,增加史上最详细示例】...
  13. 百度网盘破解版Pandownload开发者被抓
  14. [工具:iperf吞吐率测试工具 ]安装以及使用
  15. 内置式永磁同步电机IPMSM,基于虚拟信号注入法最大转矩电流比MTPA控制仿真模型
  16. dnf服务器的ini配置文件,dnf分辨率配置文件在哪 | 手游网游页游攻略大全
  17. 在线作诗,做诗机,一键生成藏头诗,藏头诗在线制作,藏头诗生成器, 姓名藏头诗,姓名作诗
  18. 谈谈我对Ui设计师的一些观点
  19. 未来科技蒲公英大飞_大烟草的下跌告诉我们关于大科技的未来
  20. bitset简单用法

热门文章

  1. 计算机系统盘没用的东西怎么删除,怎样清理电脑c盘无用的东西
  2. shopee虾皮面试题汇总-C++后端
  3. Excel VBA操作网页 显示滚动进度条
  4. Unrecognized Windows Sockets error: 10106: Socket creation failed
  5. java.net.SocketException: Unrecognized Windows Sockets error: 10106: create
  6. 罗森伯格成功布线五星蕴海建国饭店
  7. flashfxp配置文件服务器同步,如何导出FlashFXP的站点配置文件
  8. mysql建立数据透视表_SQL复习笔记 —— 数据透视表的妙用
  9. 深度解析dubbo在线运维Qos
  10. nodeJS版本升级