【问题标题】:Python email header strange behaviorPython电子邮件标题奇怪的行为
【发布时间】:2019-02-19 12:55:10
【问题描述】:

python2.7 或 python3 的 Python 电子邮件标头解码器在编码和未编码文本之间切换时似乎有一些奇怪的行为。

from email.header import decode_header
print decode_header("=?ISO-8859-1?B?QA==?=example.com");
print decode_header("=?ISO-8859-1?B?QA==?= example.com");
print decode_header("=?ISO-8859-1?Q?=40example?= .com");
print decode_header("=?ISO-8859-1?Q?=40example?=.com");

这是结果

[('=?ISO-8859-1?B?QA==?=example.com', None)]
[('@', 'iso-8859-1'), ('example.com', None)]
[('@example', 'iso-8859-1'), ('.com', None)]
[('=?ISO-8859-1?Q?=40example?=.com', None)]

在所有示例输入中,编码文本只是 @ 符号,它应该得到正确解释,但事实并非如此。我认为 RFC 1342 的解释对我来说似乎不正确。 Python 期望空格或换行符作为编码文本的结尾。我在 RFC 中没有看到这一点,RFC 只说在我阅读它时多个编码文本之间需要空间,而不是在文本的编码文本和未编码部分之间需要空间。因此,每当您看到“?=”时,您都需要将其视为 Python 不做的编码文本的结尾。我想问专家这是否是这里的错误或者我是否弄错了?

维杰

【问题讨论】:

  • 您的问题只能在 Python 2.7 中重现。我在 3.x 中运行了您的代码并得到了正确的结果。一定是2.7的bug。作为旁注,不要在行尾添加分号,它们在任何版本的 Python 中都不是必需的。
  • 更正我之前的评论:显然,2.7 产生了正确的结果,但 3.x 没有。

标签: python python-2.7 email-headers


【解决方案1】:

RFC 2047 定义了 3 个可能出现“编码字”的位置。它几乎在所有情况下都需要分隔空格,即使在“编码字”和未编码文本之间也是如此,并且大多数不需要分隔空格的情况似乎是错误的。文本如下所示(未应用errata,并手动调整格式):

“编码词”可能出现在邮件标题或正文部分 根据以下规则标头:

  1. “编码字”可以替换“文本”标记(由 RFC 822 定义) 在任何主题或评论标题字段中,任何扩展消息 标头字段,或任何 MIME 正文部分字段,其字段正文 被定义为“*文本”。一个“编码字”也可能出现在任何 用户定义的(“X-”)消息或正文部分标头字段。

    普通的 ASCII 文本和 'encoded-word' 可能一起出现在 相同的标题字段。 *但是,出现在 定义为 'text' 的标头字段必须与任何相邻的 'encoded-word' or 'text' by 'linear-white-space'。

  2. “编码词”可能出现在由“(”分隔的“评论”中,并且 ")",即允许使用 'ctext' 的地方。更准确地说,RFC 822 ABNF 对“评论”的定义修改如下:

     comment = "(" *(ctext / quoted-pair / comment / encoded-word) ")"
    

    不得出现在“评论”中的“Q”编码“编码字” 包含字符“(”、“)”或“ 'comment' 中出现的'encoded-word' 必须与 任何相邻的 'encoded-word' 或 'ctext' by 'linear-white-space'。

    请务必注意,“评论”仅在内部被识别 “结构化”场体。在其主体定义为的字段中 '*text'、"(" 和 ")" 被视为普通字符而不是 注释分隔符,并且适用本节的规则 (1)。 (见 RFC 822,第 3.1.2 和 3.1.3 节)

  3. 作为“短语”中“单词”实体的替代品,例如, 在 From、To 或 Cc 标头中的地址之前的一个。 ABNF 因此,RFC 822 中“短语”的定义变为:

     phrase = 1*( encoded-word / word )
    

    在这种情况下,可以在“Q”编码中使用的字符集 “编码字”仅限于:<upper and lower case ASCII letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" (underscore, ASCII 95.)>出现在 “短语”必须与任何相邻的“单词”、“文本”或 '线性空白'的'特殊'。

【讨论】:

  • 然而,Python 3.x“正确地”(虽然,不可否认,非法)解码没有线性空白分隔符的标头。
  • 感谢您的详细阅读和澄清。一些进行转发的电子邮件用户代理似乎只编码“@”符号,并且不同的网络邮件软件显示不同的输出。我认为这是因为在这些奇怪的情况下,在 Perl、PHP、Python(版本)之间我看到了不同的行为。看起来 Python 2.7 的行为接近正常!
【解决方案2】:

这是RFC1342的第6页:

编码词可以与普通的“词”、“文本”、 或“ctext”,如下所示:编码字以“=?”开头,以“=?”结尾 “?=”,正好包含四个“?”包括分隔符的字符, 并且后跟空格或换行符。如果“单词”、“文本”或 "ctext" 不符合上述测试,应该显示为 出现在邮件标题中。

所以 spacenewline 在编码文本之后是必需的。

来自同一 RFC 的编码标头示例:

   From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>
   To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>
   CC: =?ISO-8859-1?Q?Andr=E9_?= Pirard <PIRARD@vm1.ulg.ac.be>
   Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
    =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=

【讨论】:

  • 虽然 RFC 已经过时,但它确实展示了编码词后跟空格的一般意图。在后来的 RFC 中,空格问题似乎变得更加复杂。
猜你喜欢
  • 2013-04-18
  • 2017-04-09
  • 2017-05-09
  • 1970-01-01
  • 2011-12-26
  • 2013-10-19
  • 2011-02-27
  • 1970-01-01
  • 2012-12-24
相关资源
最近更新 更多