在 Postgresql 中存储原始 IMAP 获取的电子邮件消息的数据类型是什么?
What data type to store raw IMAP fetched email messages in Postgresql?
我需要在从 IMAP 中提取电子邮件后立即将其存储在数据库中以供以后处理。我使用 FETCH
请求提取消息,并使用 BODY.PEEK[]
.
返回数据
根据我的理解,所有 IMAP 邮件都返回为 US-ASCII
(邮件服务器只接受那个),但我可能是错的。
我的选择(按照我认为正确的顺序)是:
- US-ASCII 文本列
- 字节茶
- BLOB
我正在考虑使用 US-ASCII 但我担心编码有问题,我不知道是否有 "faulty" IMAP 服务器不返回 us-ascii 邮件。
替代方案是 Bytea,但我读到您必须处理编码,所以我不确定 US-ASCII 上的 advantage/disadvantage 是什么。
BLOB 是原始的,我不确定它在这种情况下会带来什么问题。我假设我必须处理字节到字符串的转换。
推荐的数据类型是什么?
对于诸如电子邮件之类的小对象,我认为使用 Bytea 会更好。存储和处理是不同的,并且由于您的对象将变得很小,因此它似乎会像 Bytea 一样得到更好的处理。有关 Microolap 对两者的比较,请参阅 here。这不是您问题的完整答案,但可能会从列表中删除一个选项。
您做出了非常没有根据的假设,即您可以避免处理编码。
你不能。
无论您使用 lob、bytea 还是您假设仅包含 7 位邮件的 text
列...邮件只是任意二进制数据。你不知道它的文本编码。实际上,邮件客户端一直使用 8 位编码; standards-compliant 通过 MIME quoted-printable,或者通常只是原始的 8 位文本。
一些客户端甚至已知包含包含空(零)字节的完整 8 位 MIME 段。 PostgreSQL 不会在 text
列中容忍这种情况。
但即使对于使用兼容 MIME、quoted-printable 转义文本正文等的客户端...邮件可能包含 non-ASCII 个字符,它们只是被转义了。索引这些并忽略转义将产生奇怪和错误的结果。此外,附件通常是任意的 base64 数据。将其索引为文本是完全没有意义的。然后是所有 HTML 身体,multi-part/alternative 片段,CSS,等等...
处理电子邮件时,假设客户端或服务器可能做错的任何事情,它都会做错。对于存储,将电子邮件视为未知编码的原始字节。这正是 bytea
的用途。
如果你想对邮件做任何事情,你需要一个防御性 MIME 解析器,它可以提取 MIME 部分,处理损坏的部分等。它需要根据实际 mime-part body 检查声明的编码(如果有),如果声明了 none 或声明的编码明显错误,则猜测编码。它必须处理各种伪造的 MIME 结构和内容; quoted-printable 并不是真正的 quoted-printable 的身体,等等。
所以如果你打算索引这封邮件,那绝对不是"create a fulltext index and merrily carry on"那么简单。问题不是 if 它会失败,而是 when.
就我个人而言,如果我必须这样做(如果有选择我不会),我会将原始电子邮件存储为 bytea。然后为了搜索,我将其分解为 MIME 部分,检测 text-like 部分,进行编码检测和反引用等,并将解码和清理的文本主体注入单独的 table 用于文本索引。
有一些有用的 Perl 模块可以通过 plperlu
使用,但我可能会在外部 script/tool 中使用。然后您可以选择 MIME 处理器、语言等。
我需要在从 IMAP 中提取电子邮件后立即将其存储在数据库中以供以后处理。我使用 FETCH
请求提取消息,并使用 BODY.PEEK[]
.
根据我的理解,所有 IMAP 邮件都返回为 US-ASCII
(邮件服务器只接受那个),但我可能是错的。
我的选择(按照我认为正确的顺序)是:
- US-ASCII 文本列
- 字节茶
- BLOB
我正在考虑使用 US-ASCII 但我担心编码有问题,我不知道是否有 "faulty" IMAP 服务器不返回 us-ascii 邮件。 替代方案是 Bytea,但我读到您必须处理编码,所以我不确定 US-ASCII 上的 advantage/disadvantage 是什么。 BLOB 是原始的,我不确定它在这种情况下会带来什么问题。我假设我必须处理字节到字符串的转换。
推荐的数据类型是什么?
对于诸如电子邮件之类的小对象,我认为使用 Bytea 会更好。存储和处理是不同的,并且由于您的对象将变得很小,因此它似乎会像 Bytea 一样得到更好的处理。有关 Microolap 对两者的比较,请参阅 here。这不是您问题的完整答案,但可能会从列表中删除一个选项。
您做出了非常没有根据的假设,即您可以避免处理编码。
你不能。
无论您使用 lob、bytea 还是您假设仅包含 7 位邮件的 text
列...邮件只是任意二进制数据。你不知道它的文本编码。实际上,邮件客户端一直使用 8 位编码; standards-compliant 通过 MIME quoted-printable,或者通常只是原始的 8 位文本。
一些客户端甚至已知包含包含空(零)字节的完整 8 位 MIME 段。 PostgreSQL 不会在 text
列中容忍这种情况。
但即使对于使用兼容 MIME、quoted-printable 转义文本正文等的客户端...邮件可能包含 non-ASCII 个字符,它们只是被转义了。索引这些并忽略转义将产生奇怪和错误的结果。此外,附件通常是任意的 base64 数据。将其索引为文本是完全没有意义的。然后是所有 HTML 身体,multi-part/alternative 片段,CSS,等等...
处理电子邮件时,假设客户端或服务器可能做错的任何事情,它都会做错。对于存储,将电子邮件视为未知编码的原始字节。这正是 bytea
的用途。
如果你想对邮件做任何事情,你需要一个防御性 MIME 解析器,它可以提取 MIME 部分,处理损坏的部分等。它需要根据实际 mime-part body 检查声明的编码(如果有),如果声明了 none 或声明的编码明显错误,则猜测编码。它必须处理各种伪造的 MIME 结构和内容; quoted-printable 并不是真正的 quoted-printable 的身体,等等。
所以如果你打算索引这封邮件,那绝对不是"create a fulltext index and merrily carry on"那么简单。问题不是 if 它会失败,而是 when.
就我个人而言,如果我必须这样做(如果有选择我不会),我会将原始电子邮件存储为 bytea。然后为了搜索,我将其分解为 MIME 部分,检测 text-like 部分,进行编码检测和反引用等,并将解码和清理的文本主体注入单独的 table 用于文本索引。
有一些有用的 Perl 模块可以通过 plperlu
使用,但我可能会在外部 script/tool 中使用。然后您可以选择 MIME 处理器、语言等。