使用Javascript在Microsoft Outlook中创建HTML邮件

33

我想从Javascript Web应用程序中创建电子邮件。我完全知道有关此问题的许多SO问题(例如在Chrome中使用HTML打开Outlook)。传统答案存在以下问题:

  1. Mailto:链接:这将使您创建电子邮件,但仅限于纯文本(无HTML),并且不允许附件。

  2. Activex:仅限于IE,我的应用程序还需要在Firefox和Chrome中运行。安装FF&Chrome插件以允许ActiveX存在安全隐患,而且似乎也很容易出现错误。

  3. 通过SMTP发送服务器端:用户的电子邮件不会出现在“已发送”文件夹中。还有一些障碍,如让用户在浏览器中编辑HTML并附加文件。

  4. 创建Outlook .MSG文件:似乎没有任何库,并且对此进行了很少的编写。显然,该文件格式实际上嵌入了整个FAT文件存储系统。

许多其他SO问题和我的关键区别

  • 可以访问客户机器,因此我可以安装辅助应用程序或插件,根据需要更改设置等。
  • 该界面不需要实际发送邮件,它只需要为用户设置邮件。
  • 我还需要能够从JS中提供电子邮件附件(例如PDF)。

我不可能是第一个遇到这个问题的Web应用程序开发人员,但我无法找到任何解决方案,无论是商业还是开源。

更新:

我使用了EML文件方法,目前表现良好。以下是我创建并触发它的JS代码:

var emlContent = "data:message/rfc822 eml;charset=utf-8,";
emlContent += 'To: '+emailTo+'\n';
emlContent += 'Subject: '+emailSubject+'\n';
emlContent += 'X-Unsent: 1'+'\n';
emlContent += 'Content-Type: text/html'+'\n';
emlContent += ''+'\n';
emlContent += htmlDocument;

var encodedUri = encodeURI(emlContent); //encode spaces etc like a url
var a = document.createElement('a'); //make a link in document
var linkText = document.createTextNode("fileLink");
a.appendChild(linkText);
a.href = encodedUri;
a.id = 'fileLink';
a.download = 'filename.eml';
a.style = "display:none;"; //hidden link
document.body.appendChild(a);
document.getElementById('fileLink').click(); //click the link

你的问题有些含糊不清。你的标题和标签表明你想使用JavaScript,但是你的“关键差异”说明你可以使用辅助应用程序和插件,这些并不一定是JavaScript。看起来你希望我们为你寻找解决方案,这通常不适合在SO上提问。 - Heretic Monkey
但我将使用JavaScript创建消息并与某些未知解决方案进行交互所需的任何其他内容。我已经自己四处寻找解决方案。我没有要求任何其他人帮我寻找,我只是问是否有人有我没有想到的方法。 - James Bell
我喜欢这种方法,它遵循浏览器沙盒规则(用户不必打开他们下载的EML文件),同时似乎提供了所需的一切。我肯定会找到这种技术的用途! - Falkayn
@James Bell,您能提供您的filename.eml文件吗?我很感兴趣您是如何添加附件的。 - yurin
@yurin,.EML文件可以用于将HTML电子邮件传递到Outlook,但我找不到任何添加附件的方法。 - James Bell
1
不好的消息:Chrome(大约从v.46开始)已经开始将.EML文件标记为可能有害。我不知道一个文本文件会带来什么可怕的后果,但我想他们肯定有他们的理由。 - James Bell
6个回答

29
MSG文件格式是有文档记录的,但肯定不好玩... 为什么不创建一个EML(MIME)文件呢?
建议使用EML(MIME)格式。根据OP的说法,他们考虑过MSG文件格式(#4),但由于其复杂性和缺乏处理该格式的JS库,他们被打消了念头。如果考虑使用MSG文件,那么MIME是一个更好的选择 - 它是基于文本的,因此不需要特殊的库来创建它。Outlook可以像打开MSG文件一样轻松地打开它。
为了确保Outlook将EML消息视为未发送的消息,请将X-Unsent MIME头设置为1
最简单的EML文件看起来像下面这样:
To: Joe The User <joe@domain.demo>
Subject: Test EML message
X-Unsent: 1
Content-Type: text/html

<html>
<body>
Test message with <b>bold</b> text.
</body>
</html>

1
这并没有提供问题的答案。如果您想对作者进行批评或请求澄清,请在他们的帖子下留言。 - NicolasMoise
2
不是针对你尼古拉斯,你听起来像个英语母语人士。我相信你明白我的建议是使用MIME文件格式。我相信你可以理解,“为什么不创建一个EML(MIME)文件?”是一种委婉的说法,“你确实需要使用EML(MIME)格式”。 - Dmitry Streblechenko
3
这个想法得以实现,确实给了我制作Outlook HTML邮件的方法。我还没有尝试附件,但这很好地解决了我目前的需求。感谢@CalvT的进一步开发。 - James Bell
1
赞赏“X-Unsent: 1” - 这正是我在寻找的。谢谢。 - Marc
1
@Gintas K - 当然,它们受Outlook 2016的支持。创建一个EML文件并从Windows资源管理器中打开它即可。 - Dmitry Streblechenko
显示剩余9条评论

20

使用纯文本eml文件的想法,我想出了这个: http://jsfiddle.net/CalvT/un3hapej/

这是我找到的一个编辑版本 - 用于创建.txt文件然后下载。由于.eml文件实际上是.txt文件,我认为这个方法可以行得通。而且确实如此。我已经将带有示例电子邮件的textarea保留下来,以便您可以轻松测试。当您单击“创建文件”时,它会给您提供一个下载链接来下载您的.eml文件。我唯一能看到的障碍是让浏览器在下载完成后打开.eml文件。

编辑:思考一下,因为您可以访问客户端计算机,所以可以设置浏览器始终打开该类型的文件。例如,在Chrome中,您可以单击下载旁边的箭头并选择始终打开此类型的文件。

以下是代码:

HTML:

(function () {
var textFile = null,
  makeTextFile = function (text) {
    var data = new Blob([text], {type: 'text/plain'});

    if (textFile !== null) {
      window.URL.revokeObjectURL(textFile);
    }

    textFile = window.URL.createObjectURL(data);

    return textFile;
  };


  var create = document.getElementById('create'),
    textbox = document.getElementById('textbox');

  create.addEventListener('click', function () {
    var link = document.getElementById('downloadlink');
    link.href = makeTextFile(textbox.value);
    link.style.display = 'block';
  }, false);
})();
<textarea id="textbox" style="width: 300px; height: 200px;">
To: User <user@domain.demo>
Subject: Subject
X-Unsent: 1
Content-Type: text/html

<html>
<body>
Test message
</body>
</html>
  
</textarea>

<button id="create">Create file</button>
  
<a download="message.eml" id="downloadlink" style="display: none">Download</a>


我计划进一步开发它,因为它很有趣。 - CalvT
你发现如何通过eml文件添加附件了吗? - yurin
6
在不下载文件到浏览器的情况下,能否直接在Outlook中打开eml文件? - Santhosh
我有类似的需求,并且已经采用了这种方法,但是我的电子邮件内容中包含了base64编码的图像。当eml文件生成时,图像的大小会减小。此外,Fiddler在Microsoft Edge浏览器版本90.0.818.56上无法使用。以下是相关链接 -> https://stackoverflow.com/questions/67523117/image-size-reduced-when-base64encoded-image-is-embedded-in-rich-email-containing - AnitaS
@AnitaS,对我来说,在Edge 90.0.818.62上小提琴是可以使用的,所以也许你的问题是本地问题? - CalvT
@CalvT 我不确定这个问题,尽管在其他版本的Edge浏览器上进行了测试是可以运作的。但是当HTML中嵌入base64编码的图像时会出现渲染图像的问题。https://jsfiddle.net/AnitaSS/g7jnvuab/1 - AnitaS

13

似乎没有人回答附件问题,所以这是我的解决方案:将EML创建为多部分/混合消息。

Content-Type: multipart/mixed; boundary=--boundary_text_string

通过这样做,您可以在电子邮件中包含多个部分。多部分使您可以添加附件,就像这样。

Content-Type: application/octet-stream; name=demo.pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment

从您的电子邮件头开始,然后添加您的边界,再添加部分内容(换行符位置非常重要,否则客户端将无法正确解析您的文件)。您可以添加多个部分。以下是一个示例。请注意,最后一个边界与其他边界不同(末尾有2条破折号)。

To: Demo-Recipient <demo@demo.example.com>
Subject: EML with attachments
X-Unsent: 1
Content-Type: multipart/mixed; boundary=--boundary_text_string

----boundary_text_string
Content-Type: text/html; charset=UTF-8

<html>
<body>
<p>Example</p>
</body>
</html>

----boundary_text_string
Content-Type: application/octet-stream; name=demo.txt
Content-Transfer-Encoding: base64
Content-Disposition: attachment
ZXhhbXBsZQ==

----boundary_text_string
Content-Type: application/octet-stream; name=demo.log
Content-Transfer-Encoding: base64
Content-Disposition: attachment
ZXhhbXBsZQ==

----boundary_text_string--

这将为您提供一个包含两个附件的eml文件。如果您想了解更多关于其工作原理的具体信息,请参阅RFC 1371


3

当我使用非英文字符创建.eml文件并在Outlook中打开时,我遇到了编码问题。

问题在于我将"charset="放到了错误的位置,并没有在编码周围加上引号(")。

解决方案:

function createShiftReportEmail() {
    const title = "Shift Összefoglaló";
    const body = "ÁÉŐÚŰÓÜÖÍűáéúőóöí";

    const emlContent = new Blob([`data:message/rfc822 eml,\nSubject: ${title}\nX-Unsent: 1\nContent-Type: text/plain;charset="utf-8"\n\n${body}`]);

    if (!document.querySelector('#downloadEmail')) {
        document.body.insertAdjacentHTML('beforeend', '<a id="downloadEmail" download="ShiftReport.eml" style="display: none">Download</a>');
    }
    const downloadBtn = document.querySelector('#downloadEmail');
    downloadBtn.href = URL.createObjectURL(emlContent);
    downloadBtn.click();
}

编辑:事实证明引号(")甚至不需要。只是我的放置位置有误。


1

简化生活的JS库(无需重新发明轮子):

  • 组合EML文件:nodemailer/lib/mail-composer
  • 解析EML文件:mailparser
  • 解析MSG文件:@kenjiuno/msgreader

谢谢,这真的很有帮助。然而,如果能提供一个使用nodemailer/lib/mail-composer创建EML文件的示例,那就太好了。 - undefined

0

在尝试了korhojoa的答案后,它并没有起作用,需要进行一些调整:

To: Demo-Recipient <demo@demo.example.com>
Subject: EML with attachments
X-Unsent: 1
Content-Type: multipart/mixed; boundary=--boundary_text_string

----boundary_text_string
Content-Type: text/html; charset=UTF-8

<html>
<body>
<p>Example</p>
</body>
</html>

----boundary_text_string
Content-Type: application/octet-stream; name=demo.txt
Content-Transfer-Encoding: base64
Content-Disposition: attachment

ZXhhbXBsZQ==

----boundary_text_string
Content-Type: application/octet-stream; name=demo.log
Content-Transfer-Encoding: base64
Content-Disposition: attachment

ZXhhbXBsZQ==

----boundary_text_string--

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接