Java解析eml邮件格式文件 您所在的位置:网站首页 eml转格式 Java解析eml邮件格式文件

Java解析eml邮件格式文件

2023-09-08 02:33| 来源: 网络整理| 查看: 265

基本介绍

关于邮件的需求总是以邮件发送或接收为主,之前涉及的技术选型有Java Mail、Apache Commons Email、Spring Mail,由于工作上的需要对eml格式的文件进行解析,随了解了一下使用Java来解析eml格式文件的实现,所谓的eml格式是微软公司在Outlook中所使用的一种遵循RFC822及其后续扩展的文件格式,并成为各类电子邮件软件的通用格式(本地电子邮件文件存储的文件格式),它的来源是电子邮件的英文E-mail的缩写形式,可以用outlook邮箱打开,也可以用各种本地邮箱客户端打开,如Foxmail、Notes等。

经过数番资料的百科发现可以使用Java Mail、Mime4J(Apache James子项目模块)的解析为主,Apache James有一个基于一组丰富的现代高效组件的模块化体系结构,它最终提供了运行在JVM上的完整、稳定、安全和可扩展的邮件服务器集成。James由内部项目(Server、Mailet、Mailbox、Protocols、MPT)和外部项目(Hupa、Mime4J、jSieve、jSPF、jDKIM)组成,其中Mime4J是解析邮件数据文件的实现,参考如下图所示:

Apache James Mime4J提供了一个解析器,用于普通RFC822和MIME中的电子邮件流格式。解析器使用回调机制报告解析事件,例如实体标头的开始、身体等。如果您熟悉SAX公司XML解析器接口开始使用mime4j应该没有问题。Mime4j还可以用于构建电子邮件使用消息类,使用此工具mime4j自动处理对字段和正文进行解码,并使用大型临时文件附件。

解析实现

(1)使用QQ邮箱编辑一封邮件发送出去,并到处为本地eml文件,该邮件中的信息(可提取出来的参数)包含有以下几处:

A. 邮件标题:

B. 邮件内容,内容部分可能是纯文本和富文本,富文本包含HTML文件、内容区域的本地图片等;

C. 收件人,可以是多个收件人,收件人区分昵称与实际的邮箱地址;

D. 抄送人,与收件人一致;

E. 密送人,与收件人一致;

F. 附件,可以有多个附件文件;

G. 发送时间,是否存在时区问题;

H. 邮件大小,邮件文件的大小;

I. Message-ID 邮件唯一ID标识;

(2)邮件内容专门构建的略复杂,收件人和抄送人均为多人;邮件为多个;邮件内容包含HTML富文本段落和本地图片文件,参考如下图所示:

(3)导入maven依赖(2023年一月初发布了0.8.9版本),经过坐标的依赖实践,发现导入apache-mime4j-examples坐标可以直接把依赖的几个模块直接给导入,实际应用中需要考虑依赖其它模块,按需排除emamples和commons-logging依赖,参考坐标如下:

org.apache.james apache-mime4j-examples 0.8.9

(4)解析实现示例:

package cn.chendd.eml; /** * Eml文件解析数据对象 * * @author chendd * @date 2023/2/11 21:40 */ @Data public class EmlEntry { /** * 原始message对象 */ @JSONField(serialize = false) private Message message; /** * 消息ID */ private String messageId; /** * 邮件主题 */ private String subject; /** * 纯文本邮件内容 */ private String textContent; /** * 富文本邮件内容 */ private String htmlContent; /** * 邮件附件 */ private List attachments = Lists.newArrayList(); /** * 发件人 */ private String from; /** * 收件人 */ private List to; /** * 抄送人 */ private List cc; /** * 密送人 */ private List bcc; /** * 邮件时间 */ private String dateTime; } package cn.chendd.eml; /** * 基本的eml文件解析示例 * * @author chendd * @date 2023/2/11 19:26 */ public class EmlBasicTest { public static void main(String[] args) { try (InputStream inputStream = EmlBasicTest.class.getResourceAsStream("/Java解析Eml格式文件示例.eml")) { Message message = Message.Builder.of(inputStream).build(); EmlEntry entry = new EmlEntry(); entry.setMessage(message); entry.setMessageId(message.getMessageId()); entry.setSubject(message.getSubject()); entry.setFrom(address2String(message.getFrom())); entry.setTo(address2List(message.getTo())); entry.setCc(address2List(message.getCc())); entry.setBcc(address2List(message.getBcc())); TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("GMT")); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(timeZone); entry.setDateTime(sdf.format(message.getDate())); MultipartImpl body = (MultipartImpl) message.getBody(); List bodyParts = body.getBodyParts(); //邮件附件和内容 outputContentAndAttachments(bodyParts , entry); System.out.println(JSON.toJSONString(entry , true)); } catch (Exception e) { e.printStackTrace(); } } /** * 递归处理邮件附件(附件区域附件、内容中的base64图片附件)、邮件内容(纯文本、html富文本) * @param bodyParts 邮件内容体 * @param entry 数据对象 * @throws IOException 异常处理 */ private static void outputContentAndAttachments(List bodyParts , EmlEntry entry) throws IOException { for (Entity bodyPart : bodyParts) { Body bodyContent = bodyPart.getBody(); String dispositionType = bodyPart.getDispositionType(); if (ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT.equals(dispositionType)) { //正常的附件文件 BinaryBody binaryBody = (BinaryBody) bodyContent; entry.getAttachments().add(MutableTriple.of(bodyPart.getFilename() , binaryBody.size() , binaryBody.getInputStream())); continue; } if (bodyContent instanceof TextBody) { //纯文本内容 TextBody textBody = (TextBody) bodyContent; ContentTypeFieldLenientImpl contentType = (ContentTypeFieldLenientImpl) bodyPart.getHeader().getField(HttpHeaders.CONTENT_TYPE); String mimeType = contentType.getMimeType(); //可动态获取内容的编码,按编码转换 if (MediaType.PLAIN_TEXT_UTF_8.toString().startsWith(mimeType)) { entry.setTextContent(IOUtils.toString(textBody.getReader())); } if (MediaType.HTML_UTF_8.toString().startsWith(mimeType)) { entry.setHtmlContent(IOUtils.toString(textBody.getReader())); } } else if (bodyContent instanceof Multipart) { MultipartImpl multipart = (MultipartImpl) bodyContent; outputContentAndAttachments(multipart.getBodyParts() , entry); } else if (bodyContent instanceof BinaryBody) { BinaryBody binaryBody = (BinaryBody) bodyContent; outputContentInAttachment(bodyPart.getHeader(), binaryBody, entry); } else { System.err.println("【是否还存在未覆盖到的其它内容类型场景】?"); } } } /** * 处理内容中的图片附件 * * @param header 附件头信息对象 * @param binaryBody 附件对象 * @param entry 解析数据对象 */ private static void outputContentInAttachment(Header header, BinaryBody binaryBody, EmlEntry entry) throws IOException { Field contentIdField = header.getField(FieldName.CONTENT_ID); Field typeField = header.getField(FieldName.CONTENT_TYPE); if (typeField instanceof ContentTypeField) { ContentTypeField contentTypeField = (ContentTypeField) typeField; if (contentTypeField.getMediaType().startsWith(MediaType.ANY_IMAGE_TYPE.type())) { try (InputStream inputStream = binaryBody.getInputStream()) { String base64 = Base64.getEncoder().encodeToString(IOUtils.toByteArray(inputStream)); String cid = StringUtils.substringBetween(contentIdField.getBody(), ""); String content = StringUtils.replace(entry.getHtmlContent(), "cid:" + cid, "data:" + contentTypeField.getMimeType() + ";base64," + base64); entry.setHtmlContent(content); } } } } /** * 转换邮件联系人至String * @param addressList 邮件联系人 * @return String数据 */ private static String address2String(MailboxList addressList) { if (addressList == null) { return StringUtils.EMPTY; } for (Address address : addressList) { return address.toString(); } return StringUtils.EMPTY; } /** * 转换邮件联系人至list集合 * @param addressList 邮件联系人 * @return list集合 */ private static List address2List(AddressList addressList) { List list = Lists.newArrayList(); if (addressList == null) { return list; } for (Address address : addressList) { Mailbox mailbox = (Mailbox) address; list.add(Pair.of(mailbox.getName() , mailbox.getAddress())); } return list; } } 解析结果

(解析的JSON结果)

(HTML段落另存为文件)

其它说明

(1)eml格式文件是纯文本的文件,可使用记事本、Notepad++等工具打开,所以当看到它的内容时也可以按需进行自定义解析实现;

(2)实际应用中肯定比这个要复杂的多,本篇只是一个富含多个知识细节的示例,工作中实际处理要复杂的多;

(3)某些场景下的附件名称需要特殊转码,实际的附件名称在邮件的源文件中被分割为了多段,需要合并后转码;

(4)邮件中包含回复邮件、转发邮件等多次邮件来往,需要特殊处理;

(5)邮件的内容部分包含多种内容类型,需要提供多种的解析适配程序(如:某些邮件的签名处有图片签名,混迹在内容区域,需要先解析富文本再解析二进制内容体等);

(6)本篇文章代码仅供参考,切勿直接使用,按内容类型来解析的实现应该是基于工厂模式进行的多种解析适配,示例工程源码见:下方的个人站点文章所述;

(7)了解更多欢迎访问:https://www.chendd.cn/blog/article/1624252901639442434.html



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有