19.1.4. email.policy:策略对象 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/email.policy
跳转至:导航、​搜索

19.1.4. 电子邮件.policy : 策略对象

3.3 版中的新功能。


源代码: :source:`Lib/email/policy.py`



email 包的主要焦点是处理各种电子邮件和 MIME RFC 所描述的电子邮件消息。 然而,电子邮件消息的一般格式(一个标题字段块,每个标题字段由一个名称后跟一个冒号和一个值,整个块后跟一个空行和一个任意的“正文”组成),是一种已经找到的格式电子邮件领域之外的实用程序。 其中一些用途与主要的电子邮件 RFC 非常接近,有些则不。 即使在使用电子邮件时,有时也需要打破对 RFC 的严格遵守,例如生成与本身不遵循标准的电子邮件服务器互操作的电子邮件,或者以违反标准的方式实现您想要使用的扩展标准。

策略对象使电子邮件包能够灵活地处理所有这些不同的用例。

Policy 对象封装了一组属性和方法,用于控制电子邮件包的各个组件在使用过程中的行为。 Policy 实例可以传递给 email 包中的各种类和方法来改变默认行为。 可设置的值及其默认值如下所述。

电子邮件包中的所有类都使用默认策略。 对于所有 parser 类和相关的便利函数,以及 Message 类,这是 Compat32 策略,通过其相应的预定义实例 [ X195X]compat32。 此策略提供与电子邮件包的 Python3.3 之前版本的完全向后兼容性(在某些情况下,包括错误兼容性)。

EmailMessagepolicy 关键字的默认值是 EmailPolicy 策略,通过其预定义实例 default

当创建 MessageEmailMessage 对象时,它会获取一个策略。 如果消息是由 parser 创建的,则传递给解析器的策略将是它创建的消息所使用的策略。 如果消息是由程序创建的,则可以在创建时指定策略。 当消息传递给 generator 时,生成器默认使用消息中的策略,但您也可以将特定策略传递给生成器,该策略将覆盖存储在消息对象上的策略。

email.parser 类和解析器便利函数 policy 关键字的默认值将在 Python 的未来版本中更改 。 因此,在调用 parser 模块中描述的任何类和函数时,您应该 始终明确指定要使用的策略

本文档的第一部分介绍了 Policy 的功能,这是一个 抽象基类 ,它定义了所有策略对象共有的功能,包括 compat32。 这包括电子邮件包内部调用的某些钩子方法,自定义策略可以覆盖这些方法以获得不同的行为。 第二部分描述了具体的类 EmailPolicyCompat32,它们分别实现了提供标准行为和向后兼容行为和特性的钩子。

Policy 实例是不可变的,但它们可以被克隆,接受与类构造函数相同的关键字参数并返回一个新的 Policy 实例,它是原始副本但具有指定的属性值改变了。

例如,以下代码可用于从磁盘上的文件读取电子邮件消息并将其传递给 Unix 系统上的系统 sendmail 程序:

>>> from email import message_from_binary_file
>>> from email.generator import BytesGenerator
>>> from email import policy
>>> from subprocess import Popen, PIPE
>>> with open('mymsg.txt', 'rb') as f:
...     msg = message_from_binary_file(f, policy=policy.default)
>>> p = Popen(['sendmail', msg['To'].addresses[0]], stdin=PIPE)
>>> g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n'))
>>> g.flatten(msg)
>>> p.stdin.close()
>>> rc = p.wait()

这里我们告诉 BytesGenerator 在创建二进制字符串以输入 sendmail's stdin 时使用 RFC 正确的行分隔符,其中默认策略将使用 [ X198X] 行分隔符。

一些电子邮件包方法接受 policy 关键字参数,允许为该方法覆盖策略。 例如,以下代码使用上一个示例中 msg 对象的 as_bytes() 方法,并使用消息所在平台的本机行分隔符将消息写入文件在跑:

>>> import os
>>> with open('converted.txt', 'wb') as f:
...     f.write(msg.as_bytes(policy=msg.policy.clone(linesep=os.linesep)))
17

还可以使用加法运算符组合策略对象,生成一个策略对象,其设置是相加对象的非默认值的组合:

>>> compat_SMTP = policy.compat32.clone(linesep='\r\n')
>>> compat_strict = policy.compat32.clone(raise_on_defect=True)
>>> compat_strict_SMTP = compat_SMTP + compat_strict

这个操作不是可交换的; 也就是说,添加对象的顺序很重要。 为了显示:

>>> policy100 = policy.compat32.clone(max_line_length=100)
>>> policy80 = policy.compat32.clone(max_line_length=80)
>>> apolicy = policy100 + policy80
>>> apolicy.max_line_length
80
>>> apolicy = policy80 + policy100
>>> apolicy.max_line_length
100
class email.policy.Policy(**kw)

这是所有策略类的 抽象基类 。 它提供了一些简单方法的默认实现,以及不变性属性、clone() 方法和构造函数语义的实现。

策略类的构造函数可以传递各种关键字参数。 可以指定的参数是此类上的任何非方法属性,以及具体类上的任何其他非方法属性。 构造函数中指定的值将覆盖相应属性的默认值。

此类定义了以下属性,因此可以在任何策略类的构造函数中传递以下值:

max_line_length

序列化输出中任何行的最大长度,不包括行尾字符。 默认值为 78,根据 RFC 53220None 的值表示根本不应该进行换行。

linesep

用于终止序列化输出中的行的字符串。 默认值为 \n,因为这是 Python 使用的内部行尾规则,尽管 \r\n 是 RFC 所要求的。

cte_type

控制可能或需要使用的内容传输编码的类型。 可能的值为:

7bit

所有数据必须是“7 位清洁”(仅限 ASCII)。 这意味着必要的数据将使用带引号的可打印或 base64 编码进行编码。

8bit

数据不限于 7 位清洁。 标头中的数据仍然需要仅是 ASCII 码,因此将被编码(有关例外情况,请参见下面的 fold_binary()utf8),但正文部分可能使用 [ X174X] CTE。

8bitcte_type 值仅适用于 BytesGenerator,而不适用于 Generator,因为字符串不能包含二进制数据。 如果 Generator 在指定 cte_type=8bit 的策略下运行,它的行为就像 cte_type7bit

raise_on_defect

如果 True,则遇到的任何缺陷都将作为错误提出。 如果 False(默认值),缺陷将传递给 register_defect() 方法。

mangle_from\_

如果 True,以 “From “ in body 开头的行通过在它们前面放一个 > 来转义。 当消息由生成器序列化时使用此参数。 默认值:

3.5 新功能:mangle_from_ 参数。

message_factory

用于构造新的空消息对象的工厂函数。 解析器在构建消息时使用。 默认为 None,在这种情况下使用 Message

3.6 版中的新功能。

以下 Policy 方法旨在由使用电子邮件库的代码调用,以创建具有自定义设置的策略实例:

clone(**kw)

返回一个新的 Policy 实例,其属性具有与当前实例相同的值,除非这些属性由关键字参数赋予新值。

其余的 Policy 方法由电子邮件包代码调用,并不打算由使用电子邮件包的应用程序调用。 自定义策略必须实现所有这些方法。

handle_defect(obj, defect)

处理在 obj 上发现的 缺陷 。 当email包调用这个方法时,defect永远是Defect的子类。

默认实现检查 raise_on_defect 标志。 如果是Truedefect作为异常被提出。 如果是 False(默认),则将 objdefect 传递给 register_defect()

register_defect(obj, defect)

obj 上注册一个 缺陷 。 在email包中,defect永远是Defect的子类。

默认实现调用objdefects属性的append方法。 当电子邮件包调用 handle_defect 时,obj 通常会有一个 defects 属性,该属性具有 append 方法。 与电子邮件包一起使用的自定义对象类型(例如,自定义 Message 对象)也应提供此类属性,否则解析的邮件中的缺陷将引发意外错误。

header_max_count(name)

返回名为 name 的头文件的最大允许数量。

在将标头添加到 EmailMessageMessage 对象时调用。 如果返回值不是 0None,并且已经有多个名称为 name 的头文件大于或等于返回值,则出现 ]ValueError 被引发。

因为 Message.__setitem__ 的默认行为是将值附加到标题列表中,所以很容易在没有意识到的情况下创建重复的标题。 此方法允许某些标头限制在可以以编程方式添加到 Message 的标头实例的数量。 (解析器不会遵守该限制,它将忠实地生成与正在解析的消息中存在的头一样多的头。)

默认实现为所有标头名称返回 None

header_source_parse(sourcelines)

email 包使用一个字符串列表调用此方法,每个字符串都以在被解析的源中找到的行分隔字符结尾。 第一行包括字段标题名称和分隔符。 源中的所有空白都被保留。 该方法应返回要存储在 Message 中的 (name, value) 元组,以表示解析的标头。

如果实现希望保留与现有电子邮件包策略的兼容性,name 应该是大小写保留的名称(所有字符直到 ':' 分隔符),而 value[ X207X] 应该是展开的值(删除了所有行分隔符,但空格保持不变),去掉前导空格。

sourcelines 可能包含代理转义的二进制数据。

没有默认实现

header_store_parse(name, value)

当应用程序以编程方式修改 Message(与解析器创建的 Message 相对)时,电子邮件包使用应用程序提供的名称和值调用此方法。 该方法应返回要存储在 Message 中的 (name, value) 元组以表示标头。

如果实现希望保持与现有电子邮件包策略的兼容性,namevalue 应该是不改变传入参数内容的字符串或字符串子类。

没有默认实现

header_fetch_parse(name, value)

当应用程序请求该报头时,email 包使用当前存储在 Message 中的 namevalue 调用此方法,无论该方法返回的是什么作为正在检索的标头值传递回应用程序。 注意Message中可能存在多个同名的header; 该方法传递了要返回给应用程序的标头的特定名称和值。

value 可能包含代理转义的二进制数据。 方法返回的值中不应该有代理转义的二进制数据。

没有默认实现

fold(name, value)

电子邮件包使用 namevalue 当前存储在给定标题的 Message 中调用此方法。 通过将 name 组合在一起并插入 linesep 字符,该方法应返回一个字符串,该字符串表示该标题正确“折叠”(根据策略设置)在适当的地方。 有关折叠电子邮件标头的规则的讨论,请参阅 RFC 5322

value 可能包含代理转义的二进制数据。 方法返回的字符串中不应该有代理转义的二进制数据。

fold_binary(name, value)

fold() 相同,除了返回值应该是字节对象而不是字符串。

value 可能包含代理转义的二进制数据。 这些可以在返回的字节对象中转换回二进制数据。

class email.policy.EmailPolicy(**kw)

这个具体的 Policy 提供了旨在完全符合当前电子邮件 RFC 的行为。 其中包括(但不限于)RFC 5322RFC 2047 和当前的 MIME RFC。

此策略添加了新的标头解析和折叠算法。 标头不是简单的字符串,而是 str 子类,其属性取决于字段的类型。 解析和折叠算法完全实现了 RFC 2047RFC 5322

message_factory 属性的默认值为 EmailMessage

除了上面列出的适用于所有策略的可设置属性之外,此策略还添加了以下附加属性:

3.6 版新功能: 1

utf8

如果是 False,请遵循 RFC 5322,通过将它们编码为“编码字”来支持标头中的非 ASCII 字符。 如果是 True,请遵循 RFC 6532 并使用 utf-8 编码作为标头。 以这种方式格式化的邮件可能会传递到支持 SMTPUTF8 扩展名 (RFC 6531) 的 SMTP 服务器。

refold_source

如果 Message 对象中标头的值源自 parser(而不是由程序设置),则此属性指示生成器在转换时是否应重新折叠该值消息恢复为序列化形式。 可能的值为:

none

所有源值都使用原始折叠

long

任何行长于 max_line_length 的源值将被重新折叠

all

所有值都被重新折叠。

默认值为 long

header_factory

带有两个参数 namevalue 的可调用对象,其中 name 是标头字段名称,value 是展开的标头字段值,并返回一个表示该标头的字符串子类。 提供了一个默认的 header_factory(参见 headerregistry),它支持对各种地址和日期 RFC 5322 头字段类型的自定义解析,以及主要 MIME 标头字段类型。 将来会添加对其他自定义解析的支持。

content_manager

一个对象至少有两个方法:get_content 和 set_content。 当调用 EmailMessage 对象的 get_content()set_content() 方法时,它会调用该对象的相应方法,将消息对象作为它的第一个参数,以及作为附加参数传递给它的任何参数或关键字。 默认情况下,content_manager 设置为 raw_data_manager

3.4 版中的新功能。

该类提供了Policy抽象方法的以下具体实现:

header_max_count(name)

返回用于表示具有给定名称的标头的专用类的 max_count 属性的值。

header_source_parse(sourcelines)

该名称被解析为“:”之前的所有内容,并未经修改地返回。 该值是通过去除第一行剩余部分的前导空格、将所有后续行连接在一起并去除任何尾随回车或换行符来确定的。

header_store_parse(name, value)

名称不变。 如果输入值具有 name 属性并且匹配 name 忽略大小写,则返回值不变。 否则,将 namevalue 传递给 header_factory,并将结果头对象作为值返回。 在这种情况下,如果输入值包含 CR 或 LF 字符,则会引发 ValueError

header_fetch_parse(name, value)

如果该值具有 name 属性,则返回未修改。 否则,name 和删除了任何 CR 或 LF 字符的 value 将传递给 header_factory,并返回结果头对象。 任何代理转义的字节都会变成 unicode 未知字符字形。

fold(name, value)

标头折叠由 refold_source 策略设置控制。 当且仅当一个值不具有 name 属性(具有 name 属性意味着它是某种标头对象)时,该值才被认为是“源值”。 如果需要根据策略重新折叠源值,则通过将 名称 删除任何 CR 和 LF 字符传递到 header_factory。 标题对象的折叠是通过使用当前策略调用其 fold 方法来完成的。

使用 splitlines() 将源值分成几行。 如果不重新折叠该值,则使用策略中的 linesep 重新加入行并返回。 包含非 ascii 二进制数据的行除外。 在这种情况下,无论 refold_source 设置如何,都会重新折叠该值,这会导致使用 unknown-8bit 字符集对二进制数据进行 CTE 编码。

fold_binary(name, value)

如果 cte_type7bit,则与 fold() 相同,只是返回值为字节。

如果 cte_type8bit,则非 ASCII 二进制数据被转换回字节。 无论 refold_header 设置如何,都不会重新折叠带有二进制数据的标头,因为无法知道二进制数据是由单字节字符还是多字节字符组成。

EmailPolicy 的以下实例提供适用于特定应用程序域的默认值。 请注意,将来这些实例(特别是 HTTP 实例)的行为可能会进行调整,以更加符合与其域相关的 RFC。

email.policy.default
EmailPolicy 所有默认值不变的实例。 此策略使用标准 Python \n 行结尾,而不是 RFC 正确的 \r\n
email.policy.SMTP
适用于按照电子邮件 RFC 对消息进行序列化。 类似于 default,但将 linesep 设置为 \r\n,符合 RFC。
email.policy.SMTPUTF8
除了 utf8True 之外,与 SMTP 相同。 用于将消息序列化到消息存储区,而无需在标头中使用编码字。 如果发件人或收件人地址具有非 ASCII 字符,则应仅用于 SMTP 传输(smtplib.SMTP.send_message() 方法会自动处理此问题)。
email.policy.HTTP
适用于序列化标头以用于 HTTP 流量。 与 SMTP 类似,除了 max_line_length 设置为 None(无限制)。
email.policy.strict

便利实例。 除了 raise_on_defect 设置为 True 之外,与 default 相同。 这允许通过写入来使任何策略变得严格:

somepolicy + policy.strict

通过所有这些 EmailPolicies,电子邮件包的有效 API 以以下方式从 Python 3.2 API 进行了更改:

  • Message 上设置标头会导致解析该标头并创建标头对象。
  • Message 获取标头值会导致解析该标头并创建并返回标头对象。
  • 任何标头对象,或由于策略设置而重新折叠的任何标头,都使用完全实现 RFC 折叠算法的算法折叠,包括了解需要和允许编码字的位置。


从应用程序来看,这意味着通过 EmailMessage 获得的任何 header 都是具有额外属性的 header 对象,其字符串值是完全解码的 header 的 unicode 值。 同样,可以使用 unicode 字符串为标头分配一个新值或创建一个新标头,并且该策略将负责将 unicode 字符串转换为正确的 RFC 编码形式。

头对象及其属性在 headerregistry 中描述。

class email.policy.Compat32(**kw)

这个具体的 Policy 是向后兼容策略。 它在 Python 3.2 中复制了电子邮件包的行为。 policy 模块还定义了此类的一个实例 compat32,用作默认策略。 因此 email 包的默认行为是保持与 Python 3.2 的兼容性。

以下属性的值与 Policy 默认值不同:

mangle_from_

默认值为 True

该类提供了Policy抽象方法的以下具体实现:

header_source_parse(sourcelines)

该名称被解析为“:”之前的所有内容,并未经修改地返回。 该值是通过去除第一行剩余部分的前导空格、将所有后续行连接在一起并去除任何尾随回车或换行符来确定的。

header_store_parse(name, value)

名称和值未经修改返回。

header_fetch_parse(name, value)

如果该值包含二进制数据,则使用 unknown-8bit 字符集将其转换为 Header 对象。 否则它会原封不动地返回。

fold(name, value)

标题使用 Header 折叠算法折叠,该算法保留值中的现有换行符,并将每个结果行包装到 max_line_length。 非 ASCII 二进制数据使用 unknown-8bit 字符集进行 CTE 编码。

fold_binary(name, value)

标题使用 Header 折叠算法折叠,该算法保留值中的现有换行符,并将每个结果行包装到 max_line_length。 如果 cte_type7bit,则非 ascii 二进制数据使用 unknown-8bit 字符集进行 CTE 编码。 否则使用原始源头,以及它现有的换行符和它可能包含的任何(RFC 无效)二进制数据。

email.policy.compat32
Compat32 的一个实例,提供与 Python 3.2 中电子邮件包行为的向后兼容性。

脚注

1
最初在 3.3 中作为 临时功能 添加。