email.headerregistry
: 自定义标头对象¶
源代码: Lib/email/headerregistry.py
在 3.6 版本加入: [1]
标头由 str
的自定义子类来表示。用于表示给定标头的特定类由创建标头时生效的 policy
的 header_factory
决定。本节文档介绍了 email 包为处理符合 RFC 5322 的电子邮件消息而实现的特定 header_factory
,它不仅为各种标头类型提供了自定义标头对象,还为应用程序提供了一种扩展机制,以添加自己的自定义标头类型。
当使用任何派生自 EmailPolicy
的策略对象时,所有标头都由 HeaderRegistry
生成,并以 BaseHeader
作为它们的最后一个基类。每个标头类都有一个额外的基类,该基类由标头的类型决定。例如,许多标头以 UnstructuredHeader
类作为它们的另一个基类。标头的专用第二个类由标头的名称决定,使用存储在 HeaderRegistry
中的查找表。所有这些对于典型的应用程序都是透明管理的,但提供了接口来修改默认行为,以供更复杂的应用程序使用。
以下各节首先介绍标头基类及其属性,然后是用于修改 HeaderRegistry
行为的 API,最后是从结构化标头中解析出的数据所使用的支持类。
- class email.headerregistry.BaseHeader(name, value)¶
name 和 value 是通过调用
header_factory
传递给BaseHeader
的。任何标头对象的字符串值都是完全解码为 Unicode 的 value。这个基类定义了以下只读属性:
- name¶
标头的名称(字段中“:”之前的部分)。这与在
header_factory
调用中为 name 传递的值完全相同;也就是说,大小写被保留。
- defects¶
一个
HeaderDefect
实例的元组,报告在解析期间发现的任何 RFC 合规性问题。email 包试图完整地检测合规性问题。有关可能报告的缺陷类型的讨论,请参见errors
模块。
- max_count¶
具有相同
name
的此类标头的最大数量。值为None
意味着无限制。BaseHeader
对此属性的值为None
;专门的标头类会根据需要覆盖此值。
BaseHeader
还提供了以下方法,该方法由 email 库代码调用,通常不应由应用程序调用:- fold(*, policy)¶
返回一个字符串,其中包含根据 policy 正确折叠标头所需的
linesep
字符。cte_type
为8bit
将被视为7bit
,因为标头不能包含任意二进制数据。如果utf8
是False
,非 ASCII 数据将被 RFC 2047 编码。
BaseHeader
本身不能用于创建标头对象。它定义了一个协议,每个专门的标头都与之协作以生成标头对象。具体来说,BaseHeader
要求专门的类提供一个名为parse
的classmethod()
。该方法按如下方式调用:parse(string, kwds)
kwds
是一个包含一个预初始化键defects
的字典。defects
是一个空列表。parse 方法应将任何检测到的缺陷附加到此列表中。返回时,kwds
字典*必须*包含至少decoded
和defects
键的值。decoded
应该是标头的字符串值(即,完全解码为 Unicode 的标头值)。parse 方法应假定 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
将是一个 naivedatetime
。如果找到特定的时区偏移量(包括+0000
),则datetime
将包含一个 awaredatetime
,它使用datetime.timezone
来记录时区偏移量。
标头的
decoded
值是通过根据 RFC 5322 规则格式化datetime
来确定的;也就是说,它被设置为:email.utils.format_datetime(self.datetime)
创建
DateHeader
时,value 可以是datetime
实例。这意味着,例如,以下代码是有效的并且会按预期工作:msg['Date'] = datetime(2011, 7, 15, 21)
由于这是一个 naive
datetime
,它将被解释为 UTC 时间戳,并且结果值将具有-0000
的时区。更有用的是使用utils
模块中的localtime()
函数:msg['Date'] = utils.localtime()
此示例将日期标头设置为当前时间和日期,使用当前时区偏移量。
- class email.headerregistry.AddressHeader¶
地址标头是最复杂的结构化标头类型之一。
AddressHeader
类为任何地址标头提供了通用接口。此标头类型提供了以下附加属性:
- groups¶
一个
Group
对象的元组,编码了在标头值中找到的地址和组。不属于组的地址在此列表中表示为单个地址的Group
,其display_name
为None
。
- addresses¶
一个
Address
对象的元组,编码了标头值中的所有单个地址。如果标头值包含任何组,则组中的单个地址将包含在列表中,位置是组在值中出现的位置(也就是说,地址列表被“扁平化”为一维列表)。
标头的
decoded
值将所有编码词解码为 Unicode。idna
编码的域名也被解码为 Unicode。decoded
值通过将groups
属性元素的str
值用', '
连接起来设置。可以使用
Address
和Group
对象的任意组合列表来设置地址标头的值。其display_name
为None
的Group
对象将被解释为单个地址,这允许通过使用从源标头的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¶
一个
ParameterizedMIMEHeader
类,用于处理 Content-Type 标头。- content_type¶
内容类型字符串,格式为
maintype/subtype
。
- maintype¶
- subtype¶
- class email.headerregistry.ContentDispositionHeader¶
一个
ParameterizedMIMEHeader
类,用于处理 Content-Disposition 标头。- content_disposition¶
inline
和attachment
是唯一常用且有效的值。
- class email.headerregistry.ContentTransferEncoding¶
处理 Content-Transfer-Encoding 标头。
- class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)¶
这是
EmailPolicy
默认使用的工厂。HeaderRegistry
动态地构建用于创建标头实例的类,它使用 base_class 和从其持有的注册表中检索的专门类。当给定的标头名称未出现在注册表中时,使用 default_class 指定的类作为专门类。当 use_default_map 为True
(默认值)时,在初始化期间将标头名称到类的标准映射复制到注册表中。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
- bcc:
UniqueAddressHeader
- resent-bcc:
AddressHeader
- from:
UniqueAddressHeader
- resent-from:
AddressHeader
- reply-to:
UniqueAddressHeader
- mime-version:
MIMEVersionHeader
- content-type:
ContentTypeHeader
- content-disposition:
ContentDispositionHeader
- content-transfer-encoding:
ContentTransferEncodingHeader
- message-id:
MessageIDHeader
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 代替 username 和 domain,在这种情况下,username 和 domain 将从 addr_spec 中解析出来。addr_spec 必须是符合 RFC 规范的带引号字符串;否则
Address
将引发错误。允许使用 Unicode 字符,并且在序列化时会被正确编码。但是,根据 RFC,地址的用户名部分*不允许*使用 Unicode。- display_name¶
地址的显示名称部分(如果有的话),去除了所有引号。如果地址没有显示名称,此属性将为空字符串。
- username¶
地址的
username
部分,去除了所有引号。
- domain¶
地址的
domain
部分。
- addr_spec¶
地址的
username@domain
部分,被正确引用以用作裸地址(上面显示的第二种形式)。此属性不可变。
为了支持 SMTP (RFC 5321),
Address
处理一种特殊情况:如果username
和domain
都是空字符串(或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
表示一个不在组中的单个地址。
脚注