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

源代碼: Lib/email/parser.py


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

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

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

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

FeedParser API?

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

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

這里是 BytesFeedParser 的 API:

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

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

如果指定了 policy 參數(shù),它就會使用這個參數(shù)所指定的規(guī)則來更新消息的表達方式。 如果沒有設定 policy 參數(shù),它就會使用 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)?

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

close()?

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

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

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

在 3.3 版更改: 添加了 policy 關鍵字。

Parser API?

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

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

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

注: 一定要指定policy關鍵字。 在未來版本的 Python 當中,它的默認值會變成 email.policy.default。

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

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

parse(fp, headersonly=False)?

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

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

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

parsebytes(bytes, headersonly=False)?

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

可選的 headersonlyparse() 方法中的 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)?

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

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

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

parse(fp, headersonly=False)?

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

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

parsestr(text, headersonly=False)?

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

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

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

除了 headersonly 默認為 True ,其他與 Parser 類完全一樣。

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

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

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

3.2 新版功能.

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

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

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

3.2 新版功能.

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

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

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

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

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

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

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

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

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

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

附加說明?

在解析語義的時候請注意:

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

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

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

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