Rails - 邮件,将正文作为纯文本获取

Posted

技术标签:

【中文标题】Rails - 邮件,将正文作为纯文本获取【英文标题】:Rails - Mail, getting the body as Plain Text 【发布时间】:2011-06-19 14:04:13 【问题描述】:

给定:message = Mail.new(params[:message])

如此处所示:http://docs.heroku.com/cloudmailin

它展示了如何将 message.body 获取为 html,如何获取纯文本版本?

谢谢

【问题讨论】:

【参考方案1】:

以上代码:

message = Mail.new(params[:message])

将从完整消息中创建mail gem 的新实例。然后,您可以使用该消息上的任何方法来获取内容。因此,您可以使用以下方法获取纯内容:

message.text_part

或带有

的HTML
message.html_part

这些方法只会猜测并找到 text/plain 或 text/html 内容类型的多部分消息中的第一部分。 CloudMailin 还通过 params[:plain] 和 params[:html] 提供了这些便利方法。值得记住的是,消息永远不能保证包含纯文本或 html 部分。可能值得使用以下内容来确定:

plain_part = message.multipart? ? (message.text_part ? message.text_part.body.decoded : nil) : message.body.decoded
html_part = message.html_part ? message.html_part.body.decoded : nil

附带说明,当您使用这些方法时,从消息中提取内容编码也很重要,并确保将输出编码为您想要的编码方法(例如 UTF-8)。

【讨论】:

谢谢!我在解码后解析电子邮件时遇到了一些问题,但获取 text_part 有助于解决此问题。 优秀的答案。我必须说这适用于默认的 Rails Action Mailer。不需要任何邮件宝石。 如何提取编码?我在做这个 ..force_encoding("ISO-8859-1").encode('utf_8') 和一些消息工作,在其他人不这样做。 @David "default Rails Action Mailer" mail gem。至少,很大程度上取决于它。 天哪,谢谢。难怪我之前错过了,它在Message类的第1600+行。【参考方案2】:

什么是Mail

问题中定义的message 似乎是同一MailMail::Message 类的实例,该类也用于ActionMailer::Base 或mailman gem。

我不确定这是在哪里集成到 Rails 中的,但 Steve Smith has pointed out 这是在 mail gem 中定义的。

Usage Section of the gem's readme on github。 Documentation of Mail::Message on rubydoc.info。

从多部分电子邮件中提取部分

在 gem 的自述文件中,有一个 example section on reading multipart emails。

除了html_parttext_part 方法simply find the first part of the corresponding mime type 之外,还可以手动访问和循环访问部件,并根据需要按条件过滤。

message.parts.each do |part|
  if part.content_type == 'text/plain'
    # ...
  elsif part.content_type == 'text/html'
    # ...
  end 
end

Mail::Part 是 documented here。

编码问题

根据收到邮件的来源,可能存在编码问题。例如,rails 可以识别错误的编码类型。然后,如果尝试将正文转换为 UTF-8 以便将其存储在数据库中 (body_string.encode('UTF-8')),则可能会出现编码错误,例如

Encoding::UndefinedConversionError - "\xFC" from ASCII-8BIT to UTF-8

(如this SO question)。

为了避免这种情况,可以从消息部分读出字符集,并告诉 Rails 在编码为 UTF-8 之前它是什么字符集:

encoding = part_to_use.content_type_parameters['charset']
body = part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8')

这里,decoded 方法删除了标题行,如encoding section of the mail gem's readme 所示。

编辑:硬编码问题

如果真的有硬编码问题,前一种方法解决不了,看看优秀的charlock_holmes gem。

将此 gem 添加到 Gemfile 后,有一种更可靠的方法来转换电子邮件编码,使用 detect_encoding 方法,该方法由此 gem 添加到 Strings。

我发现为邮件消息定义一个body_in_utf8 方法很有帮助。 (Mail::Part 也继承自 Mail::Message。):

module Mail
  class Message
    def body_in_utf8
      require 'charlock_holmes/string'
      body = self.body.decoded
      if body.present?
        encoding = body.detect_encoding[:encoding]
        body = body.force_encoding(encoding).encode('UTF-8')
      end
      return body
    end
  end
end

总结

# select the part to use, either like shown above, or as one-liner
part_to_use = message.html_part || message.text_part || message

# readout the encoding (charset) of the part
encoding = part_to_use.content_type_parameters['charset'] if part_to_use.content_type_parameters

# get the message body without the header information
body = part_to_use.body.decoded

# and convert it to UTF-8
body = body.force_encoding(encoding).encode('UTF-8') if encoding

编辑:或者,定义一个body_in_utf8方法后,如上图,同单行:

(message.html_part || message.text_part || message).body_in_utf8

【讨论】:

说真的??像这样的答案需要一个特殊的质量印章。 多么棒的答案。非常感谢!! 这么好的答案,谢谢。处理电子邮件是一个真正令人头疼的 80/20。【参考方案3】:
email = Mail.new(params[:message])
text_body = (email.text_part || email.html_part || email).body.decoded

我在RedmineCRM Helpdesk plugin使用这个解决方案

【讨论】:

【参考方案4】:

我相信,如果您调用 message.text_part.body.decoded,您会通过 Mail gem 为您将其转换为 UTF-8,但文档并没有 100% 清楚地说明这一点。

【讨论】:

不,它没有。它返回一个类似\xF0\xD2\x12... 的字符串【参考方案5】:

在 Rails 中保存 HTML 正文格式 使用 这会将在电子邮件文本编辑器中编写的文本按原样发送到电子邮件。

【讨论】:

是的...html_safe 在用户提供的内容上,结果不会很好(XSS)

以上是关于Rails - 邮件,将正文作为纯文本获取的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 System.NET.mail 发送带有附件但没有任何纯文本正文的电子邮件?

EWS 正文纯文本

只获取 MIME 电子邮件的“文本/纯文本”部分

如何从 Node.js IMAP 模块中的正文获取纯文本

flask 电子邮件进阶实践-用模板发送163邮件

php从邮件正文中提取文本/纯文本