email.parser:解析电子邮件消息

源代码: Lib/email/parser.py


消息对象结构可以通过两种方式创建:可以通过创建一个 EmailMessage 对象,使用字典接口添加标头,并使用 set_content() 及相关方法添加有效载荷来从头创建;也可以通过解析电子邮件消息的序列化表示来创建。

email 包提供了一个标准解析器,可以理解大多数电子邮件文档结构,包括 MIME 文档。你可以向解析器传递一个字节串、字符串或文件对象,解析器将返回对象结构的根 EmailMessage 实例。对于简单的非 MIME 消息,此根对象的有效载荷可能是一个包含消息文本的字符串。对于 MIME 消息,根对象的 is_multipart() 方法将返回 True,并且可以通过有效载荷操作方法(如 get_body()iter_parts()walk())访问其子部分。

实际上有两种解析器接口可供使用:Parser API 和增量式的 FeedParser API。Parser API 在你已将消息的全部文本加载到内存中,或者整个消息存在于文件系统上的文件中时最为有用。FeedParser 更适用于从可能因等待更多输入而阻塞的流中读取消息(例如从套接字读取电子邮件消息)。FeedParser 可以增量地消费和解析消息,并且只有在关闭解析器时才返回根对象。

请注意,解析器可以在有限的范围内进行扩展,当然你也可以完全从头开始实现自己的解析器。所有连接 email 包的内置解析器和 EmailMessage 类的逻辑都体现在 Policy 类中,因此自定义解析器可以通过实现相应 Policy 方法的自定义版本,以其认为必要的任何方式创建消息对象树。

FeedParser API

email.feedparser 模块导入的 BytesFeedParser 提供了一个有助于增量解析电子邮件消息的 API,例如在从可能阻塞的源(如套接字)读取电子邮件消息文本时所必需的。当然,BytesFeedParser 也可以用于解析完全包含在类字节对象、字符串或文件中的电子邮件消息,但对于此类用例,BytesParser API 可能更方便。这两种解析器 API 的语义和结果是相同的。

BytesFeedParser 的 API 很简单;你创建一个实例,向其输入字节数据直到没有更多数据可输入,然后关闭解析器以检索根消息对象。在解析符合标准的消息时,BytesFeedParser 非常准确,并且在解析不符合标准的消息方面也做得很好,会提供有关消息如何被判定为损坏的信息。它会将消息中发现的任何问题列表填充到消息对象的 defects 属性中。请参阅 email.errors 模块以获取它能发现的缺陷列表。

以下是 BytesFeedParser 的 API:

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

创建一个 BytesFeedParser 实例。可选的 _factory 是一个无参数的可调用对象;如果未指定,则使用 policymessage_factory。每当需要新的消息对象时,就会调用 _factory

如果指定了 policy,则使用它指定的规则来更新消息的表示。如果未设置 policy,则使用 compat32 策略,该策略保持与 Python 3.2 版本的 email 包的向后兼容性,并提供 Message 作为默认工厂。所有其他策略都提供 EmailMessage 作为默认的 _factory。有关 policy 控制的其他内容的更多信息,请参阅 policy 文档。

注意:应始终指定 policy 关键字;在 Python 的未来版本中,默认值将更改为 email.policy.default

在 3.2 版本加入。

在 3.3 版本发生变更: 添加了 policy 关键字。

在 3.6 版本发生变更: _factory 默认为策略的 message_factory

feed(data)

向解析器输入更多数据。data 应为一个包含一行或多行文本的类字节对象。这些行可以是部分的,解析器会正确地将这些部分行拼接起来。这些行可以有三种常见的行尾符:回车、换行或回车加换行(它们甚至可以混合使用)。

close()

完成对所有先前输入数据的解析,并返回根消息对象。在此方法被调用后,如果再调用 feed(),其行为是未定义的。

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

工作方式与 BytesFeedParser 类似,但 feed() 方法的输入必须是字符串。这个类的用途有限,因为要使这样的消息有效,它要么只能包含 ASCII 文本,要么在 utf8True 的情况下,不包含二进制附件。

在 3.3 版本发生变更: 添加了 policy 关键字。

Parser API

email.parser 模块导入的 BytesParser 类提供了一个 API,当消息的全部内容都可在一个类字节对象或文件中获取时,可以用它来解析消息。email.parser 模块还提供了用于解析字符串的 Parser,以及只解析标头的解析器 BytesHeaderParserHeaderParser,如果你只对消息的标头感兴趣,可以使用它们。在这些情况下,BytesHeaderParserHeaderParser 可以快得多,因为它们不尝试解析消息正文,而是将有效载荷设置为原始正文。

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

创建一个 BytesParser 实例。_classpolicy 参数的含义和语义与 BytesFeedParser_factorypolicy 参数相同。

注意:应始终指定 policy 关键字;在 Python 的未来版本中,默认值将更改为 email.policy.default

在 3.3 版本发生变更: 移除了在 2.4 版本中已弃用的 strict 参数。添加了 policy 关键字。

在 3.6 版本发生变更: _class 默认为策略的 message_factory

parse(fp, headersonly=False)

从二进制类文件对象 fp 中读取所有数据,解析得到的字节串,并返回消息对象。fp 必须同时支持 readline()read() 方法。

fp 中包含的字节必须格式化为一个 RFC 5322(或者,如果 utf8True,则为 RFC 6532)风格的标头和标头续行块,前面可以选择性地带有一个信封标头。标头块以数据末尾或一个空行结束。标头块之后是消息的正文(可能包含 MIME 编码的子部分,包括 Content-Transfer-Encoding8bit 的子部分)。

可选的 headersonly 是一个标志,指定是否在读取标头后停止解析。默认为 False,表示解析文件的全部内容。

parsebytes(bytes, headersonly=False)

parse() 方法类似,但它接受一个类字节对象而不是一个类文件对象。对一个类字节对象调用此方法,等同于先将 bytes 包装在 BytesIO 实例中,然后调用 parse()

可选的 headersonlyparse() 方法中的一样。

在 3.2 版本加入。

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

BytesParser 完全相同,只是 headersonly 默认为 True

在 3.3 版本加入。

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

这个类与 BytesParser 并行,但处理字符串输入。

在 3.3 版本发生变更: 移除了 strict 参数。添加了 policy 关键字。

在 3.6 版本发生变更: _class 默认为策略的 message_factory

parse(fp, headersonly=False)

从文本模式的类文件对象 fp 中读取所有数据,解析得到的文本,并返回根消息对象。fp 必须同时支持类文件对象的 readline()read() 方法。

除了文本模式的要求外,此方法的操作方式与 BytesParser.parse() 类似。

parsestr(text, headersonly=False)

parse() 方法类似,但它接受一个字符串对象而不是一个类文件对象。对一个字符串调用此方法,等同于先将 text 包装在 StringIO 实例中,然后调用 parse()

可选的 headersonlyparse() 方法中的一样。

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

Parser 完全相同,只是 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 的解释与 Parser 类的构造函数一样。

在 3.3 版本发生变更: 移除了 strict 参数。添加了 policy 关键字。

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

从一个打开的文件对象返回一个消息对象结构树。这等同于 Parser().parse(fp)_classpolicy 的解释与 Parser 类的构造函数一样。

在 3.3 版本发生变更: 移除了 strict 参数。添加了 policy 关键字。

在 3.6 版本发生变更: _class 默认为策略的 message_factory

以下是在 Python 交互式提示符下如何使用 message_from_bytes() 的示例:

>>> import email
>>> msg = email.message_from_bytes(myBytes)

附加说明

以下是关于解析语义的一些说明:

  • 大多数非 multipart 类型的消息被解析为带有一个字符串有效载荷的单个消息对象。这些对象的 is_multipart() 会返回 False,而 iter_parts() 将产生一个空列表。

  • 所有 multipart 类型的消息将被解析为一个容器消息对象,其有效载荷为子消息对象的列表。外部容器消息的 is_multipart() 将返回 True,而 iter_parts() 将产生一个子部分列表。

  • 大多数内容类型为 message/* 的消息(例如 message/delivery-statusmessage/rfc822)也将被解析为包含一个长度为 1 的列表有效载荷的容器对象。它们的 is_multipart() 方法将返回 Trueiter_parts() 产生的单个元素将是一个子消息对象。

  • 一些不符合标准的消息可能在其 multipart-edness(多部分性)上内部不一致。此类消息可能有一个类型为 multipartContent-Type 标头,但其 is_multipart() 方法可能返回 False。如果此类消息是使用 FeedParser 解析的,它们的 defects 属性列表中将包含一个 MultipartInvariantViolationDefect 类的实例。有关详细信息,请参阅 email.errors