Java中免费将.eml转.msg时遭遇NotOLE2FileException问题求助
EML转MSG报错解决(Java免费实现)
问题背景
需调用API传入.msg文件,本地仅有.eml文件,尝试转换时触发错误:
org.apache.poi.poifs.filesystem.NotOLE2FileException: Invalid header signature; read 0x6465766965636552, expected 0xE11AB1A1E011CFD0 - Your file appears not to be a valid OLE2 document
使用的错误代码片段:
String msg_file_path="C:\temp\msg_email.msg"; FileOutputStream msg_file = new FileOutputStream(msg_file_path); try { MAPIMessage msgObj = new MAPIMessage("C:\temp\_emai.eml"); msgObj.write(msg_file); System.out.println("EML file converted to MSG: " + msg_file); } catch (Exception e) { e.printStackTrace(); }
错误原因
MAPIMessage(Apache POI HSMF库类)的设计目的是读取解析.msg格式文件,而非转换.eml到.msg。直接传入.eml路径时,它会尝试将.eml当作OLE2格式的.msg文件解析,自然触发"不是有效OLE2文档"的错误。
正确实现方案
通过JavaMail解析.eml提取邮件内容,再用Apache POI HSMF构建.msg文件,全程免费开源。
1. 依赖配置(Maven)
<dependencies> <!-- JavaMail 用于解析EML --> <dependency> <groupId>com.sun.mail</groupId> <artifactId>jakarta.mail</artifactId> <version>2.0.1</version> </dependency> <!-- Apache POI HSMF 用于构建MSG --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>5.2.3</version> </dependency> </dependencies>
2. 完整转换代码
import org.apache.poi.hsmf.MAPIMessage; import org.apache.poi.hsmf.datatypes.AttachmentChunks; import jakarta.mail.*; import jakarta.mail.internet.MimeMessage; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; public class EmlToMsgConverter { public static void main(String[] args) { String emlFilePath = "C:\\temp\\_emai.eml"; String msgFilePath = "C:\\temp\\msg_email.msg"; try { // 解析EML文件 MimeMessage mimeMessage = parseEml(emlFilePath); // 构建MSG对象并填充内容 MAPIMessage msg = buildMsg(mimeMessage); // 写入MSG文件 try (FileOutputStream fos = new FileOutputStream(msgFilePath)) { msg.write(fos); System.out.println("转换完成:" + msgFilePath); } } catch (Exception e) { e.printStackTrace(); } } private static MimeMessage parseEml(String emlPath) throws Exception { Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); try (InputStream is = new FileInputStream(emlPath)) { return new MimeMessage(session, is); } } private static MAPIMessage buildMsg(MimeMessage mimeMsg) throws Exception { MAPIMessage msg = new MAPIMessage(); // 填充基本属性 msg.setSubject(mimeMsg.getSubject()); msg.setSenderEmail(mimeMsg.getFrom()[0].toString()); msg.setSentDate(mimeMsg.getSentDate()); // 处理收件人 Address[] toAddrs = mimeMsg.getRecipients(Message.RecipientType.TO); if (toAddrs != null) { List<String> toList = new ArrayList<>(); for (Address addr : toAddrs) { toList.add(addr.toString()); } msg.setDisplayTo(toList.toArray(new String[0])); } // 处理抄送(可选) Address[] ccAddrs = mimeMsg.getRecipients(Message.RecipientType.CC); if (ccAddrs != null) { List<String> ccList = new ArrayList<>(); for (Address addr : ccAddrs) { ccList.add(addr.toString()); } msg.setDisplayCC(ccList.toArray(new String[0])); } // 处理正文 msg.setBodyText(getPlainContent(mimeMsg)); // 若需保留HTML正文,可替换为msg.setBodyHtml(getHtmlContent(mimeMsg)); // 处理附件 if (mimeMsg.isMimeType("multipart/*")) { Multipart multipart = (Multipart) mimeMsg.getContent(); for (int i = 0; i < multipart.getCount(); i++) { BodyPart part = multipart.getBodyPart(i); if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { try (InputStream is = part.getInputStream()) { AttachmentChunks attachment = msg.createAttachment(); attachment.setFilename(part.getFileName()); attachment.setData(is.readAllBytes()); } } } } return msg; } private static String getPlainContent(MimeMessage msg) throws Exception { if (msg.isMimeType("text/plain")) { return msg.getContent().toString(); } else if (msg.isMimeType("multipart/*")) { Multipart multipart = (Multipart) msg.getContent(); for (int i = 0; i < multipart.getCount(); i++) { BodyPart part = multipart.getBodyPart(i); if (Part.INLINE.equalsIgnoreCase(part.getDisposition()) || part.getDisposition() == null) { return getPlainContent((MimeMessage) part); } } } return ""; } }
3. 注意事项
- 确保依赖版本兼容:Apache POI 5.x需搭配Jakarta Mail 2.x
- 复杂邮件(如内嵌图片、多格式正文)需扩展解析逻辑,示例提供基础处理框架
- 路径中的反斜杠需转义为
\\,避免Java字符串解析错误
内容的提问来源于stack exchange,提问作者preet leelaramani
相关产品推荐
相关产品推荐

