email.header: 国际化标头

源代码: Lib/email/header.py


此模块是旧式 (Compat32) 电子邮件 API 的一部分。在当前的 API 中,标头的编码和解码由 EmailMessage 类的类字典 API 透明地处理。除了在旧式代码中使用外,该模块对于需要完全控制编码标头时所用字符集的应用程序也很有用。

本节的其余文本是该模块的原始文档。

RFC 2822 是描述电子邮件格式的基础标准。它源于较早的 RFC 822 标准,该标准在大多数电子邮件仅由 ASCII 字符组成的时代得到广泛使用。RFC 2822 是一个假定电子邮件只包含 7-bit ASCII 字符的规范。

当然,随着电子邮件在全球范围内的部署,它已经变得国际化,现在可以在电子邮件中使用特定语言的字符集。基础标准仍然要求电子邮件仅使用 7-bit ASCII 字符进行传输,因此已经编写了大量的 RFC 来描述如何将包含非 ASCII 字符的电子邮件编码为符合 RFC 2822 的格式。这些 RFC 包括 RFC 2045RFC 2046RFC 2047RFC 2231email 包在其 email.headeremail.charset 模块中支持这些标准。

如果希望在电子邮件标头中包含非 ASCII 字符,例如在 SubjectTo 字段中,则应使用 Header 类,并将 Message 对象中的字段赋值为 Header 的实例,而不是为标头值使用字符串。从 email.header 模块中导入 Header 类。例如:

>>> from email.message import Message
>>> from email.header import Header
>>> msg = Message()
>>> h = Header('p\xf6stal', 'iso-8859-1')
>>> msg['Subject'] = h
>>> msg.as_string()
'Subject: =?iso-8859-1?q?p=F6stal?=\n\n'

请注意我们是如何希望 Subject 字段包含非 ASCII 字符的。我们通过创建一个 Header 实例,并传入字节串所编码的字符集来实现这一点。当随后的 Message 实例被扁平化时,Subject 字段被正确地进行了 RFC 2047 编码。支持 MIME 的邮件阅读器将使用嵌入的 ISO-8859-1 字符显示此标头。

下面是 Header 类的描述:

class email.header.Header(s=None, charset=None, maxlinelen=None, header_name=None, continuation_ws=' ', errors='strict')

创建一个符合 MIME 标准的标头,可以包含不同字符集的字符串。

可选参数 s 是初始标头值。如果为 None(默认值),则不设置初始标头值。之后可以使用 append() 方法调用来追加内容到标头中。s 可以是 bytesstr 的实例,但其语义请参见 append() 的文档。

可选参数 charset 有两个作用:它与 append() 方法的 charset 参数具有相同的含义。它还为所有后续省略 charset 参数的 append() 调用设置默认字符集。如果在构造函数中未提供 charset(默认情况),则 us-ascii 字符集将同时用作 s 的初始字符集和后续 append() 调用的默认字符集。

最大行长度可以通过 maxlinelen 显式指定。为了将第一行拆分得更短(以考虑未包含在 s 中的字段标头,例如 Subject),请在 header_name 中传入字段的名称。默认的 maxlinelen 是 78,而 header_name 的默认值是 None,表示在处理长、分行的标头的第一行时不考虑它。

可选的 continuation_ws 必须是符合 RFC 2822 的折叠空白,通常是空格或硬制表符。此字符将被添加到续行的开头。continuation_ws 默认为单个空格字符。

可选的 errors 参数会直接传递给 append() 方法。

append(s, charset=None, errors='strict')

将字符串 s 附加到 MIME 标头。

可选的 charset 如果给出,应该是一个 Charset 实例(参见 email.charset)或字符集的名称,它将被转换为一个 Charset 实例。值为 None(默认值)意味着使用构造函数中给定的 charset

s 可以是 bytesstr 的实例。如果它是 bytes 的实例,那么 charset 是该字节串的编码,如果字符串无法用该字符集解码,则会引发 UnicodeError

如果 sstr 的实例,那么 charset 是一个提示,指定字符串中字符的字符集。

在任何一种情况下,当使用 RFC 2047 规则生成符合 RFC 2822 标准的标头时,字符串将使用字符集的输出编解码器进行编码。如果字符串无法使用输出编解码器进行编码,则会引发 UnicodeError。

如果 s 是一个字节字符串,可选的 errors 会作为 errors 参数传递给 decode 调用。

encode(splitchars=';, \t', maxlinelen=None, linesep='\n')

将消息标头编码为符合 RFC 的格式,可能会对长行进行换行,并将非 ASCII 部分封装在 base64 或 quoted-printable 编码中。

可选的 splitchars 是一个字符串,包含在正常标头换行期间拆分算法应给予额外权重的字符。这非常粗略地支持 RFC 2822 的“更高级别语法中断”:在拆分行时,以 splitchar 结尾的拆分点更受青睐,字符的偏好顺序按其在字符串中出现的顺序排列。字符串中可以包含空格和制表符,以指示当其他拆分字符未出现在被拆分的行中时,是否应优先选择其中一个作为拆分点。Splitchars 不影响 RFC 2047 编码的行。

如果给定 maxlinelen,它将覆盖实例的最大行长度值。

linesep 指定用于分隔折叠标头行的字符。它默认为对 Python 应用程序代码最有用的值 (\n),但可以指定 \r\n 以生成具有符合 RFC 的行分隔符的标头。

在 3.2 版本发生变更: 添加了 linesep 参数。

Header 类还提供了许多方法来支持标准运算符和内置函数。

__str__()

返回 Header 的近似字符串表示,使用无限行长。所有片段都使用指定的编码转换为 unicode,并适当地连接在一起。任何字符集为 'unknown-8bit' 的片段都将使用 'replace' 错误处理程序作为 ASCII 解码。

在 3.2 版本发生变更: 增加了对 'unknown-8bit' 字符集的处理。

__eq__(other)

此方法允许您比较两个 Header 实例是否相等。

__ne__(other)

此方法允许您比较两个 Header 实例是否不相等。

email.header 模块还提供了以下便捷函数。

email.header.decode_header(header)

解码消息标头值,而不转换字符集。标头值在 header 中。

由于历史原因,此函数可能返回以下任一内容:

  1. 一个包含标头每个已解码部分的元组列表 (decoded_bytes, charset),其中 decoded_bytes 始终是 bytes 的实例,而 charset

    • 包含指定字符集名称的小写字符串。

    • 对于标头的未编码部分,为 None

  2. 一个长度为 1 的列表,包含一个元组 (string, None),其中 string 始终是 str 的实例。

当发生某些解码错误时(例如 base64 解码异常),可能会引发 email.errors.HeaderParseError

以下是示例:

>>> from email.header import decode_header
>>> decode_header('=?iso-8859-1?q?p=F6stal?=')
[(b'p\xf6stal', 'iso-8859-1')]
>>> decode_header('unencoded_string')
[('unencoded_string', None)]
>>> decode_header('bar =?utf-8?B?ZsOzbw==?=')
[(b'bar ', None), (b'f\xc3\xb3o', 'utf-8')]

备注

此函数仅为向后兼容而存在。对于新代码,我们建议使用 email.headerregistry.HeaderRegistry

email.header.make_header(decoded_seq, maxlinelen=None, header_name=None, continuation_ws=' ')

decode_header() 返回的元组序列创建一个 Header 实例。

decode_header() 接受一个标头值字符串,并返回一个格式为 (decoded_string, charset) 的元组序列,其中 charset 是字符集的名称。

此函数接受这样一个元组序列,并返回一个 Header 实例。可选的 maxlinelenheader_namecontinuation_wsHeader 构造函数中的相同。

备注

此函数仅为向后兼容而存在,不建议在新代码中使用。