19.1.2. email.parser: 解析电子邮件信息


    使用以下两种方法的其中一种以创建消息对象结构:直接创建一个 对象,使用字典接口添加消息头,并且使用 set_content() 和其他相关方法添加消息负载;或者通过解析一个电子邮件消息的序列化表达来创建消息对象结构。

    包提供了一个可以理解包含 MIME 文档在内的绝大多数电子邮件文档结构的标准语法分析程序。 你可以传递给语法分析程序一个字节串、字符串或者文件对象,语法分析程序会返回给你对应于该对象结构的根 EmailMessage 实例。 对于简单的、非 MIME 的消息,这个根对象的负载很可能就是一个包含了该消息文字内容的字符串。 对于 MIME 消息,调用根对象的 方法会返回 ,其子项可以通过负载操纵方法来进行访问,例如 get_body()、 还有 walk()

    事实上你可以使用的语法分析程序接口有两种: API 和增量式的 FeedParser API。当你的全部消息内容都在内存当中,或者整个消息都保存在文件系统内的一个文件当中的时候, API非常有用。当你从可能会为了等待更多输入而阻塞的数据流当中读取消息(比如从套接字当中读取电子邮件消息)的时候,FeedParser 会更合适。 会增量读取并解析消息,并且只有在你关闭语法分析程序的时候才会返回根对象。

    请注意,语法分析程序可以进行有限的拓展,你当然也可以完全从零开始实现你自己的语法分析程序。将 email 包中内置的语法分析程序和 类连接起来的所有逻辑代码都包含在 policy 类当中,所以如有必要,自定义的语法分析程序可以通过实现自定义的对应 policy 方法来创建对应的消息对象树。

    email.feedparser 模块导入的 BytesFeedParser 类提供了一个适合于增量解析电子邮件消息的API,比如说在从一个可能会阻塞(例如套接字)的源当中读取消息文字的场合中它就会变得很有用。当然, 也可以用来解析一个已经完整包含在一个 bytes-like object 、字符串或文件内的电子邮件消息,但是在这些场合下使用 API可能会更加方便。这两个语法分析程序API的语义和最终结果是一致的。

    BytesFeedParser 的API十分简洁易懂:你创建一个语法分析程序的实例,向它不断输入大量的字节直到尽头,然后关闭这个语法分析程序就可以拿到根消息对象了。 在处理符合标准的消息的时候 非常准确;在处理不符合标准的消息的时候它做的也不差,但这视消息损坏的程度而定。它会向消息对象的 defects 属性中写入它从消息中找到的问题列表。关于它能找到的所有问题类型的列表,详见 模块。

    这里是 BytesFeedParser 的 API:

    class email.parser.BytesFeedParser(_factory=None, **, policy=policy.compat32*)

    创建一个 实例。可选的 _factory 参数是一个不带参数的可调用对象;如果没有被指定,就会使用 policy 参数的 message_factory 属性。 每当需要一个新的消息对象的时候,_factory 都会被调用。

    如果指定了 policy 参数,它就会使用这个参数所指定的规则来更新消息的表达方式。 如果没有设定 policy 参数,它就会使用 策略。 这个策略维持了对 Python 3.2 版本的 email 包的后向兼容性,并且使用 Message 作为默认的工厂。 其他策略使用 作为默认的 _factory。 关于 policy 还会控制什么,参见 policy 的文档。

    注: 一定要指定policy关键字。 在未来版本的 Python 当中,它的默认值会变成 。

    3.2 新版功能.

    在 3.3 版更改: 添加了policy关键字。

    在 3.6 版更改: _factory 默认为策略 message_factory

    • close()

      完成之前输入的所有数据的解析并返回根消息对象。 如果在这个方法被调用之后仍然调用 feed() 方法,结果是未定义的。

    class email.parser.FeedParser(_factory=None, **, policy=policy.compat32*)

    行为跟 类一致,只不过向 feed() 方法输入的内容必须是字符串。 它的实用性有限,因为这种消息只有在其只含有 ASCII 文字,或者 utf8 被设置为 True 且没有二进制格式的附件的时候,才会有效。

    在 3.3 版更改: 添加了policy关键字。

    类从 email.parser 模块导入,当消息的完整内容包含在一个 或文件中时它提供了可用于解析消息的 API。 email.parser 模块还提供了 用来解析字符串,以及只用来解析消息头的 BytesHeaderParser 和 ,如果你只对消息头感兴趣就可以使用后两者。 在这种场合下 BytesHeaderParser 和 速度非常快,因为它们并不会尝试解析消息体,而是将载荷设为原始数据。

    class email.parser.BytesParser(_class=None, **, policy=policy.compat32*)

    注: 一定要指定policy关键字。 在未来版本的 Python 当中,它的默认值会变成 email.policy.default

    在 3.3 版更改: 移除了在2.4版本中被弃用的strict参数。新增了policy关键字。

    在 3.6 版更改: _class 默认为策略 。

    • parse(fp, headersonly=False)

      从二进制的类文件对象 fp 中读取全部数据、解析其字节内容、并返回消息对象。 fp 必须同时支持 方法和 read() 方法。

      fp 内包含的字节内容必须是一块遵循 RFC 5322 (如果 utf8True,则为 )格式风格的消息头和消息头延续行,并可能紧跟一个信封头。 头块要么以数据结束,要么以一个空行为终止。 跟着头块的是消息体(消息体内可能包含 MIME 编码的子部分,这也包括 Content-Transfer-Encoding 字段为 8bit 的子部分)。

      可选的headersonly指示了是否应当在读取完消息头后就终止。默认值为``False``,意味着它会解析整个文件的全部内容。

    • parsebytes(bytes, headersonly=False)

      parse() 方法类似,只不过它要求输入为一个 而不是类文件对象。于一个 bytes-like object 调用此方法相当于先将这些字节包装于一个 实例中,然后调用 parse() 方法。

      可选的 headersonly 与 方法中的 headersonly 是一致的。

    3.2 新版功能.

    class email.parser.BytesHeaderParser(_class=None, **, policy=policy.compat32*)

    除了 headersonly 默认为 True,其他与 BytesParser 类完全一样。

    3.3 新版功能.

    class email.parser.Parser(_class=None, **, policy=policy.compat32*)

    这个类与 一样,但是处理字符串输入。

    在 3.3 版更改: 移除了strict参数。添加了policy关键字。

    在 3.6 版更改: _class 默认为策略 message_factory

    • (text, headersonly=False)

      parse() 方法类似,只不过它要求输入为一个字符串而不是类文件对象。 于一个字符串对象调用此方法相当于先将 text 包装于一个 实例中,然后调用 parse() 方法。

    class email.parser.HeaderParser(_class=None, **, policy=policy.compat32*)

    除了 headersonly 默认为 True,其他与 类完全一样。

    考虑到从一个字符串或一个文件对象中创建一个消息对象是非常常见的任务,我们提供了四个方便的函数。它们于顶层 email 包命名空间内可用。

    email.message_from_bytes(s, _class=None, **, policy=policy.compat32*)

    从一个 中返回消息对象。 这与 BytesParser().parsebytes(s) 等价。 可选的 _classpolicy 参数与 BytesParser 类的构造函数的参数含义一致。

    3.2 新版功能.

    在 3.3 版更改: 移除了strict参数。添加了policy关键字。

    email.message_from_binary_file(fp, _class=None, **, policy=policy.compat32*)

    从打开的二进制 中返回消息对象。 这与 BytesParser().parse(fp) 等价。 _classpolicy 参数与 BytesParser 类的构造函数的参数含义一致。

    3.2 新版功能.

    在 3.3 版更改: 移除了strict参数。添加了policy关键字。

    email.message_from_string(s, _class=None, **, policy=policy.compat32*)

    从一个字符串中返回消息对象。 这与 Parser().parsestr(s) 等价。 _classpolicy 参数与 类的构造函数的参数含义一致。

    在 3.3 版更改: 移除了strict参数。添加了policy关键字。

    email.message_from_file(fp, _class=None, **, policy=policy.compat32*)

    从一个打开的 file object 中返回消息对象。 这与 Parser().parse(fp) 等价。 _classpolicy 参数与 类的构造函数的参数含义一致。

    在 3.3 版更改: 移除了strict参数。添加了policy关键字。

    在 3.6 版更改: _class 默认为策略 message_factory

    这里是一个展示了你如何在Python交互式命令行中使用 message_from_bytes() 的例子:

    在解析语义的时候请注意:

    • 大多数非 multipart 类型的消息都会被解析为一个带有字符串负载的消息对象。这些对象在调用 的时候会返回``False``,调用 iter_parts() 的时候会返回一个空列表。

    • 所有 multipart 类型的消息都会被解析成一个容器消息对象。该对象的负载是一个子消息对象列表。外层的容器消息在调用 的时候会返回``True``,在调用 iter_parts() 的时候会产生一个子部分列表。