Skip to main content

19.1.6. email.headerregistry:自定义标题对象

源代码: Lib/email/headerregistry.py


3.6 新版功能: [1]

标题由 str 的定制子类表示。用于表示给定报头的特定类由创建报头时有效的 policyheader_factory 确定。本节记录电子邮件包实现的特定 header_factory,用于处理符合 RFC 5322 的电子邮件,这不仅为各种标题类型提供自定义标题对象,而且为应用程序添加自己的自定义标题类型提供了扩展机制。

当使用从 EmailPolicy 派生的任何策略对象时,所有头都由 HeaderRegistry 生成,并具有 BaseHeader 作为它们的最后一个基类。每个头类都有一个额外的基类,由头的类型决定。例如,许多头部具有类 UnstructuredHeader 作为它们的其他基类。头的专用第二类由头的名称确定,使用存储在 HeaderRegistry 中的查找表。所有这些对于典型的应用程序是透明地管理的,但是提供了接口来修改默认行为以供更复杂的应用使用。

下面的部分首先记录头部基类及其属性,然后是用于修改 HeaderRegistry 行为的API,最后是用于表示从结构化头部解析的数据的支持类。

class email.headerregistry.BaseHeader(name, value)

namevalueheader_factory 调用传递给 BaseHeader。任何头对象的字符串值是 value 完全解码为unicode。

此基类定义以下只读属性:

name

标题的名称(“:”前的字段部分)。这正是在 nameheader_factory 调用中传递的值;也就是说,情况被保留。

defects

一个 HeaderDefect 实例的元组,报告解析期间发现的任何RFC合规性问题。电子邮件包尝试完全关于检测合规性问题。有关可能报告的缺陷类型的讨论,请参阅 errors 模块。

max_count

此类型的可以具有相同 name 的标头的最大数量。 None 的值表示无限制。此属性的 BaseHeader 值为 None;预期专用头部类将根据需要覆盖此值。

BaseHeader 还提供了以下方法,它由电子邮件库代码调用,并且一般不应用程序调用:

fold(*, policy)

根据需要返回包含 linesep 字符的字符串,以根据 policy 正确折叠标题。 8bitcte_type 将被视为是 7bit,因为标头可能不包含任意二进制数据。如果 utf8False,则非ASCII数据将被 RFC 2047 编码。

BaseHeader 本身不能用于创建头对象。它定义每个专用报头协作以便产生报头对象的协议。具体来说,BaseHeader 要求专门的类提供一个名为 parseclassmethod()。该方法称为如下:

parse(string, kwds)

kwds 是包含一个预初始化的键 defects 的字典。 defects 是一个空列表。解析方法应该将任何检测到的缺陷附加到此列表。在返回时,kwds 字典 must 至少包含键 decodeddefects 的值。 decoded 应该是头的字符串值(即,头值完全解码为unicode)。解析方法应该假设 string 可以包含内容传输编码的部分,但应该正确处理所有有效的unicode字符,以便它可以解析未编码的标头值。

BaseHeader__new__ 然后创建头实例,并调用其 init 方法。如果专用类只想要设置除 BaseHeader 本身提供的属性之外的附加属性,则只需要提供 init 方法。这样的 init 方法应该看起来像这样:

def init(self, *args, **kw):
    self._myattr = kw.pop('myattr')
    super().init(*args, **kw)

也就是说,专业类放到 kwds 字典中的任何额外的东西应该被移除和处理,并且 kw (和 args)的剩余内容被传递到 BaseHeader init 方法。

class email.headerregistry.UnstructuredHeader

“非结构化”报头是 RFC 5322 中的报头的默认类型。任何没有指定语法的头都被视为非结构化头。非结构化报头的典型示例是 Subject 报头。

RFC 5322 中,非结构化头是ASCII字符集中任意文本的一串。然而,RFC 2047 具有 RFC 5322 兼容机制,用于将非ASCII文本作为头部值中的ASCII字符进行编码。当包含编码字的 value 被传递给构造函数时,UnstructuredHeader 解析器按照非结构化文本的 RFC 2047 规则将这样编码的字转换为unicode。解析器使用试探法来尝试解码某些不兼容的编码字。在这种情况下注册缺陷,以及诸如编码字或非编码文本中的无效字符的问题的缺陷。

此标题类型不提供其他属性。

class email.headerregistry.DateHeader

RFC 5322 为电子邮件标头中的日期指定了非常具体的格式。 DateHeader 解析器识别日期格式,以及识别有时在“野外”找到的许多变体形式。

此标题类型提供以下附加属性:

datetime

如果标题值可以被识别为一个表单或另一个表单的有效日期,则此属性将包含表示该日期的 datetime 实例。如果输入日期的时区指定为 -0000 (表示它在UTC中,但不包含有关源时区的信息),则 datetime 将是原始 datetime。如果找到特定的时区偏移(包括 +0000),则 datetime 将包含使用 datetime.timezone 记录时区偏移的感知 datetime

报头的 decoded 值通过根据 RFC 5322 规则格式化 datetime 来确定;也就是说,它被设置为:

email.utils.format_datetime(self.datetime)

当创建 DateHeader 时,value 可以是 datetime 实例。这意味着,例如,下面的代码是有效的,并做什么会期望:

msg['Date'] = datetime(2011, 7, 15, 21)

因为这是一个朴素的 datetime,它将被解释为UTC时间戳,并且结果值将具有 -0000 的时区。更有用的是使用 utils 模块中的 localtime() 函数:

msg['Date'] = utils.localtime()

此示例使用当前时区偏移将日期标题设置为当前时间和日期。

class email.headerregistry.AddressHeader

地址头是最复杂的结构化头类型之一。 AddressHeader 类为任何地址头提供通用接口。

此标题类型提供以下附加属性:

groups

一个 Group 对象的元组,用于编码在标头值中找到的地址和组。不是组的一部分的地址在该列表中表示为其 display_nameNone 的单地址 Groups

addresses

Address 对象的元组,从头值编码所有单独的地址。如果标题值包含任何组,则来自组的各个地址将包含在列表中该值出现的点(即,地址列表“展平”为一维列表)中。

报头的 decoded 值将所有编码字解码为unicode。 idna 编码的域名也被解码为unicode。 decoded 值通过 join 设置具有 ', 'groups 属性的元素的 str 值。

任何组合中的 AddressGroup 对象的列表可以用于设置地址头部的值。其 display_nameNoneGroup 对象将被解释为单个地址,这允许通过使用从源头的 groups 属性获得的列表来完整地复制地址列表。

class email.headerregistry.SingleAddressHeader

添加一个附加属性的 AddressHeader 的子类:

address

由标头值编码的单个地址。如果头值实际上包含多个地址(这将违反默认 policy 下的RFC),访问此属性将导致 ValueError

上述许多类也有 Unique 变体(例如,UniqueUnstructuredHeader)。唯一的区别是在 Unique 变体中,max_count 设置为1。

class email.headerregistry.MIMEVersionHeader

MIME-Version 头部实际上只有一个有效值,即 1.0。对于将来校验,此标题类支持其他有效的版本号。如果版本号对于每个 RFC 2045 具有有效值,则头对象将具有以下属性的非 None 值:

version

版本号作为字符串,删除任何空格和/或注释。

major

主版本号作为整数

minor

次版本号作为整数

class email.headerregistry.ParameterizedMIMEHeader

MIME头都以前缀“Content-”开头。每个特定头具有某个值,在该头的类下描述。一些还可以采取补充参数的列表,其具有通用格式。这个类充当所有接受参数的MIME头的基础。

params

将参数名称映射到参数值的字典。

class email.headerregistry.ContentTypeHeader

处理 Content-Type 头的 ParameterizedMIMEHeader 类。

content_type

内容类型字符串,格式为 maintype/subtype

maintype
subtype
class email.headerregistry.ContentDispositionHeader

处理 Content-Disposition 头的 ParameterizedMIMEHeader 类。

content-disposition

inlineattachment 是常用的唯一有效值。

class email.headerregistry.ContentTransferEncoding

处理 Content-Transfer-Encoding 头。

cte

有效值为 7bit8bitbase64quoted-printable。有关详细信息,请参阅 RFC 2045

class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)

这是默认情况下由 EmailPolicy 使用的工厂。 HeaderRegistry 构建用于动态创建头实例的类,使用 base_class 和从其保存的注册表检索的专门类。当给定的头名称未出现在注册表中时,由 default_class 指定的类用作专用类。当 use_default_mapTrue (默认值)时,在初始化期间将头名称到类的标准映射复制到注册表中。 base_class 始终是生成的类的 __bases__ 列表中的最后一个类。

默认映射为:

subject:

UniqueUnstructuredHeader

date:

UniqueDateHeader

resent-date:

DateHeader

orig-date:

UniqueDateHeader

sender:

UniqueSingleAddressHeader

resent-sender:

SingleAddressHeader

to:

UniqueAddressHeader

resent-to:

AddressHeader

cc:

UniqueAddressHeader

resent-cc:

AddressHeader

from:

UniqueAddressHeader

resent-from:

AddressHeader

reply-to:

UniqueAddressHeader

HeaderRegistry 有以下方法:

map_to_type(self, name, cls)

name 是要映射的头的名称。它将在注册表中转换为小写。 cls 是要与 base_class 一起使用的专用类,以创建用于实例化与 name 匹配的报头的类。

__getitem__(name)

构造并返回一个类来处理创建 name 头。

__call__(name, value)

从注册表中检索与 name 关联的专用头(如果 name 未出现在注册表中,则使用 default_class),并将其与 base_class 组合以生成类,调用构造类的构造函数,传递它相同的参数列表,最后返回类实例创建。

以下类是用于表示从结构化头部解析的数据的类,并且通常可以由应用程序用来构造结构化值以分配给特定头部。

class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)

用于表示电子邮件地址的类。地址的一般形式是:

[display_name] <username@domain>

要么:

username@domain

其中每个部分必须符合 RFC 5322 中阐述的特定语法规则。

为了方便,可以指定 addr_spec 而不是 usernamedomain,在这种情况下,将从 addr_spec 解析 usernamedomainaddr_spec 必须是RFC引用的字符串;如果不是 Address 会引发错误。允许使用Unicode字符,并且在序列化时将进行属性编码。然而,根据RFC,unicode在地址的用户名部分允许 not

display_name

地址的显示名称部分(如果有),删除所有引用。如果地址没有显示名称,则此属性将为空字符串。

username

地址的 username 部分,删除所有引号。

domain

地址的 domain 部分。

addr_spec

地址的 username@domain 部分,正确引用为裸地址(上面显示的第二种形式)。此属性不可变。

__str__()

对象的 str 值是根据 RFC 5322 规则引用的地址,但没有任何非ASCII字符的内容传输编码。

为了支持SMTP(RFC 5321),Address 处理一种特殊情况:如果 usernamedomain 都是空字符串(或 None),则 Address 的字符串值是 <>

class email.headerregistry.Group(display_name=None, addresses=None)

用于表示地址组的类。地址组的一般形式是:

display_name: [address-list];

为了方便处理由组和单个地址的混合组成的地址的列表,Group 也可以用于表示不是组的一部分的单个地址,方法是将 display_name 设置为 None,并提供单个地址的列表作为 addresses

display_name

组的 display_name。如果是 None,并且 addresses 中只有一个 Address,则 Group 表示不在组中的单个地址。

addresses

表示组中地址的 Address 对象的可能为空的元组。

__str__()

Groupstr 值根据 RFC 5322 格式化,但没有任何非ASCII字符的内容传输编码。如果 display_name 不是并且在 addresses 列表中存在单个 Address,则 str 值将与该单个 Addressstr 相同。

脚注

[1]

最初添加在3.3作为 临时模块