背景
后台问我能不能前端直接解析 eml
文件,项目是 Vue
, 首先想到能不能 npm
找个包解析
过程
- 首先上 npmjs 直接搜
eml
, 找到了一个eml-format
包 - 了解
quoted-printable
编码,随后发现我从QQ邮箱导出的eml
文件是GB2312
编码,因为之前对编码不熟悉, JS 也没有直接对它解码的方法,想用 JS 原生的编解码方法也没弄好 最后找到一个 js对中文进行gb2312/gbk编码解码 , 确定从里面下载的 js 文件确实可以解码
GB2312
编码,于是稍作修改之后放到项目中引用,解析如下:// 这里的 attachments 是我直接用 eml-format 对字符串解析得到的对象里获取到的内容属性 // 但是使用请求工具, 如 axios , 其get方法直接获取服务器上的 eml 文件,返回的字符串保险起见再 .toString() 一下,再用 eml-format 解析,这时格式会发生变化,内容属性不一定是 attachments , 甚至不一定是数组, 具体情况具体分析 temp.attachments.map(item => { let tempData = item.data; tempData = tempData.slice(tempData.indexOf('Transfer-Encoding: quoted-printable') + 'Transfer-Encoding: quoted-printable'.length); // 去掉多余数据 tempData = tempData.replace(/=\r\n/g, ''); // 去除 quoted-printable 行末等号,以免影响汉字匹配 let reg = /((=[0-9|A-F]{2}){2})/g; // GB2312 汉字检测,连续两个 '=xx' 才能解析为一个汉字 tempData = tempData.replace(reg, function (str, a) { return gbDecode.decode(a.replace(/=/g, '%')); }); // 转换汉字 tempData = tempData.replace(/(=[0-9|A-F]{2})/g, function (str, a) { return gbDecode.decode(a.replace(/=/g, '%')); }); // 转换符号(剩余的单个 '=xx') item.data = tempData; });
但是之后我在搜索
GB2312
时发现了一个更好的包,emailjs-mime-codec
,于是新的解析代码如下:// 引入 import * as emlFormat from 'eml-format'; import * as Codec from 'emailjs-mime-codec'; // 项目里用的 axios ,这里就跟着用了 // this.emlData 是 vue 的用法, 用它之前我已在 vue 定义了这个变量 axios.get('服务器请求url').then(response => { this.emlData = response.data.toString(); // 不 .toString() 可能有些稀奇古怪的问题 this.emlData = this.emlData.replace(/(=\?[\s\S]*?\?=)/g, function (str, a) { // 正则替换一些地方(目前只发现了 subject 邮件主题是这样)的 =?...?= return escape(Codec.mimeWordsDecode(a)); // 返回解码后又被 escape 编码的字符串,另外大家都说 escape 弃用了,那看要不要换成 encodeURI 吧 }); }); // 这个 parsedEmlData 是在 vue 的 computed 定义的计算属性,可以根据 this.emlData 的变化而动态调用 下面的 getter 函数,函数返回新值 parsedEmlData: function () { let temp = this.emlData; temp = Codec.quotedPrintableDecode(temp, 'GB2312'); // 整体解码,替换原来的手动正则匹配 let returnValue = {}; emlFormat.read(temp, (err, data) => { if (err) { console.log(err); } else { data.subject = unescape(data.subject); // 把之前的 escape 编码的数据解码回中文,不走这一步整体解码后这里很可能不会被解码,还有些其他原因,有兴趣的可以试试,同理,之前用 encodeURI 的话这里就用 decodeURI returnValue = data; } }); return returnValue; }
后续
后台说这个只是储备,他们有接口可以返回后台解析的数据……