email.parser: 解析電子郵件信息?

源代碼: Lib/email/parser.py


使用以下兩種方法的其中一種以創(chuàng )建消息對象結構:直接創(chuàng )建一個(gè) EmailMessage 對象,使用字典接口添加消息頭,并且使用 set_content() 和其他相關(guān)方法添加消息負載;或者通過(guò)解析一個(gè)電子郵件消息的序列化表達來(lái)創(chuàng )建消息對象結構。

email 包提供了一個(gè)可以理解包含 MIME 文檔在內的絕大多數電子郵件文檔結構的標準語(yǔ)法分析程序。 你可以傳遞給語(yǔ)法分析程序一個(gè)字節串、字符串或者文件對象,語(yǔ)法分析程序會(huì )返回給你對應于該對象結構的根 EmailMessage 實(shí)例。 對于簡(jiǎn)單的、非 MIME 的消息,這個(gè)根對象的負載很可能就是一個(gè)包含了該消息文字內容的字符串。 對于 MIME 消息,調用根對象的 is_multipart() 方法會(huì )返回 True,其子項可以通過(guò)負載操縱方法來(lái)進(jìn)行訪(fǎng)問(wèn),例如 get_body()、iter_parts() 還有 walk()。

事實(shí)上你可以使用的語(yǔ)法分析程序接口有兩種: Parser API 和增量式的 FeedParser API。當你的全部消息內容都在內存當中,或者整個(gè)消息都保存在文件系統內的一個(gè)文件當中的時(shí)候,Parser API非常有用。當你從可能會(huì )為了等待更多輸入而阻塞的數據流當中讀取消息(比如從套接字當中讀取電子郵件消息)的時(shí)候,FeedParser 會(huì )更合適。FeedParser 會(huì )增量讀取并解析消息,并且只有在你關(guān)閉語(yǔ)法分析程序的時(shí)候才會(huì )返回根對象。

請注意,語(yǔ)法分析程序可以進(jìn)行有限的拓展,你當然也可以完全從零開(kāi)始實(shí)現你自己的語(yǔ)法分析程序。將 email 包中內置的語(yǔ)法分析程序和 EmailMessage 類(lèi)連接起來(lái)的所有邏輯代碼都包含在 policy 類(lèi)當中,所以如有必要,自定義的語(yǔ)法分析程序可以通過(guò)實(shí)現自定義的對應 policy 方法來(lái)創(chuàng )建對應的消息對象樹(shù)。

FeedParser API?

email.feedparser 模塊導入的 BytesFeedParser 類(lèi)提供了一個(gè)適合于增量解析電子郵件消息的API,比如說(shuō)在從一個(gè)可能會(huì )阻塞(例如套接字)的源當中讀取消息文字的場(chǎng)合中它就會(huì )變得很有用。當然, BytesFeedParser 也可以用來(lái)解析一個(gè)已經(jīng)完整包含在一個(gè) bytes-like object 、字符串或文件內的電子郵件消息,但是在這些場(chǎng)合下使用 BytesParser API可能會(huì )更加方便。這兩個(gè)語(yǔ)法分析程序API的語(yǔ)義和最終結果是一致的。

BytesFeedParser 的API十分簡(jiǎn)潔易懂:你創(chuàng )建一個(gè)語(yǔ)法分析程序的實(shí)例,向它不斷輸入大量的字節直到盡頭,然后關(guān)閉這個(gè)語(yǔ)法分析程序就可以拿到根消息對象了。 在處理符合標準的消息的時(shí)候 BytesFeedParser 非常準確;在處理不符合標準的消息的時(shí)候它做的也不差,但這視消息損壞的程度而定。它會(huì )向消息對象的 defects 屬性中寫(xiě)入它從消息中找到的問(wèn)題列表。關(guān)于它能找到的所有問(wèn)題類(lèi)型的列表,詳見(jiàn) email.errors 模塊。

這里是 BytesFeedParser 的 API:

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

創(chuàng )建一個(gè) BytesFeedParser 實(shí)例??蛇x的 _factory 參數是一個(gè)不帶參數的可調用對象;如果沒(méi)有被指定,就會(huì )使用 policy 參數的 message_factory 屬性。 每當需要一個(gè)新的消息對象的時(shí)候,_factory 都會(huì )被調用。

如果指定了 policy 參數,它就會(huì )使用這個(gè)參數所指定的規則來(lái)更新消息的表達方式。 如果沒(méi)有設定 policy 參數,它就會(huì )使用 compat32 策略。 這個(gè)策略維持了對 Python 3.2 版本的 email 包的后向兼容性,并且使用 Message 作為默認的工廠(chǎng)。 其他策略使用 EmailMessage 作為默認的 _factory。 關(guān)于 policy 還會(huì )控制什么,參見(jiàn) policy 的文檔。

注: 一定要指定policy關(guān)鍵字。 在未來(lái)版本的 Python 當中,它的默認值會(huì )變成 email.policy.default。

3.2 新版功能.

在 3.3 版更改: 添加了 policy 關(guān)鍵字。

在 3.6 版更改: _factory 默認為策略 message_factory。

feed(data)?

向語(yǔ)法分析程序輸入更多數據。data 應當是一個(gè)包含一行或多行內容的 bytes-like object。 行內容可以是不完整的,語(yǔ)法分析程序會(huì )妥善的將這些不完整的行縫合在一起。每一行可以使用以下三種常見(jiàn)的終止符號的其中一種:回車(chē)符、換行符或回車(chē)符加換行符(三者甚至可以混合使用)。

close()?

完成之前輸入的所有數據的解析并返回根消息對象。 如果在這個(gè)方法被調用之后仍然調用 feed() 方法,結果是未定義的。

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

行為跟 BytesFeedParser 類(lèi)一致,只不過(guò)向 feed() 方法輸入的內容必須是字符串。它的實(shí)用性有限,因為這種消息只有在其只含有ASCII文字,或者 utf8 被設置為 True 且沒(méi)有二進(jìn)制格式的附件的時(shí)候,才會(huì )有效。

在 3.3 版更改: 添加了 policy 關(guān)鍵字。

Parser API?

BytesParser 類(lèi)從 email.parser 模塊導入,當消息的完整內容包含在一個(gè) bytes-like object 或文件中時(shí)它提供了可用于解析消息的 API。 email.parser 模塊還提供了 Parser 用來(lái)解析字符串,以及只用來(lái)解析消息頭的 BytesHeaderParserHeaderParser,如果你只對消息頭感興趣就可以使用后兩者。 在這種場(chǎng)合下 BytesHeaderParserHeaderParser 速度非???,因為它們并不會(huì )嘗試解析消息體,而是將載荷設為原始數據。

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

創(chuàng )建一個(gè) BytesParser 實(shí)例。 _classpolicy 參數在含義和語(yǔ)義上與 BytesFeedParser_factorypolicy 參數一致。

注: 一定要指定policy關(guān)鍵字。 在未來(lái)版本的 Python 當中,它的默認值會(huì )變成 email.policy.default。

在 3.3 版更改: 移除了在2.4版本中被棄用的 strict 參數。新增了 policy 關(guān)鍵字。

在 3.6 版更改: _class 默認為策略 message_factory。

parse(fp, headersonly=False)?

從二進(jìn)制的類(lèi)文件對象 fp 中讀取全部數據、解析其字節內容、并返回消息對象。 fp 必須同時(shí)支持 readline() 方法和 read() 方法。

fp 內包含的字節內容必須是一塊遵循 RFC 5322 (如果 utf8True,則為 RFC 6532 )格式風(fēng)格的消息頭和消息頭延續行,并可能緊跟一個(gè)信封頭。 頭塊要么以數據結束,要么以一個(gè)空行為終止。 跟著(zhù)頭塊的是消息體(消息體內可能包含 MIME 編碼的子部分,這也包括 Content-Transfer-Encoding 字段為 8bit 的子部分)。

可選的 headersonly 指示了是否應當在讀取完消息頭后就終止。默認值為 False ,意味著(zhù)它會(huì )解析整個(gè)文件的全部?jì)热荨?/p>

parsebytes(bytes, headersonly=False)?

parse() 方法類(lèi)似,只不過(guò)它要求輸入為一個(gè) bytes-like object 而不是類(lèi)文件對象。于一個(gè) bytes-like object 調用此方法相當于先將這些字節包裝于一個(gè) BytesIO 實(shí)例中,然后調用 parse() 方法。

可選的 headersonlyparse() 方法中的 headersonly 是一致的。

3.2 新版功能.

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

除了 headersonly 默認為 True,其他與 BytesParser 類(lèi)完全一樣。

3.3 新版功能.

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

這個(gè)類(lèi)與 BytesParser 一樣,但是處理字符串輸入。

在 3.3 版更改: 移除了 strict 參數。添加了 policy 關(guān)鍵字。

在 3.6 版更改: _class 默認為策略 message_factory。

parse(fp, headersonly=False)?

從文本模式的文件類(lèi)對象 fp 讀取所有數據,解析所讀取的文本,并返回根消息對象。 fp 必須同時(shí)支持文件類(lèi)對象上的 readline()read() 方法。

除了文字模式的要求外,這個(gè)方法跟 BytesParser.parse() 的運行方式一致。

parsestr(text, headersonly=False)?

parse() 方法類(lèi)似,只不過(guò)它要求輸入為一個(gè)字符串而不是類(lèi)文件對象。于一個(gè)字符串對象調用此方法相當于先將 text 包裝于一個(gè) StringIO 實(shí)例中,然后調用 parse() 方法。

可選的 headersonlyparse() 方法中的 headersonly 是一致的。

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

除了 headersonly 默認為 True ,其他與 Parser 類(lèi)完全一樣。

考慮到從一個(gè)字符串或一個(gè)文件對象中創(chuàng )建一個(gè)消息對象是非常常見(jiàn)的任務(wù),我們提供了四個(gè)方便的函數。它們于頂層 email 包命名空間內可用。

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

從一個(gè) bytes-like object 中返回消息對象。 這與 BytesParser().parsebytes(s) 等價(jià)。 可選的 _classpolicy 參數與 BytesParser 類(lèi)的構造函數的參數含義一致。

3.2 新版功能.

在 3.3 版更改: 移除了 strict 參數。添加了 policy 關(guān)鍵字。

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

從打開(kāi)的二進(jìn)制 file object 中返回消息對象。 這與 BytesParser().parse(fp) 等價(jià)。 _classpolicy 參數與 BytesParser 類(lèi)的構造函數的參數含義一致。

3.2 新版功能.

在 3.3 版更改: 移除了 strict 參數。添加了 policy 關(guān)鍵字。

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

從一個(gè)字符串中返回消息對象。 這與 Parser().parsestr(s) 等價(jià)。 _classpolicy 參數與 Parser 類(lèi)的構造函數的參數含義一致。

在 3.3 版更改: 移除了 strict 參數。添加了 policy 關(guān)鍵字。

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

從一個(gè)打開(kāi)的 file object 中返回消息對象。 這與 Parser().parse(fp) 等價(jià)。 _classpolicy 參數與 Parser 類(lèi)的構造函數的參數含義一致。

在 3.3 版更改: 移除了 strict 參數。添加了 policy 關(guān)鍵字。

在 3.6 版更改: _class 默認為策略 message_factory。

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

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

附加說(shuō)明?

在解析語(yǔ)義的時(shí)候請注意:

  • 大多數非 multipart 類(lèi)型的消息都會(huì )被解析為一個(gè)帶有字符串負載的消息對象。這些對象在調用 is_multipart() 的時(shí)候會(huì )返回 False ,調用 iter_parts() 的時(shí)候會(huì )產(chǎn)生一個(gè)空列表。

  • 所有 multipart 類(lèi)型的消息都會(huì )被解析成一個(gè)容器消息對象。該對象的負載是一個(gè)子消息對象列表。外層的容器消息在調用 is_multipart() 的時(shí)候會(huì )返回 True ,在調用 iter_parts() 的時(shí)候會(huì )產(chǎn)生一個(gè)子部分列表。

  • 大多數內容類(lèi)型為 message/* (例如 message/delivery-statusmessage/rfc822 )的消息也會(huì )被解析為一個(gè)負載是長(cháng)度為1的列表的容器對象。在它們身上調用 is_multipart() 方法會(huì )返回 True ,調用 iter_parts() 所產(chǎn)生的單個(gè)元素會(huì )是一個(gè)子消息對象。

  • 一些不遵循標準的消息在其內部關(guān)于它是否為 multipart 類(lèi)型前后不一。這些消息可能在消息頭的 Content-Type 字段中寫(xiě)明為 multipart ,但它們的 is_multipart() 方法的返回值可能是 False 。如果這種消息被 FeedParser 類(lèi)解析,它們的 defects 屬性列表當中會(huì )有一個(gè) MultipartInvariantViolationDefect 類(lèi)的實(shí)例。關(guān)于更多信息,詳見(jiàn) email.errors 。