email.message:表示一封電子郵件

原始碼:Lib/email/message.py


在 3.6 版本加入: [1]

email 包的核心類是 EmailMessage 類,它從 email.message 模組匯入。它是 email 物件模型的基礎類。EmailMessage 提供了設定和查詢頭欄位、訪問訊息正文以及建立或修改結構化訊息的核心功能。

一封電子郵件由*標頭*和*有效負載*(也稱為*內容*)組成。標頭是 RFC 5322RFC 6532 風格的欄位名和值,欄位名和值之間用冒號分隔。冒號既不屬於欄位名也不屬於欄位值。有效負載可以是一個簡單的文字訊息、一個二進位制物件,或者是一個結構化的子訊息序列,每個子訊息都有自己的標頭集和有效負載。後一種型別的有效負載由訊息的 MIME 型別指示,例如 multipart/*message/rfc822

EmailMessage 物件提供的概念模型是一個有序的標頭字典,加上一個代表訊息的 RFC 5322 主體的*有效負載*,它可能是一個子 EmailMessage 物件的列表。除了用於訪問標頭名稱和值的常規字典方法外,還有一些方法用於從標頭訪問特殊資訊(例如 MIME 內容型別)、操作有效負載、生成訊息的序列化版本以及遞迴地遍歷物件樹。

EmailMessage 的類字典介面以標頭名稱為索引,標頭名稱必須是 ASCII 值。字典的值是帶有某些額外方法的字串。標頭以保留大小寫形式儲存和返回,但欄位名匹配不區分大小寫。鍵是有序的,但與真正的字典不同,可以有重複的鍵。提供了額外的方法來處理具有重複鍵的標頭。

對於簡單的訊息物件,*有效負載*是字串或位元組物件;對於MIME容器文件(如multipart/*message/rfc822 訊息物件),它是一個 EmailMessage 物件的列表。

class email.message.EmailMessage(policy=default)

如果指定了*policy*,則使用其指定的規則來更新和序列化訊息的表示。如果未設定*policy*,則使用 default 策略,該策略遵循電子郵件 RFC 的規則,但行尾除外(它使用 Python 標準的 \n 行尾,而不是 RFC 強制的 \r\n)。更多資訊請參見 policy 文件。

as_string(unixfrom=False, maxheaderlen=None, policy=None)

將整個訊息扁平化為一個字串返回。當可選引數*unixfrom*為真時,信封頭會包含在返回的字串中。*unixfrom* 預設為 False。為了向後相容基類 Message,*maxheaderlen* 引數被接受,但預設為 None,這意味著預設情況下行長由策略的 max_line_length 控制。*policy* 引數可用於覆蓋從訊息例項獲取的預設策略。這可以用來控制該方法產生的一些格式,因為指定的 *policy* 將被傳遞給 Generator

扁平化訊息可能會觸發對 EmailMessage 的更改,如果需要填充預設值來完成向字串的轉換(例如,可能會生成或修改 MIME 邊界)。

請注意,此方法是為方便起見而提供的,在您的應用程式中可能不是序列化訊息的最有用方式,特別是當您處理多個訊息時。請參閱 email.generator.Generator 以獲取更靈活的訊息序列化 API。另請注意,當 utf8False(預設值)時,此方法僅限於生成序列化為“7 位清潔”的訊息。

在 3.6 版更改: 當*maxheaderlen*未指定時,預設行為從預設為 0 更改為預設為策略中的*max_line_length*值。

__str__()

等價於 as_string(policy=self.policy.clone(utf8=True))。允許 str(msg) 生成一個包含序列化訊息的可讀格式的字串。

在 3.4 版更改: 該方法已更改為使用 utf8=True,從而產生類似 RFC 6531 的訊息表示,而不是直接作為 as_string() 的別名。

as_bytes(unixfrom=False, policy=None)

將整個訊息扁平化為一個位元組物件返回。當可選的*unixfrom*為真時,信封頭會包含在返回的字串中。*unixfrom*預設為False。*policy*引數可用於覆蓋從訊息例項獲取的預設策略。這可以用來控制該方法產生的一些格式,因為指定的*policy*將被傳遞給BytesGenerator

扁平化訊息可能會觸發對 EmailMessage 的更改,如果需要填充預設值來完成向字串的轉換(例如,可能會生成或修改 MIME 邊界)。

請注意,此方法是為方便起見而提供的,在您的應用程式中可能不是序列化訊息的最有用方式,特別是當您處理多個訊息時。請參閱 email.generator.BytesGenerator 以獲取更靈活的訊息序列化 API。

__bytes__()

等價於 as_bytes()。允許 bytes(msg) 生成一個包含序列化訊息的位元組物件。

is_multipart()

如果訊息的有效負載是子 EmailMessage 物件的列表,則返回 True,否則返回 False。當 is_multipart() 返回 False 時,有效負載應該是一個字串物件(可能是一個經過 CTE 編碼的二進位制有效負載)。請注意,is_multipart() 返回 True 並不一定意味著 “msg.get_content_maintype() == 'multipart'” 會返回 True。例如,當 EmailMessage 的型別為 message/rfc822 時,is_multipart 將返回 True

set_unixfrom(unixfrom)

將訊息的信封頭設定為*unixfrom*,它應該是一個字串。(關於這個頭的簡要描述,請參閱 mboxMessage。)

get_unixfrom()

返回訊息的信封頭。如果信封頭從未被設定,則預設為 None

以下方法實現了用於訪問訊息標頭的類對映介面。請注意,這些方法與正常的對映(即字典)介面之間存在一些語義差異。例如,在字典中沒有重複的鍵,但在這裡可能有重複的訊息標頭。此外,在字典中,keys() 返回的鍵沒有保證的順序,但在 EmailMessage 物件中,標頭總是按照它們在原始訊息中出現的順序或者稍後新增到訊息中的順序返回。任何被刪除然後重新新增的標頭總是被附加到標頭列表的末尾。

這些語義差異是刻意為之的,旨在為最常見的使用場景提供便利。

請注意,在所有情況下,訊息中存在的任何信封頭都不包含在對映介面中。

__len__()

返回包括重複項在內的標頭總數。

__contains__(name)

如果訊息物件有一個名為*name*的欄位,則返回True。匹配不區分大小寫,*name*不包括末尾的冒號。用於in運算子。例如:

if 'message-id' in myMessage:
   print('Message-ID:', myMessage['message-id'])
__getitem__(name)

返回指定標頭欄位的值。*name* 不包含冒號欄位分隔符。如果標頭缺失,返回 None;絕不會引發 KeyError

請注意,如果指定的欄位在訊息頭中出現多次,究竟返回哪個欄位值是未定義的。請使用 get_all() 方法來獲取所有名為 *name* 的現有頭的值。

使用標準(非 compat32)策略時,返回的值是 email.headerregistry.BaseHeader 子類的例項。

__setitem__(name, val)

向訊息中新增一個欄位名為*name*,值為*val*的標頭。該欄位被附加到訊息現有標頭的末尾。

請注意,這*不會*覆蓋或刪除任何具有相同名稱的現有標頭。如果您想確保新標頭是訊息中唯一一個欄位名為*name*的標頭,請先刪除該欄位,例如:

del msg['subject']
msg['subject'] = 'Python roolz!'

如果 policy 將某些頭定義為唯一的(就像標準策略一樣),當嘗試為一個已存在的此類頭賦值時,此方法可能會引發 ValueError。這種行為是為了保持一致性而有意為之的,但不要依賴它,因為我們將來可能會選擇讓這類賦值自動刪除現有的頭。

__delitem__(name)

從訊息的標頭中刪除所有名為*name*的欄位。如果指定的欄位不存在於標頭中,不會引發異常。

keys()

返回一個包含訊息所有標頭欄位名的列表。

values()

返回訊息所有欄位值的列表。

items()

返回一個包含所有訊息欄位頭和值的二元組列表。

get(name, failobj=None)

返回指定標頭欄位的值。這與 __getitem__() 相同,只是如果指定的標頭不存在,則返回可選的 *failobj*(*failobj* 預設為 None)。

以下是一些其他有用的與標頭相關的方法:

get_all(name, failobj=None)

返回名為*name*的欄位的所有值的列表。如果訊息中沒有這樣的標頭,則返回*failobj*(預設為None)。

add_header(_name, _value, **_params)

擴充套件的標頭設定。此方法類似於 __setitem__(),但可以作為關鍵字引數提供額外的標頭引數。*_name* 是要新增的標頭欄位,*_value* 是標頭的*主要*值。

對於關鍵字引數字典*_params*中的每一項,鍵被視為引數名,下劃線會轉換成短橫線(因為短橫線在 Python 識別符號中是非法的)。通常,引數會以 key="value" 的形式新增,除非值為 None,這種情況下只會新增鍵。

如果值包含非 ASCII 字元,可以透過將值指定為 (CHARSET, LANGUAGE, VALUE) 格式的三元組來顯式控制字元集和語言。其中 CHARSET 是一個字串,指定用於編碼值的字元集;LANGUAGE 通常可以設定成 None 或空字串(其他可能性請參見 RFC 2231);VALUE 是包含非 ASCII 碼點的字串值。如果未傳遞三元組且值包含非 ASCII 字元,它將使用 utf-8CHARSETNoneLANGUAGE 自動以 RFC 2231 格式進行編碼。

下面是一個例子:

msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')

這將新增一個如下所示的標頭:

Content-Disposition: attachment; filename="bud.gif"

一個使用非 ASCII 字元的擴充套件介面示例:

msg.add_header('Content-Disposition', 'attachment',
               filename=('iso-8859-1', '', 'Fußballer.ppt'))
replace_header(_name, _value)

替換標頭。替換訊息中找到的第一個與*_name*匹配的標頭,保留原始標頭的順序和欄位名大小寫。如果沒有找到匹配的標頭,則引發 KeyError

get_content_type()

返回訊息的內容型別,強制轉換為 maintype/subtype 形式的小寫字串。如果訊息中沒有 Content-Type 標頭,則返回 get_default_type() 的返回值。如果 Content-Type 標頭無效,則返回 text/plain

(根據 RFC 2045,訊息總有一個預設型別,所以 get_content_type() 總是會返回一個值。RFC 2045 定義訊息的預設型別為 text/plain,除非它出現在一個 multipart/digest 容器內,在這種情況下,它的預設型別將是 message/rfc822。如果 Content-Type 標頭的型別規範無效,RFC 2045 規定預設型別應為 text/plain。)

get_content_maintype()

返回訊息的主要內容型別。這是 get_content_type() 返回的字串的 maintype 部分。

get_content_subtype()

返回訊息的子內容型別。這是由 get_content_type() 返回的字串的 subtype 部分。

get_default_type()

返回預設的內容型別。大多數訊息的預設內容型別是text/plain,但作為multipart/digest容器子部分的訊息除外。這類子部分的預設內容型別是message/rfc822

set_default_type(ctype)

設定預設內容型別。*ctype* 應該是 text/plainmessage/rfc822,儘管這並非強制要求。預設內容型別不儲存在 Content-Type 標頭中,因此它僅在訊息中不存在 Content-Type 標頭時影響 get_content_type 方法的返回值。

set_param(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)

Content-Type 標頭中設定一個引數。如果該引數已存在於標頭中,則將其值替換為 *value*。當 *header* 是 Content-Type(預設值)且訊息中尚不存在該標頭時,會新增該標頭,將其值設定為 text/plain,並附加新的引數值。可選的 *header* 指定了除 Content-Type 之外的備用標頭。

如果值包含非 ASCII 字元,可以使用可選的 *charset* 和 *language* 引數顯式指定字元集和語言。可選的 *language* 指定了 RFC 2231 語言,預設為空字串。*charset* 和 *language* 都應該是字串。預設是使用 utf8 *charset* 和 None 作為 *language*。

如果*replace*為False(預設值),標頭會被移動到標頭列表的末尾。如果*replace*為True,標頭將在原地更新。

不推薦在 EmailMessage 物件中使用 *requote* 引數。

請注意,可以透過頭值的 params 屬性訪問頭的現有引數值(例如,msg['Content-Type'].params['charset'])。

在 3.4 版更改: 添加了 replace 關鍵字。

del_param(param, header='content-type', requote=True)

Content-Type 標頭中完全移除給定的引數。標頭將在原地重寫,不包含該引數及其值。可選的 *header* 指定了除 Content-Type 之外的備選標頭。

不推薦在 EmailMessage 物件中使用 *requote* 引數。

get_filename(failobj=None)

返回訊息 Content-Disposition 標頭中 filename 引數的值。如果該標頭沒有 filename 引數,此方法會退而查詢 Content-Type 標頭上的 name 引數。如果兩者都未找到,或標頭缺失,則返回 *failobj*。返回的字串將始終根據 email.utils.unquote() 去除引號。

get_boundary(failobj=None)

返回訊息的Content-Type標頭中boundary引數的值,如果標頭缺失或沒有boundary引數,則返回*failobj*。返回的字串將始終根據email.utils.unquote()進行反引號處理。

set_boundary(boundary)

Content-Type 標頭的 boundary 引數設定為 *boundary*。set_boundary() 會在必要時始終為 *boundary* 新增引號。如果訊息物件沒有 Content-Type 標頭,則會引發 HeaderParseError

請注意,使用此方法與刪除舊的 Content-Type 標頭並透過 add_header() 新增帶有新邊界的新標頭有細微差別,因為 set_boundary() 會保留 Content-Type 標頭在標頭列表中的順序。

get_content_charset(failobj=None)

返回 Content-Type 頭的 charset 引數,並強制轉換為小寫。如果沒有 Content-Type 頭,或者該頭沒有 charset 引數,則返回 *failobj*。

get_charsets(failobj=None)

返回一個包含訊息中字元集名稱的列表。如果訊息是 multipart 型別,則列表中將為有效負載中的每個子部分包含一個元素;否則,它將是一個長度為 1 的列表。

列表中的每一項都是一個字串,即所代表子部分的 Content-Type 標頭中 charset 引數的值。如果子部分沒有 Content-Type 標頭,沒有 charset 引數,或者不是 text 主要 MIME 型別,則返回列表中的該項將是 *failobj*。

is_attachment()

如果存在 Content-Disposition 標頭且其值(不區分大小寫)為 attachment,則返回 True,否則返回 False

在 3.4.2 版更改: 為了與 is_multipart() 保持一致,is_attachment 現在是一個方法而不是屬性。

get_content_disposition()

如果訊息有 Content-Disposition 標頭,則返回其小寫值(不帶引數),否則返回 None。如果訊息遵循 RFC 2183,則此方法的可能值為 *inline*、*attachment* 或 None

在 3.5 版本加入。

以下方法與查詢和操作訊息的內容(有效負載)有關。

walk()

walk() 方法是一個通用的生成器,可用於以深度優先遍歷順序迭代訊息物件樹的所有部分和子部分。通常,您會將 walk() 用作 for 迴圈中的迭代器;每次迭代返回下一個子部分。

這是一個列印多部分訊息結構中每個部分的 MIME 型別的示例:

>>> for part in msg.walk():
...     print(part.get_content_type())
multipart/report
text/plain
message/delivery-status
text/plain
text/plain
message/rfc822
text/plain

walk 會遍歷任何 is_multipart() 返回 True 的部分的子部分,即使 msg.get_content_maintype() == 'multipart' 可能返回 False。我們可以透過使用 _structure 除錯輔助函式在我們的示例中看到這一點:

>>> from email.iterators import _structure
>>> for part in msg.walk():
...     print(part.get_content_maintype() == 'multipart',
...           part.is_multipart())
True True
False False
False True
False False
False False
False True
False False
>>> _structure(msg)
multipart/report
    text/plain
    message/delivery-status
        text/plain
        text/plain
    message/rfc822
        text/plain

這裡的message部分不是multipart,但它們確實包含子部分。is_multipart()返回Truewalk會深入到子部分。

get_body(preferencelist=('related', 'html', 'plain'))

返回最適合作為訊息“正文”的 MIME 部分。

*preferencelist*必須是來自集合relatedhtmlplain的字串序列,並指示返回部分的內容型別的偏好順序。

從呼叫 get_body 方法的物件開始查詢候選匹配項。

如果*preferencelist*中不包含related,則如果遇到的任何相關內容的根部分(或根部分的子部分)的(子)部分與偏好設定匹配,則將其視為候選部分。

當遇到 multipart/related 時,檢查 start 引數,如果找到一個具有匹配 Content-ID 的部分,則在尋找候選匹配時只考慮它。否則,只考慮 multipart/related 的第一個(預設根)部分。

如果某個部分有 Content-Disposition 標頭,只有當該標頭的值為 inline 時,才將該部分視為候選匹配項。

如果沒有任何候選者匹配*preferencelist*中的任何偏好,則返回None

注意:(1)對於大多數應用程式,真正有意義的*preferencelist*組合只有('plain',)('html', 'plain')和預設的('related', 'html', 'plain')。(2)因為匹配從呼叫get_body的物件開始,所以在multipart/related上呼叫get_body將返回物件本身,除非*preferencelist*具有非預設值。(3)未指定Content-Type或其Content-Type標頭無效的訊息(或訊息部分)將被視為型別為text/plain,這有時可能導致get_body返回意外的結果。

iter_attachments()

返回一個迭代器,遍歷訊息中所有非“正文”部分的直接子部分。也就是說,跳過 text/plaintext/htmlmultipart/relatedmultipart/alternative 的首次出現(除非它們透過 Content-Disposition: attachment 被明確標記為附件),並返回所有剩餘的部分。當直接應用於 multipart/related 時,返回一個迭代器,遍歷除根部分之外的所有相關部分(即:由 start 引數指向的部分,或者如果沒有 start 引數或 start 引數與任何部分的 Content-ID 不匹配時的第一個部分)。當直接應用於 multipart/alternative 或非 multipart 時,返回一個空迭代器。

iter_parts()

返回一個迭代器,遍歷訊息的所有直接子部分,對於非multipart型別,該迭代器將為空。(另見 walk()。)

get_content(*args, content_manager=None, **kw)

呼叫*content_manager*的get_content()方法,將 self 作為訊息物件傳遞,並將任何其他引數或關鍵字作為附加引數傳遞。如果未指定*content_manager*,則使用當前policy指定的content_manager

set_content(*args, content_manager=None, **kw)

呼叫*content_manager*的set_content()方法,將 self 作為訊息物件傳遞,並將任何其他引數或關鍵字作為附加引數傳遞。如果未指定*content_manager*,則使用當前policy指定的content_manager

將非 multipart 訊息轉換為 multipart/related 訊息,將任何現有的 Content- 標頭和有效負載移動到 multipart 的(新的)第一部分。如果指定了 *boundary*,則將其用作 multipart 中的邊界字串,否則讓邊界在需要時自動建立(例如,當訊息被序列化時)。

make_alternative(boundary=None)

將非 multipartmultipart/related 轉換為 multipart/alternative,將任何現有的 Content- 標頭和有效負載移動到 multipart 的(新)第一部分。如果指定了 *boundary*,則將其用作 multipart 中的邊界字串,否則讓邊界在需要時自動建立(例如,當訊息被序列化時)。

make_mixed(boundary=None)

將一個非multipart、一個multipart/related或一個multipart-alternative轉換為一個multipart/mixed,將任何現有的Content-頭和有效負載移動到multipart的一個(新的)第一部分。如果指定了*boundary*,則將其用作多部分中的邊界字串,否則讓邊界在需要時自動建立(例如,當訊息被序列化時)。

如果訊息是 multipart/related,建立一個新的訊息物件,將所有引數傳遞給它的 set_content() 方法,並將其 attach()multipart 上。如果訊息是 非-multipart,呼叫 make_related() 然後按上述步驟繼續。如果訊息是任何其他型別的 multipart,則引發 TypeError。如果未指定 *content_manager*,則使用當前 policy 指定的 content_manager。如果新增的部分沒有 Content-Disposition 標頭,則新增一個值為 inline 的標頭。

add_alternative(*args, content_manager=None, **kw)

如果訊息是 multipart/alternative,則建立一個新的訊息物件,將所有引數傳遞給其 set_content() 方法,並將其 attach()multipart 中。如果訊息是 非multipartmultipart/related,則呼叫 make_alternative(),然後按上述步驟繼續。如果訊息是任何其他型別的 multipart,則引發 TypeError。如果未指定 *content_manager*,則使用當前 policy 指定的 content_manager

add_attachment(*args, content_manager=None, **kw)

如果訊息是 multipart/mixed,則建立一個新的訊息物件,將所有引數傳遞給其 set_content() 方法,並將其 attach()multipart 中。如果訊息是 非multipartmultipart/relatedmultipart/alternative,則呼叫 make_mixed(),然後按上述步驟繼續。如果未指定 *content_manager*,則使用當前 policy 指定的 content_manager。如果新增的部分沒有 Content-Disposition 標頭,則新增一個值為 attachment 的標頭。此方法可用於顯式附件(Content-Disposition: attachment)和 inline 附件(Content-Disposition: inline),方法是向 content_manager 傳遞適當的選項。

clear()

移除有效負載和所有標頭。

clear_content()

移除有效負載和所有 !Content- 標頭,保留所有其他標頭及其原始順序。

EmailMessage 物件具有以下例項屬性:

preamble

MIME 文件的格式允許在標頭後的空行和第一個多部分邊界字串之間存在一些文字。通常,這段文字在支援 MIME 的郵件閱讀器中是不可見的,因為它不屬於標準的 MIME 封裝。然而,在檢視訊息的原始文字或在不支援 MIME 的閱讀器中檢視訊息時,這段文字可能會變得可見。

preamble 屬性包含 MIME 文件中這段前導的額外封裝文字。當 Parser 在標頭之後、第一個邊界字串之前發現一些文字時,它會將這段文字賦給訊息的 *preamble* 屬性。當 Generator 正在寫出 MIME 訊息的純文字表示,並且發現訊息有一個 *preamble* 屬性時,它會把這段文字寫在標頭和第一個邊界之間的區域。詳情請參見 email.parseremail.generator

請注意,如果訊息物件沒有前導文字,*preamble* 屬性將為 None

epilogue

*epilogue* 屬性的作用與 *preamble* 屬性相同,但它包含出現在最後一個邊界和訊息結尾之間的文字。與 preamble 一樣,如果沒有結尾文字,此屬性將為 None

defects

*defects* 屬性包含一個列表,其中包含解析此訊息時發現的所有問題。有關可能的解析缺陷的詳細描述,請參見 email.errors

class email.message.MIMEPart(policy=default)

這個類代表 MIME 訊息的一個子部分。它與 EmailMessage 相同,只是在呼叫 set_content() 時不會新增 MIME-Version 標頭,因為子部分不需要自己的 MIME-Version 標頭。

腳註