使用JavaMail 1.5.6解析嵌套EML文件时内容为空问题咨询
我刚碰到一模一样的问题!之前用JavaMail 1.5.6写EML解析器,参考官方msghow.java示例,结果遇到带EML附件的邮件时,明明能识别出这个附件是message/rfc822类型,但调用getSubject()、getSentDate()这些方法全返回null,连正文都拿不到。之前用mime4j没问题,但就想纯用JavaMail搞定,后来终于找到原因了。
先看看你提供的测试邮件片段:
MIME-Version: 1.0 Date: Tue, 30 Apr 2019 16:20:45 +0200 Message-ID: <CA+fLqEW8TUfSxih9DTp2WXa63pS7wf1eZiro_9k1XS4AShN5Zg@mail.gmail.com> Subject: Message with an eml as attachment From: a b <ab@gmail.com> To: cd@pec.cd.it Content-Type: multipart/mixed; boundary="00000000000057f76c0587c01bc9" --00000000000057f76c0587c01bc9 Content-Type: multipart/alternative; boundary="00000000000057f7670587c01bc7" --00000000000057f7670587c01bc7 Content-Type: text/plain; charset="UTF-8" Hello guys, this is a simple message from a not certified account, it contains only one attachment, an eml message --00000000000057f7670587c01bc7 Content-Type: text/html; charset="UTF-8" <div dir="ltr">Hello guys,<div><br></div><div>this is a simple message from a not certified account, it contains only one attachment, an eml message</div></div> --00000000000057f76c0587c01bc9 Content-Type: message/rfc822; name="Cena zerebao.eml" Content-Disposition: attachment; filename="Cena zerebao.eml" Content-Transfer-Encoding: base64 X-Attachment-Id: f_jv3vpu760 Content-ID: <f_jv3vpu760> WC1Ob3Rlcy1JdGVtOiBGcmksIDYgSnVsIDIwMTggMTc6NDA6MDAgKzAyMDA7DQogdHlwZT00MDA7 IG5hbWU9T3JpZ2luYWxNb2RUaW1lDQpYLU5vdGVzLUl0ZW06IE1lbW87DQogbmFtZT1Gb3JtDQpY LU5vdGVzLUl0ZW06IFN0ZE5vdGVzTHRyMjU7DQo.... and so on
问题根源
官方的msghow.java示例没有专门处理message/rfc822类型的附件,它只是把所有BodyPart当成普通附件或文本内容来处理,但实际上这种类型的附件本身就是一封完整的邮件,不能直接用MimeBodyPart的方法去获取邮件头信息,必须把它转换成MimeMessage对象才行。
解决方法
遍历父邮件的Multipart内容时,一旦检测到BodyPart是message/rfc822类型,就用它的输入流创建一个新的MimeMessage实例,之后就能像处理普通邮件一样获取它的主题、日期、正文和附件了。
给你一段核心代码示例:
// 假设已经获取到父邮件的MimeMessage对象message Multipart multipart = (Multipart) message.getContent(); Session session = Session.getDefaultInstance(new Properties()); for (int i = 0; i < multipart.getCount(); i++) { BodyPart bodyPart = multipart.getBodyPart(i); if (bodyPart.isMimeType("message/rfc822")) { // 关键步骤:将EML附件转换为MimeMessage MimeMessage nestedMessage = new MimeMessage(session, bodyPart.getInputStream()); // 现在可以正常获取内嵌EML的各种信息了 String nestedSubject = nestedMessage.getSubject(); Date nestedSentDate = nestedMessage.getSentDate(); Object nestedContent = nestedMessage.getContent(); // 递归解析内嵌EML的内容和附件(如果有的话) parseEmailContent(nestedMessage); // parseEmailContent是你自己实现的解析方法 } else { // 处理普通文本内容或非EML附件 if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) { // 处理普通附件 String fileName = bodyPart.getFileName(); // ... } else { // 处理正文文本 String content = bodyPart.getContent().toString(); // ... } } }
为什么这样可行?
message/rfc822类型的附件本质上是符合RFC822标准的邮件内容,JavaMail的MimeMessage正好是用来解析这种格式的。通过输入流重新构建MimeMessage,就能让JavaMail正确解析它的邮件头和内容结构,而不是把它当成一段二进制或文本数据。
之前我就是这么改的,改完之后内嵌EML的所有信息都能正常获取了,官方示例msghow.java也可以按这个逻辑修改来解决问题。
内容的提问来源于stack exchange,提问作者Gamby

