email.policy:策略对象

版本 3.3 中的新Function。

源代码: Lib/email/policy.py


email软件包的主要重点是处理各种电子邮件和 MIME RFC 所描述的电子邮件。但是,电子邮件的一般格式(一个标题字段块,每个标题字段由一个名称,一个冒号,一个值,整个块,一个空行和一个任意的“ body”组成)是一种已经发现的格式电子邮件领域之外的 Util。其中一些用法与主要电子邮件 RFC 相当接近,有些则与之不符。即使使用电子邮件,有时也需要 break 对 RFC 的严格合规,例如生成与本身不遵循标准的电子邮件服务器进行互操作的电子邮件,或者以违反方式使用您想要使用的扩展标准。

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

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

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

EmailMessage的* policy *关键字的默认值是EmailPolicy策略(pass其 sched 义实例default)。

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

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

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

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 正确的行分隔符,其中默认策略将使用\n行分隔符。

一些电子邮件软件包方法接受* 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

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

>>> 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
  • 类别 email.policy. Policy(*** kw *)
    • 这是所有策略类别的抽象 Base Class。它提供了一些简单方法的默认实现,以及不变性属性,clone()方法和构造函数语义的实现。

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

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

  • max_line_length

    • 序列化输出中任何行的最大长度,不计算行字符的结尾。 RFC 5322默认为 78. 0None的值表示根本不应该进行换行。
  • linesep

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

    • 控制可能使用或要求使用的内容传输编码的类型。可能的值为:
7bit所有数据都必须为“ 7 位干净”(仅 ASCII)。这意味着必要的数据将使用带引号的可打印格式或 base64 编码进行编码。
8bit数据不限于 7 位整洁。Headers 中的数据仍然必须为纯 ASCII,因此将被编码(有关异常,请参阅下面的fold_binary()utf8),但是正文部分可能会使用8bit CTE。

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

  • raise_on_defect

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

    • 如果为True,则在主体中以>开头的行会跳过主体中以*“ From” *开头的行。生成器正在序列化消息时使用此参数。默认值:False

3.5 版中的新Function:* mangle_from_ *参数。

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

3.6 版的新Function。

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

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

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

  • handle_defect(* obj defect *)
    • 处理在* obj 上发现的缺陷*。当电子邮件包调用此方法时,* defect *将始终是Defect的子类。

默认实现检查raise_on_defect标志。如果为True,则引发* defect (异常)。如果它是False(默认值),则将 obj defect *传递给register_defect()

  • register_defect(* obj defect *)
    • 在* obj 上注册一个 defect 。在电子邮件包中, defect *始终是Defect的子类。

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

  • header_max_count(* name *)
    • 返回名为* name *的 Headers 的最大允许数量。

将 Headers 添加到EmailMessageMessage对象时调用。如果返回的值不是0None,并且已经有多个 Headers* name *大于或等于返回的值,则引发ValueError

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

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

  • header_source_parse(* sourcelines *)
    • 电子邮件包使用字符串列表来调用此方法,每个字符串都以要在源中找到的行分隔字符结尾。第一行包括字段标题名称和分隔符。源中的所有空格都将保留。该方法应返回(name, value)Tuples,该 Tuples 将存储在Message中以表示已解析的 Headers。

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

源代码可能包含替代转义的二进制数据。

没有默认实现

  • header_store_parse(* name value *)
    • 当应用程序以编程方式修改Message时(与解析器创建的Message相反),电子邮件软件包将使用应用程序提供的名称和值来调用此方法。该方法应返回(name, value)Tuples,该 Tuples 将存储在Message中以表示 Headers。

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

没有默认实现

  • header_fetch_parse(* name value *)
    • 当应用程序请求该 Headers 时,电子邮件软件包将使用当前存储在Message中的* name value *来调用此方法,该方法返回的任何内容将作为 Headers 的值传递回应用程序检索。请注意,Message中可能存储了多个同名标题;该方法将传递给 Headers 的特定名称和值,该 Headers 将被返回给应用程序。
  • value *可能包含替代转义的二进制数据。该方法返回的值中不应包含替代转义的二进制数据。

没有默认实现

  • fold(* name value *)
    • 电子邮件包使用给定标题的当前存储在Message中的* name value 调用此方法。该方法应返回一个字符串,该字符串表示该标题已正确折叠(根据策略设置),方法是将 name value *组成并在适当的位置插入linesep个字符。有关折叠电子邮件 Headers 的规则的讨论,请参见 RFC 5322
  • value *可能包含替代转义的二进制数据。该方法返回的字符串中不应包含替代转义的二进制数据。
  • fold_binary(* name value *)
    • fold()相同,除了返回的值应该是字节对象而不是字符串。
  • value *可能包含替代转义的二进制数据。这些可以在返回的字节对象中转换回二进制数据。
  • 类别 email.policy. EmailPolicy(*** kw *)
    • 具体的Policy提供了旨在完全符合当前电子邮件 RFC 的行为。这些包括(但不限于) RFC 5322 RFC 2047和当前的 MIME RFC。

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

message_factory属性的默认值为EmailMessage

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

3.6 版的新Function:[1]

  • utf8

    • 如果为False,则跟随 RFC 5322,pass将 Headers 编码为“编码字”来支持 Headers 中的非 ASCII 字符。如果为True,则跟随 RFC 6532并为标题使用utf-8编码。以这种方式格式化的邮件可能会传递到支持SMTPUTF8extensions( RFC 6531)的 SMTP 服务器。
  • refold_source

    • 如果Message对象中 Headers 的值源自parser(而不是由程序设置),则此属性指示在将消息转换回序列化形式时,生成器是否应重新折叠该值。可能的值为:
none所有源值均使用原始折叠
long任意行长于max_line_length的源值将被重新折叠
all所有值都被重新折叠。

默认值为long

  • header_factory

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

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

3.4 版的新Function。

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

  • header_max_count(* name *)

    • 返回专用类的max_count属性的值,该属性用于表示具有给定名称的 Headers。
  • header_source_parse(* sourcelines *)

    • 该名称将被解析为直到“ :”的所有内容,并且将返回未修改的名称。该值是pass以下方式确定的:从第一行的其余部分中去除前导空格,将所有后续行连接在一起,并去除所有尾随的回车符或换行符。
  • header_store_parse(* name value *)

    • 名称不变。如果 Importing 值具有name属性,并且匹配* name (忽略大小写),则该值将保持不变。否则,将 name value *传递给header_factory,并将返回的 Headers 对象作为值返回。在这种情况下,如果 Importing 值包含 CR 或 LF 字符,则会引发ValueError
  • header_fetch_parse(* name value *)

    • 如果该值具有name属性,则将其返回未修改状态。否则,将* name value *除去所有 CR 或 LF 字符后,传递给header_factory,并返回结果 Headers 对象。任何替代的转义字节都会变成 Unicode 未知字符字形。
  • fold(* name value *)

    • 标题折叠由refold_source策略设置控制。当且仅当一个值没有name属性(具有name属性表示它是某种标题对象)时,该值才被视为“源值”。如果需要根据策略重新折叠源值,则pass将* name value *传递给header_factory,并将任何 CR 和 LF 字符删除,将其转换为 Headers 对象。头对象的折叠是pass使用当前策略调用其fold方法来完成的。

源值使用splitlines()分成几行。如果该值不被重新折叠,则使用策略中的linesep重新合并这些行并返回。exception 是包含非 ASCII 二进制数据的行。在那种情况下,无论refold_source设置如何,该值都会重新折叠,这会使二进制数据使用unknown-8bit字符集进行 CTE 编码。

  • fold_binary(* name value *)
    • 如果cte_type7bit,则与fold()相同,除了返回的值是字节。

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

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

  • email.policy. default

    • EmailPolicy的实例,所有默认设置不变。此策略使用标准的 Python \n行结尾而不是 RFC 正确的\r\n
  • email.policy. SMTP

    • 适用于序列化符合电子邮件 RFC 的消息。类似于default,但将linesep设置为\r\n,这符合 RFC。
  • email.policy. SMTPUTF8

    • SMTP相同,除了utf8True。在不使用 Headers 中的编码字的情况下,将消息序列化到消息存储很有用。如果发件人或收件人地址包含非 ASCII 字符(smtplib.SMTP.send_message()方法会自动处理),则仅应用于 SMTP 传输。
  • email.policy. HTTP

    • 适用于序列化 Headers,以用于 HTTP 通信。类似于SMTP,但max_line_length设置为None(无限制)。
  • email.policy. strict

    • 便利实例。与default相同,除了raise_on_defect设置为True。这样可以pass以下方式严格执行任何策略:
somepolicy + policy.strict

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

Note

  • Message上设置 Headers 会导致该 Headers 被解析并创建 Headers 对象。

  • Message获取 Headers 值将导致对该 Headers 进行解析,并创建并返回一个 Headers 对象。

  • 使用完全实现 RFC 折叠算法的算法来折叠任何 Headers 对象或由于策略设置而重新折叠的任何 Headers,包括知道在哪里需要并允许编码的单词。

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

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

  • 类别 email.policy. Compat32(*** kw *)
    • 具体的Policy是向后兼容策略。它复制了 Python 3.2 中电子邮件包的行为。 policy模块还定义了此类的实例compat32,用作默认策略。因此,电子邮件软件包的默认行为是保持与 Python 3.2 的兼容性。

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

  • mangle_from_
    • 默认值为True

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

  • header_source_parse(* sourcelines *)

    • 该名称将被解析为直到“ :”的所有内容,并且将返回未修改的名称。该值是pass以下方式确定的:从第一行的其余部分中去除前导空格,将所有后续行连接在一起,并去除所有尾随的回车符或换行符。
  • 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,则使用unknown-8bit字符集对非 ASCII 二进制数据进行 CTE 编码。否则,将使用原始源 Headers 及其现有的换行符及其可能包含的任何(RFC 无效)二进制数据。
  • email.policy. compat32

    • Compat32的实例,向后兼容 Python 3.2 中电子邮件包的行为。

Footnotes