上一篇
使用JavaMail API解析邮件内容,定位附件部分(如Multipart中的MIMEBodyPart),移除或过滤附件后重新构建邮件,可通过遍历邮件部件的Content-Disposition属性识别附件,创建不含附件的新邮件对象实现删除。
在Java中删除邮件附件需要操作邮件的MIME结构,通常使用JavaMail API实现,以下是详细步骤和完整代码示例,涵盖邮件解析、附件识别与删除逻辑:
核心原理
邮件附件在MIME协议中存储为MIME BodyPart,删除附件的本质是:
- 递归解析邮件的多层级MIME结构(
multipart/mixed、multipart/alternative等)。 - 识别附件部分(
Content-Disposition为attachment或指定文件名)。 - 重建不包含附件的邮件体。
完整代码实现
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.Properties;
public class EmailAttachmentRemover {
public static void main(String[] args) throws Exception {
// 1. 读取原始邮件文件(.eml格式)
File emlFile = new File("original_email.eml");
InputStream emlStream = new FileInputStream(emlFile);
Session session = Session.getDefaultInstance(new Properties());
Message message = new MimeMessage(session, emlStream);
// 2. 删除附件并生成新邮件
Message cleanedMessage = removeAttachments(message);
// 3. 保存处理后的邮件
cleanedMessage.writeTo(new FileOutputStream("cleaned_email.eml"));
System.out.println("附件删除完成!");
}
/**
* 递归删除邮件中的所有附件
*/
private static Message removeAttachments(Message originalMessage) throws Exception {
Object content = originalMessage.getContent();
// 情况1:邮件是单一文本(无附件)
if (content instanceof String) {
return originalMessage;
}
// 情况2:邮件是多部分结构(含附件)
if (content instanceof Multipart) {
Multipart originalMultipart = (Multipart) content;
MimeMultipart newMultipart = new MimeMultipart();
// 遍历所有邮件部分
for (int i = 0; i < originalMultipart.getCount(); i++) {
BodyPart bodyPart = originalMultipart.getBodyPart(i);
// 策略1:跳过附件(根据Content-Disposition)
if (isAttachment(bodyPart)) {
continue;
}
// 策略2:处理嵌套多部分(如内嵌邮件)
Object partContent = bodyPart.getContent();
if (partContent instanceof Multipart) {
BodyPart cleanedPart = new MimeBodyPart();
cleanedPart.setContent(removeAttachments(bodyPart).getContent());
newMultipart.addBodyPart(cleanedPart);
} else {
// 保留非附件部分
newMultipart.addBodyPart(bodyPart);
}
}
// 重建邮件
MimeMessage newMessage = new MimeMessage((MimeMessage) originalMessage);
newMessage.setContent(newMultipart);
return newMessage;
}
return originalMessage;
}
/**
* 判断是否为附件
*/
private static boolean isAttachment(BodyPart bodyPart) throws MessagingException {
String disposition = bodyPart.getDisposition();
String fileName = bodyPart.getFileName();
return (disposition != null && disposition.equalsIgnoreCase(Part.ATTACHMENT))
|| (fileName != null && !fileName.isEmpty());
}
}
关键步骤解析
-
邮件解析:

- 使用
MimeMessage加载.eml格式的原始邮件。 - 通过
getContent()获取邮件内容对象。
- 使用
-
附件识别逻辑:
- 检查
Content-Disposition: attachment头。 - 或检测
filename属性是否存在(如Content-Type: image/jpeg; name="photo.jpg")。
- 检查
-
结构处理:
- 嵌套多部分邮件:递归处理
multipart/related(常见于HTML邮件内嵌图片)。 - 非附件保留:文本正文(
text/plain、text/html)、内联资源(Content-Disposition: inline)等。
- 嵌套多部分邮件:递归处理
-
重建邮件:

- 创建新的
MimeMultipart对象,只添加非附件部分。 - 用
setContent()更新邮件体,保留原始头部(发件人、主题等)。
- 创建新的
注意事项
-
内嵌资源处理:
- 若需删除内嵌图片(如HTML中的
<img src="cid:...">),需额外检查Content-ID头。 - 示例:在
isAttachment()中添加|| (part.getHeader("Content-ID") != null)。
- 若需删除内嵌图片(如HTML中的
-
性能优化:
- 大附件邮件可能占用高内存,建议使用
InputStream分块处理。
- 大附件邮件可能占用高内存,建议使用
-
边界情况:

- 签名文件(.sig)、日历事件(.ics)可能被误判为附件,需调整过滤逻辑。
- 处理加密邮件(PGP/SMIME)需先解密。
扩展场景
| 场景 | 解决方案 |
|---|---|
| 仅删除特定类型附件 | 在isAttachment()中检查文件扩展名(如.exe) |
| 保留内联图片 | 添加条件:&& !disposition.equalsIgnoreCase("inline") |
| 从收件箱直接删除 | 结合IMAP协议,使用Folder.fetch()获取邮件后处理 |
权威引用
- JavaMail API 官方文档:Oracle JavaMail Docs
- RFC 2045 (MIME标准):IETF RFC 2045
- 邮件安全实践:OWASP Email Security Cheat Sheet
提示:实际部署时建议添加异常处理(如
MessagingException,IOException),并关闭所有流资源(try-with-resources)。
