在Ruby中格式化电子邮件回复

3
我正在使用ruby制作自己的电子邮件客户端,目前它可以解析/读取消息。 它还可以创建一个回复消息,设置标头并将消息发送给原始发件人。 如何将原始引用消息添加到回复中? 在回复中如何格式化原始消息?是否有最佳实践或格式? MIME/RFC?我知道应该有HTML和文本的字符串,只是不确定如何生成这些字符串。
现在我的回复没有原始消息,这使得单独理解变得复杂。
1个回答

6

回复邮件是一项相当具有挑战性的任务,特别是在开始时您不知道从哪里开始。

最近,我需要编写此类电子邮件并以编程方式发送。我首先做的是查看其他电子邮件客户端(如Thunderbird)如何处理此类邮件。尽管需要一些实验和耐心。

我使用的消息的整体结构主要基于这个Stack Overflow答案:https://dev59.com/hG865IYBdhLWcg3wQMWW#23853079


1. HTML部分

请注意,您有几个选项:要么组成HTML片段(典型的<body>标记的内容),要么整个HTML文档(包括<html><head><body>标记)。我看了一下Thunderbird是如何做的。结果它创建了整个文档,大致生成方式如下:

  1. 创建HTML文档
  2. <head>部分添加元信息<meta content="text/html; charset=utf-8" http-equiv="Content-Type">(将字符集替换为您喜欢的字符集)
  3. <body>部分添加您组成的HTML片段、引用的标题(例如:“<div>几天前,John Smith写道:</div>”)以及紧随其后的<blockquote cite="mid:originalmessagemid@example.com" type="cite">块。请注意,原始消息中有一个消息ID。
这里是我不太喜欢Thunderbird的部分:
4. 复制原始邮件的HTML内容并粘贴到<blockquote>块中。
Thunderbird实际上并不检查复制的HTML是片段还是文档。但是如果它是文档,则会剥离<html><head>标签...同时保留它们的内容。结果,您可以在新邮件的<body>标记中看到来自原始邮件的<head>部分的<style><title>标记。很混乱。
此外,Thunderbird无法处理全局样式。您可以轻松地使用全局样式而不是内联样式来撰写棘手的邮件,当消息的收件人开始撰写回复时,样式会泄漏到整个消息中。
你可以做同样的事情。这并不会伤害任何人,只是一些通常在普通邮件中不被注意到的怪癖。而且很容易。或者你可以再进一步,清理这个混乱。
首先,你需要获取任何一个 HTML 解析器。我正在使用Nokogiri,我的使用方式如下:
  1. 它会自动将任何片段转换为HTML文档,因此无需分别分析片段和文档
  2. 在文档中查找 <body> 标签并复制其内容
  3. 删除任何发现的 <style> 标签
  4. 将结果复制到需要的位置
大致看起来应该像这样:
doc = Nokogiri::HTML.parse(strHTML)
body = doc.css('body')[0]
body.css('style').each { |node|
    node.unlink
}

puts body.inner_html

Nokogiri还有一个好处 - 如果在HTML消息中有任何内联图像,您可以轻松找到它们,将URL替换为“cid:...”方案,并将图像添加为内联附件。

2. 纯文本部分

没错,在 multipart/alternative 部分中也有邮件的纯文本版本。这里最关键的步骤是将任何HTML文本转换为纯文本版本,这比编写HTML部分更加棘手。毕竟,你需要编写一个简单的渲染引擎(就像其他任何网页浏览器一样)。可能会有专门针对此类问题的工具,但不幸的是我当时找不到。

以下是几个要点,可以帮助您入手:

  • 所有换行符(\r\n或\n)应替换为一个空格
  • 所有多个空格应仅减少到一个(除非它们是不间断的)
  • 某些标签保留内容,而其他标签则不保留(例如<style><script>标签与<b><div>标签)
  • 某些标签需要在其后添加换行符(<br>和块级标签如<p><div>是例子)
  • 您必须正确格式化表格。您必须计算列的宽度,考虑colspanrowspan,用空格填充单元格的内容以对齐等。
  • 您必须找到<b><i>等标记的替代标记(如用星号或其他方式将其包围)
  • 您还可以通过在下方和/或上方添加破折号或星号来格式化标题:<h1><h2>等标记
  • 您必须正确格式化<a>标记,即将其转换为格式:Stack Overflow 网站[http://stackoverflow.com]
  • 您必须丢弃<img>标记,并可能用替代文本替换它们(如果存在)
  • 您还必须解码HTML实体(&gt;等)。如果不是Nokogiri,则HTMLEntities gem在这种情况下可能有所帮助

这个列表可以不断延伸。当然,这是没有必要的。

在互联网上有一些库和项目可以实现这个功能,但它们并非为Ruby编写,或者缺少上述功能中的一些。例如:


一旦你解决了这个问题,text/plain 部分的结构与 HTML 部分基本相同。在最开始是你的回复,然后是引用标题和引用的消息。通常格式化为每行都以“>”字符开头。现在有一个问题,你应该粘贴什么内容。

第一种选择是将原始消息的 HTML 部分(通过上述方法)转换并将其作为引用消息粘贴。第二种选择是使用原始消息的 text/plain 部分(如果存在),而不进行任何转换粘贴。后一种选项的好处是,在长时间的交谈中,“>”字符将以树状方式累积。此外,它保留了发件人可能手动组装的纯文本格式,使其更加准确。


3. 总结

根据您的实际需求和想要达到的质量水平,撰写此类邮件的难度可以从简单/棘手到困难不等,特别是如果您需要自己编写所有内容。如果您找到任何Ruby gem可以帮助您完成其中一些任务,请毫不犹豫地使用它们。

组成HTML部分可以像将HTML片段复制并粘贴到彼此中一样容易,最好在此之前删除一些标签。组成纯文本部分可以像完全删除几个标记(<head><script><style>,...)一样容易,同时保留其内容并按顺序解码所有HTML实体。

删除HTML标记可以使用正则表达式完成,但这是强烈反对的做法,并被认为是穷人工具箱中的工具。因此,我建议使用Nokogiri或类似工具来完成此任务。

虽然这不是一个问题的一部分,但我必须强调编写电子邮件客户端的一个方面。您应该始终记得对HTML消息进行清理,特别是您收到的消息。如果入站邮件中出现可疑的iframe或脚本,并且未被垃圾邮件过滤器立即阻止/过滤,则可能是XSS攻击的一部分。在这种情况下,Sanitize宝石可能会证明有用。

干杯


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