基于JDK的Java提取目录未送达邮件附件.eml方案及代码修复
修复后的EML附件提取代码
原代码存在的问题
- 仅处理单个.eml文件,未遍历目标目录下所有.eml
- 循环中修改
saveDir变量,导致后续附件路径错误 extractEML方法逻辑偏离需求(提取PDF而非嵌套的.eml附件),且存在冗余参数和重复异常声明- 创建目录时使用
mkdir()无法生成多级目录,容易失败 - 未处理文件名重复的情况,可能导致文件覆盖
- 异常处理过于粗暴,直接抛出所有异常,不利于排查问题
修复后的代码
import jakarta.mail.*; import jakarta.mail.internet.MimeBodyPart; import jakarta.mail.internet.MimeMessage; import java.io.*; import java.util.Properties; public class EMLAttachmentExtractor { // 配置:源目录和目标目录,根据实际修改 private static final String SOURCE_DIR = "/Users/Documents/old"; private static final String DEST_DIR = "/Users/Documents/extracted_eml_attachments"; public static void main(String[] args) { // 初始化目标目录 File destFolder = new File(DEST_DIR); if (!destFolder.exists()) { if (destFolder.mkdirs()) { System.out.println("目标目录已创建:" + DEST_DIR); } else { System.err.println("无法创建目标目录:" + DEST_DIR); return; } } // 遍历源目录下所有.eml文件 File sourceFolder = new File(SOURCE_DIR); File[] emlFiles = sourceFolder.listFiles((dir, name) -> name.toLowerCase().endsWith(".eml")); if (emlFiles == null || emlFiles.length == 0) { System.err.println("源目录中未找到.eml文件"); return; } Properties props = new Properties(); Session mailSession = Session.getDefaultInstance(props, null); for (File emlFile : emlFiles) { System.out.println("正在处理文件:" + emlFile.getName()); try (InputStream is = new FileInputStream(emlFile)) { MimeMessage message = new MimeMessage(mailSession, is); processMessage(message, destFolder, emlFile.getName()); } catch (Exception e) { System.err.println("处理文件失败:" + emlFile.getName() + ",错误信息:" + e.getMessage()); } } System.out.println("所有文件处理完成"); } /** * 处理单个邮件消息,提取其中的.eml附件 */ private static void processMessage(MimeMessage message, File destFolder, String parentFileName) throws MessagingException, IOException { Object content = message.getContent(); if (content instanceof Multipart multipart) { int partCount = multipart.getCount(); for (int i = 0; i < partCount; i++) { BodyPart bodyPart = multipart.getBodyPart(i); String disposition = bodyPart.getDisposition(); // 处理附件 if (Part.ATTACHMENT.equalsIgnoreCase(disposition)) { String fileName = bodyPart.getFileName(); if (fileName != null && fileName.toLowerCase().endsWith(".eml")) { // 处理文件名重复:在文件名前添加原文件前缀 String safeFileName = parentFileName.replace(".eml", "_") + fileName; File destFile = new File(destFolder, safeFileName); // 避免文件覆盖 int counter = 1; while (destFile.exists()) { String baseName = safeFileName.substring(0, safeFileName.lastIndexOf(".")); safeFileName = baseName + "_" + counter + ".eml"; destFile = new File(destFolder, safeFileName); counter++; } // 保存附件 ((MimeBodyPart) bodyPart).saveFile(destFile); System.out.println("已提取附件:" + destFile.getAbsolutePath()); // 递归处理嵌套的.eml附件(如果有的话) processMessage(new MimeMessage(Session.getDefaultInstance(new Properties(), null), new FileInputStream(destFile)), destFolder, safeFileName); } } else if (bodyPart.getContent() instanceof Multipart) { // 处理内嵌的multipart(比如邮件正文里的附件) processMessage((MimeMessage) bodyPart.getContent(), destFolder, parentFileName); } } } } }
关键修复点说明
- 批量处理文件:使用
listFiles过滤器自动遍历源目录下所有.eml文件 - 路径管理优化:不再修改全局目录变量,每次生成独立的目标文件路径
- 核心逻辑修正:专注提取.eml附件,支持递归处理嵌套在附件里的.eml文件
- 目录创建优化:使用
mkdirs()创建多级目录,确保目录结构能正常生成 - 文件名冲突解决:通过添加原文件名前缀和递增计数器,避免重复文件被覆盖
- 异常处理优化:捕获单个文件的处理异常,单个文件失败不中断整个批量任务
- 资源自动管理:使用try-with-resources语法自动关闭输入流,避免资源泄漏
依赖说明
注意:jakarta.mail并非JDK自带类库,需要在项目中引入依赖。如果使用Maven,可添加以下依赖:
<dependency> <groupId>com.sun.mail</groupId> <artifactId>jakarta.mail</artifactId> <version>2.0.1</version> </dependency>
内容的提问来源于stack exchange,提问作者daringfireball
相关产品推荐
相关产品推荐

