【问题标题】:What data type to store raw IMAP fetched email messages in Postgresql?在 Postgresql 中存储原始 IMAP 获取的电子邮件消息的数据类型是什么?
【发布时间】:2017-07-18 19:42:54
【问题描述】:

我需要在从 IMAP 获取电子邮件消息后立即将其存储在数据库中以供以后处理。我使用FETCH 请求提取消息,并使用BODY.PEEK[] 返回数据。

据我了解,所有 IMAP 邮件都以US-ASCII 的形式返回(邮件服务器只接受那个),但我可能是错的。

我的选择(按照我认为正确的顺序)是:

  • US-ASCII 文本列
  • 字节亚
  • BLOB

我正在考虑使用 US-ASCII,但我担心编码有问题,我不知道是否有“故障”IMAP 服务器没有返回 us-ascii 邮件。 另一种选择是 Bytea,但我读到您必须处理编码,所以我不确定与 US-ASCII 相比有什么优势/劣势。 BLOB 是原始的,我不确定它在这种情况下会带来什么问题。我假设我必须处理字节到字符串的转换。

推荐的数据类型是什么?

【问题讨论】:

  • 你使用什么库/语言?
  • 可以使用 UTF-8 编码的文本吗?
  • 经典电子邮件假定为 US_AScii,但实际上并非如此,并且可以包含高字节字符。解释取决于标题,因此文本类型不合适。
  • 我使用 Ruby 作为语言并使用net/imapuid_fetch 下载消息。我使用FetchData#attr["BODY[]"] 获取整个消息,到目前为止,该字符串始终编码为us-ascii。我不需要对该文本执行任何操作,稍后将其取回、解析并创建它的“可用”版本
  • @Fire-Dragon-DoL 是的。符合标准的电子邮件是(曾经)7 位 US-ASCII。大量电子邮件不完全符合标准。 8 位的东西潜入其中。它们应该存储为非文本数据。此外,8 位电子邮件已经出现多年(请参阅 SMTPUTF8 和 IMAP UTF8 扩展)。此外,很少有邮件服务器会直接拒绝包含 8 位内容的邮件,即使未声明也是如此。

标签: postgresql email imap


【解决方案1】:

对于电子邮件等小对象,我认为使用 Bytea 会更好。存储和处理是不同的,因为你的对象会很小,看起来它会像字节茶一样处理得更好。请参阅here 以了解 Microolap 对两者的比较。这不是您问题的完整答案,但可能会从列表中删除一个选项。

【讨论】:

  • 该链接对“程序员认为是原始字节”的描述很有帮助!
  • 是的,您不应该假设电子邮件缺少 NULL 字节、正确编码、正确声明编码、不混合编码等。bytea 是 IMO 唯一正确的选择。
【解决方案2】:

您做出了一个非常没有根据的假设,即您可以避免处理编码。

你不能。

无论您使用 lob、bytea 还是您假设仅包含 7 位邮件的 text 列...邮件只是任意二进制数据。你不知道它的文本编码。实际上,邮件客户端一直使用 8 位编码;通过 MIME 引用打印符合标准,或者通常只是原始的 8 位文本。

甚至已知某些客户端包含包含空(零)字节的完整 8 位 MIME 段。 PostgreSQL 不会在 text 列中容忍这种情况。

但即使对于使用兼容 MIME、可引用打印的转义文本主体等的客户,邮件也可能包含非 ASCII 字符,它们只是被转义了。索引这些并忽略转义将产生奇怪和错误的结果。此外,附件通常是任意 base64 数据。将其作为文本进行索引是完全没有意义的。然后是所有的 HTML 正文、多部分/替代段、CSS 等......

在处理电子邮件时,假设客户端或服务器可能做错的任何事情,它都会做错。对于存储,将电子邮件视为未知编码的原始字节。这正是bytea 的用途。

如果您想对邮件进行任何操作,您需要一个防御性的 MIME 解析器,它可以提取 MIME 部分、处理损坏的部分等。它需要检查声明的编码(如果有的话)针对实际的 mime 部分主体,如果没有声明或声明的编码明显错误,则猜测编码。它必须处理各种伪造的 MIME 结构和内容;不是真正可引用打印的引用打印体,等等。

因此,如果您打算索引这封电子邮件,那绝对不是“创建全文索引并愉快地继续”那么简单。问题不是 if 它会失败,而是 when

就个人而言,如果我必须这样做(如果我可以选择不这样做),我会将原始电子邮件存储为 bytea。然后对于搜索,我将其分解为 MIME 部分,检测类似文本的部分,进行编码检测和取消引用等,并将解码和清理的文本主体注入单独的表中以进行文本索引。

有一些有用的 Perl 模块可以通过plperlu 使用,但我可能会在外部脚本/工具中使用。然后,您可以选择 MIME 处理器、语言等。

【讨论】:

  • 嘿 Craig,我认为你误会了,我只需要存储原始消息。没有索引或任何目的,只是纯粹的存储。消息的实际解码发生在稍后的时间点,我从数据库中获取这个原始字节流,用一个库做一些邮件解析魔法,只有在这一点上,我有一些是文本的东西,具有适当的编码。因此,我正在寻找仅将最原始的数据版本存储在数据库中,以便稍后对其进行操作。根据您的回答,似乎 bytea 就足够了,谢谢
  • 是的,bytea 绝对是正确的选择。
猜你喜欢
  • 2012-05-04
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 1970-01-01
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多