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

源代碼: Lib/email/parser.py


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

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

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

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

FeedParser API?

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

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

這里是 BytesFeedParser 的 API:

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

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

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

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

3.2 新版功能.

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

在 3.6 版更改: _factory 默認(rèn)為策略 message_factory。

feed(data)?

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

close()?

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

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

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

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

Parser API?

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

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

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

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

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

在 3.6 版更改: _class 默認(rèn)為策略 message_factory。

parse(fp, headersonly=False)?

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

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

可選的 headersonly 指示了是否應(yīng)當(dāng)在讀取完消息頭后就終止。默認(rèn)值為 False ,意味著它會(huì)解析整個(gè)文件的全部?jī)?nèi)容。

parsebytes(bytes, headersonly=False)?

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

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

3.2 新版功能.

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

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

3.3 新版功能.

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

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

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

在 3.6 版更改: _class 默認(rèn)為策略 message_factory。

parse(fp, headersonly=False)?

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

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

parsestr(text, headersonly=False)?

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

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

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

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

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

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

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

3.2 新版功能.

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

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

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

3.2 新版功能.

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

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

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

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

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

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

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

在 3.6 版更改: _class 默認(rèn)為策略 message_factory。

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

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

附加說(shuō)明?

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

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

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

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

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