文章目录

  • 什么是EML文件
  • 实现EML导入
  • 就这?
  • winmail.dat
  • 编码

什么是EML文件

通过的说,电子邮件导出后的文件格式就是.eml文件,比如使用outlook163邮箱等等电子邮件程序将电子邮件导出后,就可以得到.eml文件,EML文件应该符合RFC 5322规范,这样EML文件就可以在不同的邮件客户端之间流通。

也就是说,使用163邮箱客户端导出的eml文件,完全可以在Ooutlook中『基本一致』的打开

之所以说基本一致,因为还是有很多兼容性问题要处理,而且很多邮箱客户端还有独有的私有协议内容,对应的样式在其他邮箱客户端只能以基本的样式进行展示

以163邮箱为例,如下图,将邮件导出,就得到了预约直播,听专家分享《面向大规模数据的云端管理,百度沧海·存储产品解析》.eml文件

使用邮箱大师,就可以将这个文件导入,并进行展示:

展示与原邮件基本是一致的

实现EML导入

在我们的灵犀办公客户端上,也要实现这个导入EML文件的功能,这个功能有现成的库来支持,可选择的有三个库:

  • NodeMailer的MailParser
  • eml-format
  • eml-parser

三个工具使用的解析的结果大同小异,我们选用的是MailParser(额外说一句,NodeMailer功能非常强大,可以用它构建一个自己的邮件收发系统)

按照文档很容易就能实现一个简单的EML解析器:

const fse = require('fs-extra');
const simpleParser = require('mailparser').simpleParser;function parseEml(filePath) {return fse.stat(filePath).then(() => {return fse.readFile(filePath).then((file) => {return simpleParser(file);});});
}

解析的结果包含了下面的字段:

在我们的系统中,根据这些属性,可以构造出一个完整的MailEntitiy结构,用于完成常规的服务端返回的邮件数据解析流程。到此解析就流程就完了。

就这?

当然不是,为了提高解析性能,我们还在客户端本地的数据库,使用文件地址和文件名称组合为key,在本地数据库记录了结果。当然这都是小优化,直到功能上线后,QA报了一个线上问题,有一封邮件,我们的客户端打开后,样式乱了,结果如下:

导入导服务端之后却是正常的

用邮箱大师也是正常的,那我们出了什么问题呢?

用MailParser解析之后,发现解析的结果里面,attachments是有值的,而htmlfalsetext里面就是我们的客户端解析后的数据,并没有相应的内联样式:

一开始以为是参数的问题,一通调试后发现然并卵,后来以为是编码的问题,因为这封邮件的charsetgb2312,结果发现也没有用(虽然后面编码还是要处理的)

咨询了服务端的同学,他给出的答案一针见血,邮件的附件里面是不是有一个dat附件,需要对dat附件进行二次解析才可以

winmail.dat

winmai.dat是Microsoft Outlook是特殊格式附件,如果Outlook寄出富文本格式的信件,其他邮件客户端收到的时候,就会产生这个文件。真正的内容和样式实际上都是在这个附件中。

所以需要对这个文件进行二次解析,在NPM上找到了node-tnef这个工具,使用它就可以解析winmai.dat附件。由于我们在解析eml文件时,附件已经是Buffer格式的数据了,所以直接使用tnef.parseBuffer这个方法就可以,得到的content里面包含了BodyHTML数据,把这个带有样式的富文本数据格式赋值给eml解析后的html字段(原本是false)就可以解析出正确的数据了

function handleDatAttachments(parsedMail, encoding) {const datAttach = parsedMail.attachments.find((v) => v.contentType === 'application/ms-tnef' && v.filename && v.filename.endsWith('dat'));if (datAttach) {return new Promise((resolve) => {tnef.parseBuffer(datAttach.content, (err, content) => {if (err) {resolve('');} else {const res = content.BodyHTML.toString();resolve(res);}});});}
}function parseEml(filePath) {return fse.stat(filePath).then(() => {return fse.readFile(filePath).then((file) => {return simpleParser(file).then((parsedMail) => ({parsedMail}));});});
}parseEml(path.join(__dirname, 'test3.eml')).then(({encoding, parsedMail}) => {console.timeEnd('parse time');return writeFile('parsed.js', JSON.stringify(parsedMail)).then(() => {return handleDatAttachments(parsedMail, encoding).then((html) => {if (html) {parsedMail.html = html;}return parsedMail;});});}).then((parsedMail) => writeFile('parsed.html', parsedMail.html));

前面先对附件进行了一下过滤,只针对这种特殊的附件进行处理,其他的附件处理时有自己的逻辑。解析完成后,在本地模拟时,使用了一个iframe来加载内容:

<!-- index.html -->
<!DOCTYPE html>
<html lang='en'>
<head><meta charset='UTF-8'><title>Title</title><style>* {padding: 0;margin: 0;}html, body {width: 100%;height: 100%;overflow: hidden;}.iframe {border: none;}</style>
</head>
<body><iframe class='iframe' src='parsed.html' width='100%' height='100%'></iframe>
</body>
</html>

结果发现,表格样式可以加载出来了,但是文本都成了乱码了:
这就是前面说的编码的问题了

编码

在Webstorm里面直接打开test3.eml文件,可以看到这样的一段内容:

--_000_12ff39986d6b48b7a0ff65d2447f3c87ghaccn_
Content-Type: text/plain; charset="gb2312"
Content-Transfer-Encoding: base64

里面的charsetgb2312,但是我们的index.html设置的charsetUTF-8,二者不匹配,自然就出现了问题。

这就需要我们将解析得到的gb2312编码的html内容转换为utf-8编码。由于Node原生不支持GBK编码,所以使用了iconv-lite这个工具来进行编码的转换,使用很简单:

const iconvLite = require('iconv-lite');
// 将 data 中的内容以 gbk 编码格式转换为默认使用 utf-8 编码的字符串
const newData = iconvLite.decode(data, 'gbk')

所以在上面的代码中加入这一部分,此外还要注意的是,解析得到的HTML内容中是有一个<meta>指定了charset=gb2312的编码,也会导致页面解析出问题,所以需要给它替换掉。

这里直接使用了字符串的查找和替换,也可以使用DomParser来进行文档的二次处理,加上这部分内容之后,显示终于正常了

完整的代码:

/*** Created by zh on 2022/6/1.*/
const fse = require('fs-extra');
const path = require('path');
const simpleParser = require('mailparser').simpleParser;
const tnef = require('node-tnef');
const iconvLite = require('iconv-lite');function parseEml(filePath) {return fse.stat(filePath).then(() => {return fse.readFile(filePath).then((file) => {const charsetMatch = file.toString().match(/Content-Type:.+charset="(.+)"/i);const encoding = Array.isArray(charsetMatch) && charsetMatch[1] ? charsetMatch[1] : 'utf8';return simpleParser(file).then((parsedMail) => ({parsedMail,encoding}));});});
}function handleDatAttachments(parsedMail, encoding) {const datAttach = parsedMail.attachments.find((v) => v.contentType === 'application/ms-tnef' && v.filename && v.filename.endsWith('dat'));if (datAttach) {return new Promise((resolve) => {tnef.parseBuffer(datAttach.content, (err, content) => {if (err) {resolve('');} else {const buffer = iconvLite.decode(Buffer.from(content.BodyHTML), encoding);const res = buffer.toString();resolve(res);}});});}
}function writeFile(fileName, data) {const filePath = path.join(__dirname, fileName);return fse.writeFile(filePath, data, 'utf8').then(() => {console.log('写入完成', fileName);});
}console.time('parse time');
parseEml(path.join(__dirname, 'test3.eml')).then(({encoding, parsedMail}) => {console.timeEnd('parse time');return writeFile('parsed.js', JSON.stringify(parsedMail)).then(() => {return handleDatAttachments(parsedMail, encoding).then((html) => {if (html) {parsedMail.html = encoding !== 'utf-8' ? html.replace(/charset=gb2312/i, /charset=utf-8/) : html;}return parsedMail;});});}).then((parsedMail) => writeFile('parsed.html', parsedMail.html));

也可以在这里看到源码。

使用Node解析EML文件相关推荐

  1. java解析eml文件_使用JavaMail解析EML文件

    Java 当我们在outlook中保存一个邮件是可以存成eml格式,这种格式是标准的邮件格式. 这种文件可以用JavaMail来解析. import java.util.*; import java. ...

  2. Java解析eml文件工具类

    依赖 <!-- https://mvnrepository.com/artifact/javax.mail/mail --><dependency><groupId> ...

  3. python 解析 eml文件

    #-*- encoding: gb2312 -*- import email fp = open('xxxx.eml', "r") msg = email.message_from ...

  4. java eml解析_javamail 收邮件 解析eml文件

    内容来自:http://www.oschina.net/bbs/thread/528 以下代码经过测试了的能通过 我在用javaMail做收邮件时怎么邮件内容重复(一种文本格式的,一种html格式的) ...

  5. Java实现eml文件的解析

    最近在做邮件归档,然后需要解析邮件导出的eml,记录每封邮件的归档时间,发件人.标题.发件时间.归档的目录 以下是一个demo示例:待完成此功能后再优化后续代码 import java.io.File ...

  6. C# 操作.eml文件

    前段时间做了个关于邮件的东西,记录一下如何解析和保存eml文件的. /// <summary>         /// 解析eml         /// </summary> ...

  7. 通过Node.js解析stl文件

    通过Node.js解析stl文件 在此之前请确认已安装Node.js,已配置环境变量.如未安装与配置,请查看Node.js安装及环境配置(Windows) 一.下载Node项目文件 Node项目文件下 ...

  8. Java解析eml邮件格式文件

    基本介绍 关于邮件的需求总是以邮件发送或接收为主,之前涉及的技术选型有Java Mail.Apache Commons Email.Spring Mail,由于工作上的需要对eml格式的文件进行解析, ...

  9. 如何解析EML(邮件)格式的文件以及一款小巧的EML邮件阅读工具

    在理解EML格式的时候,先回顾一下历史,这样有助于理解邮件的格式,比如邮件传输时为何会有多种编码方式.此外,理解EML格式也有助于理解HTTP协议. 历史溯源 由于历史原因,我们目前看到的大部分的网络 ...

最新文章

  1. 这个最基本的生命细节才被揭开——25毫秒核孔穿梭
  2. 相对路径和绝对路径错误造成的漏洞
  3. 《精通Unreal游戏引擎》一第4步 使用BSP创建地图
  4. 笔记-项目质量管理-过程决策程序图法
  5. 【字符串系列】字符串匹配中的位并行算法
  6. Python基础教程:__setattr__和__delattr__和__getattr__的用法
  7. 如何使用Navicat MySQL导入.sql文件
  8. 个税改革怎么改?媒体称年收入超12万者税负或增加
  9. 如何用python刷屏_利用python实现在微信群刷屏的方法
  10. CCF推荐国际学术会议和期刊目录2019年
  11. 教育实习手册高中计算机,计算机教育实习论文大纲格式模板 计算机教育实习论文框架如何写...
  12. python3视频教程哪个好_2020年5个经典python编程入门视频教程推荐学习
  13. 【CVPR 2021】Revisiting Knowledge Distillation: An Inheritance and Exploration Framework
  14. 多态的表现形式有哪些?
  15. Word怎么在方框里打勾就是一个方框打上一个对号
  16. 彻底卸载mac软件的方法,这样才删除干净哦
  17. Gym - 100519 B Bring Your Own Bombs 离散化+二分+思维
  18. 阿里云服务器与堡垒机搭建Oracle数据库(配置多个实例)以及数据库导入、导出
  19. Linux中nohup的使用
  20. 一周内咸鱼疯转2.4W次,最终被所有大厂封杀

热门文章

  1. 内网渗透系列:内网渗透思路整理
  2. 线上护肤品市场分析报告
  3. ⑤电子产品拆解分析-人体感应灯
  4. MSChart的研究
  5. Homestead环境搭建及简介
  6. 1986 三 法兹·多米诺 Fats Domino
  7. 团队管理案例——渐入佳境了
  8. 解决WIN8磁盘占用率100%的问题电脑从WINXP换WIN7,WIN8非电脑配置低档但系统运行很卡的问题。——硬盘4K对齐
  9. 二叉树的创建和基本操作(详解)
  10. 滑雪大冒险去身份验证弹窗