在 Ruby 中格式化电子邮件回复
Format Email Reply in Ruby
我正在 ruby 中制作我自己的电子邮件客户端,它目前可以 parse/read-in 消息。它还可以创建对消息的回复,设置 headers,并将消息发送给原始发件人。
如何将引用的原始消息添加到回复中?
我应该如何格式化回复中的原始消息?是否有最佳实践或格式? MIME/RFC?我知道 HTML 和文本应该有一个字符串。只是不确定如何制作这些字符串。
现在我的回复没有下面的原始消息,很难自行理解。
撰写电子邮件回复是一项相当大的挑战,尤其是在一开始您不知道从哪里开始的时候。
最近我不得不编写此类电子邮件并以编程方式发送。我首先做的是看看电子邮件客户端是如何做到这一点的,比如 Thunderbird。不过,这需要一些实验和耐心。
我使用的消息的整体结构很大程度上基于这个 Stack Overflow 答案:https://whosebug.com/a/23853079/1368043
1。 HTML部分
请注意,您没有几个选择:要么编写 HTML 片段(典型 <body>
标签的内容),要么编写整个 HTML 文档(使用 <html>
、<head>
和 <body>
标签)。我看了一下 Thunderbird 是如何做到的。原来它创建了整个文档,大致是这样生成的:
- 创建 HTML 文档
- 在
<head>
部分添加元信息 <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
(将字符集替换为您喜欢的字符集)
- 在
<body>
部分添加您编写的 HTML 片段,添加引用的标题(例如:“<div>Few days ago, John Smith wrote: </div>
”)并添加 <blockquote>
块紧随其后:<blockquote cite="mid:originalmessagemid@example.com" type="cite">
。请注意,原始消息有一个消息 ID。
这是我不太喜欢 Thunderbird 的部分:
- 复制原始消息的 HTML 内容并将其粘贴到
<blockquote>
块中。
Thunderbird 并不真正检查复制的 HTML 是片段还是文档。但是,如果它是一个文档,它会去除 <html>
和 <head>
标签......同时保留它们的内容。结果,您可以看到原始邮件 <head>
部分中的 <style>
和 <title>
标记位于新邮件的 <body>
标记中。太乱了。
此外,Thunderbird 不处理全局样式。您可以轻松地使用全局样式而不是内联样式来撰写棘手的邮件,当邮件的收件人开始撰写回复时,样式会渗透到整个邮件中。
你也可以做同样的事情。它并没有真正伤害到任何人,它们只是典型邮件通常不会观察到的怪癖。另外这很容易。或者你可以更进一步清理这个烂摊子。
首先,您必须让自己拥有任何 HTML 解析器。我用的是Nokogiri,我的使用方法是这样的:
- 它会自动将任何片段转换为HTML文档,因此无需分别分析片段和文档
- 在文档中找到
<body>
标签并复制其内容
- 删除找到的任何
<style>
个标签
- 将结果复制到需要的地方
大致如下所示:
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 部分还要棘手。毕竟,您必须编写一个简单的渲染引擎(就像任何其他网络浏览器一样)。可能有 gems,不幸的是我当时找不到。
虽然有几个要点可以帮助您入门:
- 所有换行符(\r\n 或 \n)应替换为单个 space
- 所有多个 space 都应减少为一个(除非它们是 non-breaking)
- 某些标签会保留内容而其他标签不会(例如
<style>
或 <script>
标签与 <b>
或 <div>
)
- 某些标签需要在它们之后换行(
<br>
和 <p>
和 <div>
等块标签就是示例)
- 您必须正确格式化 table。您必须计算列的宽度,考虑
colspan
s 和 rowspan
s,用 spaces 填充单元格的内容以对齐它们等
- 您必须为
<b>
、<i>
、... 标签找到替代标记(例如用星号或诸如此类的东西包围它们)
- 您还可以格式化标题:
<h1>
、<h2>
、...标签,方法是在 and/or 上方 下面添加破折号或星号
- 您必须正确格式化
<a>
标签,即将它们转换成以下格式:Stack Overflow site [http://whosebug.com]
- 您必须丢弃
<img>
标签,并可能用替代文本替换它们(如果存在)
- 您还必须解码 HTML 个实体(
>
等)。如果不是 Nokogiri,HTMLEntities gem 在这种情况下可能会有所帮助
这个列表可以继续下去。当然不用了
Internet 上有一些库和项目可以执行此操作,但它们不是为 Ruby 编写的and/or 他们缺少上面列出的一些功能。例如:
- http://www.codeproject.com/Articles/11902/Convert-HTML-to-Plain-Text (C#)
- https://www.npmjs.com/package/html-to-text (node.js)
一旦你解决了这个问题,text/plain
部分的结构实际上与 HTML 部分相同。一开始就有你的回复。然后是引用标题,然后是引用的消息。它的格式通常是每行前面都有“>”字符。现在,问题是您究竟应该在其中粘贴什么内容。
第一个选项是转换原始消息的 HTML 部分(通过上述方法)并将其粘贴为引用的消息。第二种方法是使用原始消息的 text/plain
部分(如果存在)并在不进行任何转换的情况下粘贴它。后一种选择的好处是,长时间对话中的“>”字符将在时间后以树状方式累积。此外,它还保留了发件人可能手动组装的纯文本格式,以使其更加准确。
3。摘要
根据您的实际需要和想要达到的质量水平,撰写此类邮件的难度从 easy/tricky 到困难不等,特别是如果您必须自己编写所有代码.如果您碰巧发现任何 Ruby gem 至少可以帮助您完成其中的某些任务,请不要犹豫并使用它们。
编写 HTML 部分就像相互复制和粘贴 HTML 部分一样简单,最好事先剥离一些标签。编写纯文本部分就像完全删除几个标签一样简单(<head>
、<script>
、<style>
、...),在保留内容的同时剥离所有标签并解码所有 HTML 个实体,按此顺序。
删除 HTML 标签可以使用正则表达式来完成,但它是 strongly discouraged 并且被认为是穷人工具箱中的工具。所以我建议为此目的使用 Nokogiri 或类似的东西。
虽然这不是问题的一部分,但我必须强调编写电子邮件客户端的一个方面。您应该始终记得清理您的HTML消息,尤其是您收到的消息。在收到的邮件中可疑地查看 iframe 或脚本没有什么好处,如果垃圾邮件过滤器没有立即 blocked/filtered,它们可能是 XSS 攻击的一部分。在这种情况下,Sanitize gem 可能有用。
干杯
我正在 ruby 中制作我自己的电子邮件客户端,它目前可以 parse/read-in 消息。它还可以创建对消息的回复,设置 headers,并将消息发送给原始发件人。
如何将引用的原始消息添加到回复中?
我应该如何格式化回复中的原始消息?是否有最佳实践或格式? MIME/RFC?我知道 HTML 和文本应该有一个字符串。只是不确定如何制作这些字符串。
现在我的回复没有下面的原始消息,很难自行理解。
撰写电子邮件回复是一项相当大的挑战,尤其是在一开始您不知道从哪里开始的时候。
最近我不得不编写此类电子邮件并以编程方式发送。我首先做的是看看电子邮件客户端是如何做到这一点的,比如 Thunderbird。不过,这需要一些实验和耐心。
我使用的消息的整体结构很大程度上基于这个 Stack Overflow 答案:https://whosebug.com/a/23853079/1368043
1。 HTML部分
请注意,您没有几个选择:要么编写 HTML 片段(典型 <body>
标签的内容),要么编写整个 HTML 文档(使用 <html>
、<head>
和 <body>
标签)。我看了一下 Thunderbird 是如何做到的。原来它创建了整个文档,大致是这样生成的:
- 创建 HTML 文档
- 在
<head>
部分添加元信息<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
(将字符集替换为您喜欢的字符集) - 在
<body>
部分添加您编写的 HTML 片段,添加引用的标题(例如:“<div>Few days ago, John Smith wrote: </div>
”)并添加<blockquote>
块紧随其后:<blockquote cite="mid:originalmessagemid@example.com" type="cite">
。请注意,原始消息有一个消息 ID。
这是我不太喜欢 Thunderbird 的部分:
- 复制原始消息的 HTML 内容并将其粘贴到
<blockquote>
块中。
Thunderbird 并不真正检查复制的 HTML 是片段还是文档。但是,如果它是一个文档,它会去除 <html>
和 <head>
标签......同时保留它们的内容。结果,您可以看到原始邮件 <head>
部分中的 <style>
和 <title>
标记位于新邮件的 <body>
标记中。太乱了。
此外,Thunderbird 不处理全局样式。您可以轻松地使用全局样式而不是内联样式来撰写棘手的邮件,当邮件的收件人开始撰写回复时,样式会渗透到整个邮件中。
你也可以做同样的事情。它并没有真正伤害到任何人,它们只是典型邮件通常不会观察到的怪癖。另外这很容易。或者你可以更进一步清理这个烂摊子。
首先,您必须让自己拥有任何 HTML 解析器。我用的是Nokogiri,我的使用方法是这样的:
- 它会自动将任何片段转换为HTML文档,因此无需分别分析片段和文档
- 在文档中找到
<body>
标签并复制其内容 - 删除找到的任何
<style>
个标签 - 将结果复制到需要的地方
大致如下所示:
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 部分还要棘手。毕竟,您必须编写一个简单的渲染引擎(就像任何其他网络浏览器一样)。可能有 gems,不幸的是我当时找不到。
虽然有几个要点可以帮助您入门:
- 所有换行符(\r\n 或 \n)应替换为单个 space
- 所有多个 space 都应减少为一个(除非它们是 non-breaking)
- 某些标签会保留内容而其他标签不会(例如
<style>
或<script>
标签与<b>
或<div>
) - 某些标签需要在它们之后换行(
<br>
和<p>
和<div>
等块标签就是示例) - 您必须正确格式化 table。您必须计算列的宽度,考虑
colspan
s 和rowspan
s,用 spaces 填充单元格的内容以对齐它们等 - 您必须为
<b>
、<i>
、... 标签找到替代标记(例如用星号或诸如此类的东西包围它们) - 您还可以格式化标题:
<h1>
、<h2>
、...标签,方法是在 and/or 上方 下面添加破折号或星号
- 您必须正确格式化
<a>
标签,即将它们转换成以下格式:Stack Overflow site [http://whosebug.com]
- 您必须丢弃
<img>
标签,并可能用替代文本替换它们(如果存在) - 您还必须解码 HTML 个实体(
>
等)。如果不是 Nokogiri,HTMLEntities gem 在这种情况下可能会有所帮助
这个列表可以继续下去。当然不用了
Internet 上有一些库和项目可以执行此操作,但它们不是为 Ruby 编写的and/or 他们缺少上面列出的一些功能。例如:
- http://www.codeproject.com/Articles/11902/Convert-HTML-to-Plain-Text (C#)
- https://www.npmjs.com/package/html-to-text (node.js)
一旦你解决了这个问题,text/plain
部分的结构实际上与 HTML 部分相同。一开始就有你的回复。然后是引用标题,然后是引用的消息。它的格式通常是每行前面都有“>”字符。现在,问题是您究竟应该在其中粘贴什么内容。
第一个选项是转换原始消息的 HTML 部分(通过上述方法)并将其粘贴为引用的消息。第二种方法是使用原始消息的 text/plain
部分(如果存在)并在不进行任何转换的情况下粘贴它。后一种选择的好处是,长时间对话中的“>”字符将在时间后以树状方式累积。此外,它还保留了发件人可能手动组装的纯文本格式,以使其更加准确。
3。摘要
根据您的实际需要和想要达到的质量水平,撰写此类邮件的难度从 easy/tricky 到困难不等,特别是如果您必须自己编写所有代码.如果您碰巧发现任何 Ruby gem 至少可以帮助您完成其中的某些任务,请不要犹豫并使用它们。
编写 HTML 部分就像相互复制和粘贴 HTML 部分一样简单,最好事先剥离一些标签。编写纯文本部分就像完全删除几个标签一样简单(<head>
、<script>
、<style>
、...),在保留内容的同时剥离所有标签并解码所有 HTML 个实体,按此顺序。
删除 HTML 标签可以使用正则表达式来完成,但它是 strongly discouraged 并且被认为是穷人工具箱中的工具。所以我建议为此目的使用 Nokogiri 或类似的东西。
虽然这不是问题的一部分,但我必须强调编写电子邮件客户端的一个方面。您应该始终记得清理您的HTML消息,尤其是您收到的消息。在收到的邮件中可疑地查看 iframe 或脚本没有什么好处,如果垃圾邮件过滤器没有立即 blocked/filtered,它们可能是 XSS 攻击的一部分。在这种情况下,Sanitize gem 可能有用。
干杯