19.1.4. email.policy:策略对象 — Python 文档
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 之前版本的完全向后兼容性(在某些情况下,包括错误兼容性)。
EmailMessage 的 policy 关键字的默认值是 EmailPolicy 策略,通过其预定义实例 default。
当创建 Message 或 EmailMessage 对象时,它会获取一个策略。 如果消息是由 parser 创建的,则传递给解析器的策略将是它创建的消息所使用的策略。 如果消息是由程序创建的,则可以在创建时指定策略。 当消息传递给 generator 时,生成器默认使用消息中的策略,但您也可以将特定策略传递给生成器,该策略将覆盖存储在消息对象上的策略。
email.parser 类和解析器便利函数 的 policy 关键字的默认值将在 Python 的未来版本中更改 。 因此,在调用 parser 模块中描述的任何类和函数时,您应该 始终明确指定要使用的策略 。
本文档的第一部分介绍了 Policy 的功能,这是一个 抽象基类 ,它定义了所有策略对象共有的功能,包括 compat32。 这包括电子邮件包内部调用的某些钩子方法,自定义策略可以覆盖这些方法以获得不同的行为。 第二部分描述了具体的类 EmailPolicy 和 Compat32,它们分别实现了提供标准行为和向后兼容行为和特性的钩子。
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() 方法和构造函数语义的实现。
策略类的构造函数可以传递各种关键字参数。 可以指定的参数是此类上的任何非方法属性,以及具体类上的任何其他非方法属性。 构造函数中指定的值将覆盖相应属性的默认值。
此类定义了以下属性,因此可以在任何策略类的构造函数中传递以下值:
- linesep
用于终止序列化输出中的行的字符串。 默认值为
\n
,因为这是 Python 使用的内部行尾规则,尽管\r\n
是 RFC 所要求的。
- cte_type
控制可能或需要使用的内容传输编码的类型。 可能的值为:
7bit
所有数据必须是“7 位清洁”(仅限 ASCII)。 这意味着必要的数据将使用带引号的可打印或 base64 编码进行编码。
8bit
数据不限于 7 位清洁。 标头中的数据仍然需要仅是 ASCII 码,因此将被编码(有关例外情况,请参见下面的 fold_binary() 和 utf8),但正文部分可能使用 [ X174X] CTE。
8bit
的cte_type
值仅适用于BytesGenerator
,而不适用于Generator
,因为字符串不能包含二进制数据。 如果Generator
在指定cte_type=8bit
的策略下运行,它的行为就像cte_type
是7bit
。
- 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 标志。 如果是
True
,defect作为异常被提出。 如果是False
(默认),则将 obj 和 defect 传递给 register_defect()。
- register_defect(obj, defect)
在 obj 上注册一个 缺陷 。 在email包中,defect永远是
Defect
的子类。默认实现调用obj的
defects
属性的append
方法。 当电子邮件包调用 handle_defect 时,obj 通常会有一个defects
属性,该属性具有append
方法。 与电子邮件包一起使用的自定义对象类型(例如,自定义Message
对象)也应提供此类属性,否则解析的邮件中的缺陷将引发意外错误。
- header_max_count(name)
返回名为 name 的头文件的最大允许数量。
在将标头添加到 EmailMessage 或 Message 对象时调用。 如果返回值不是
0
或None
,并且已经有多个名称为 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)
元组以表示标头。如果实现希望保持与现有电子邮件包策略的兼容性,name 和 value 应该是不改变传入参数内容的字符串或字符串子类。
没有默认实现
- header_fetch_parse(name, value)
当应用程序请求该报头时,email 包使用当前存储在
Message
中的 name 和 value 调用此方法,无论该方法返回的是什么作为正在检索的标头值传递回应用程序。 注意Message
中可能存在多个同名的header; 该方法传递了要返回给应用程序的标头的特定名称和值。value 可能包含代理转义的二进制数据。 方法返回的值中不应该有代理转义的二进制数据。
没有默认实现
- fold(name, value)
电子邮件包使用 name 和 value 当前存储在给定标题的
Message
中调用此方法。 通过将 name 与 值 组合在一起并插入 linesep 字符,该方法应返回一个字符串,该字符串表示该标题正确“折叠”(根据策略设置)在适当的地方。 有关折叠电子邮件标头的规则的讨论,请参阅 RFC 5322。value 可能包含代理转义的二进制数据。 方法返回的字符串中不应该有代理转义的二进制数据。
- fold_binary(name, value)
与 fold() 相同,除了返回值应该是字节对象而不是字符串。
value 可能包含代理转义的二进制数据。 这些可以在返回的字节对象中转换回二进制数据。
- class email.policy.EmailPolicy(**kw)
这个具体的 Policy 提供了旨在完全符合当前电子邮件 RFC 的行为。 其中包括(但不限于)RFC 5322、RFC 2047 和当前的 MIME RFC。
此策略添加了新的标头解析和折叠算法。 标头不是简单的字符串,而是
str
子类,其属性取决于字段的类型。 解析和折叠算法完全实现了 RFC 2047 和 RFC 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
带有两个参数
name
和value
的可调用对象,其中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 忽略大小写,则返回值不变。 否则,将 name 和 value 传递给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 编码。
EmailPolicy 的以下实例提供适用于特定应用程序域的默认值。 请注意,将来这些实例(特别是 HTTP
实例)的行为可能会进行调整,以更加符合与其域相关的 RFC。
- email.policy.default
EmailPolicy
所有默认值不变的实例。 此策略使用标准 Python\n
行结尾,而不是 RFC 正确的\r\n
。
- email.policy.SMTP
- 适用于按照电子邮件 RFC 对消息进行序列化。 类似于
default
,但将linesep
设置为\r\n
,符合 RFC。
- email.policy.SMTPUTF8
- 除了 utf8 是
True
之外,与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 进行了更改:
从应用程序来看,这意味着通过 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_type
是7bit
,则非 ascii 二进制数据使用unknown-8bit
字符集进行 CTE 编码。 否则使用原始源头,以及它现有的换行符和它可能包含的任何(RFC 无效)二进制数据。
- email.policy.compat32
- Compat32 的一个实例,提供与 Python 3.2 中电子邮件包行为的向后兼容性。
脚注