email.message.Message
: 使用 compat32
API 來表示電子郵件消息?
Message
類與 EmailMessage
類非常相似,但沒有該類所添加的方法,并且某些方法的默認行為也略有不同。 我們還在這里記錄了一些雖然被 EmailMessage
類所支持但并不推薦的方法,除非你是在處理舊有代碼。
在其他情況下這兩個類的理念和結構都是相同的。
本文檔描述了默認 (對于 Message
) 策略 Compat32
之下的行為。 如果你要使用其他策略,你應當改用 EmailMessage
類。
電子郵件消息由多個 標頭 和一個 載荷 組成。 標頭必須為 RFC 5322 風格的名稱和值,其中字典名和值由冒號分隔。 冒號不是字段名或字段值的組成部分。 載荷可以是簡單的文本消息,或是二進制對象,或是多個子消息的結構化序列,每個子消息都有自己的標頭集合和自己的載荷。 后一種類型的載荷是由具有 multipart/* 或 message/rfc822 等 MIME 類型的消息來指明的。
Message
對象所提供了概念化模型是由標頭組成的有序字典,加上用于訪問標頭中的特殊信息以及訪問載荷的額外方法,以便能生成消息的序列化版本,并遞歸地遍歷對象樹。 請注意重復的標頭是受支持的,但必須使用特殊的方法來訪問它們。
Message
偽字典以標頭名作為索引,標頭名必須為 ASCII 值。 字典的值為應當只包含 ASCII 字符的字符串;對于非 ASCII 輸入有一些特殊處理,但這并不總能產生正確的結果。 標頭以保留原大小寫的形式存儲和返回,但字段名稱匹配對大小寫不敏感。 還可能會有一個單獨的封包標頭,也稱 Unix-From 標頭或 From_
標頭。 載荷 對于簡單消息對象的情況是一個字符串或字節(jié)串,對于 MIME 容器文檔的情況 (例如 multipart/* 和 message/rfc822) 則是一個 Message
對象。
以下是 Message
類的方法:
- class email.message.Message(policy=compat32)?
如果指定了 policy (它必須為
policy
類的實例) 則使用它所設置的規(guī)則來更新和序列化消息的表示形式。 如果未設置 policy,則使用compat32
策略,該策略會保持對 Python 3.2 版 email 包的向下兼容性。 更多信息請參閱policy
文檔。在 3.3 版更改: 增加了 policy 關鍵字參數(shù)。
- as_string(unixfrom=False, maxheaderlen=0, policy=None)?
以展平的字符串形式返回整個消息對象。 或可選的 unixfrom 為真值,返回的字符串會包括封包標頭。 unixfrom 的默認值是
False
。 出于保持向下兼容性的原因,maxheaderlen 的默認值是0
,因此如果你想要不同的值你必須顯式地重載它(在策略中為 max_line_length 指定的值將被此方法忽略)。 policy 參數(shù)可被用于覆蓋從消息實例獲取的默認策略。 這可以用來對該方法所輸出的格式進行一些控制,因為指定的 policy 將被傳遞給Generator
。如果需要填充默認值以完成對字符串的轉換則展平消息可能觸發(fā)對
Message
的修改(例如,MIME 邊界可能會被生成或被修改)。請注意此方法是出于便捷原因提供的,可能無法總是以你想要的方式格式化消息。 例如,在默認情況下它不會按 unix mbox 格式的要求對以
From
打頭的行執(zhí)行調整。 為了獲得更高靈活性,請實例化一個Generator
實例并直接使用其flatten()
方法。 例如:from io import StringIO from email.generator import Generator fp = StringIO() g = Generator(fp, mangle_from_=True, maxheaderlen=60) g.flatten(msg) text = fp.getvalue()
如果消息對象包含未按照 RFC 標準進行編碼的二進制數(shù)據(jù),則這些不合規(guī)數(shù)據(jù)將被 unicode "unknown character" 碼位值所替代。 (另請參閱
as_bytes()
和BytesGenerator
。)在 3.4 版更改: 增加了 policy 關鍵字參數(shù)。
- __str__()?
與
as_string()
等價。 這將讓str(msg)
產生一個包含已格式化消息的字符號。
- as_bytes(unixfrom=False, policy=None)?
以字節(jié)串對象的形式返回整個扁平化后的消息。 當可選的 unixfrom 為真值時,返回的字符串會包括封包標頭。 unixfrom 的默認值為
False
。 policy 參數(shù)可被用于重載從消息實例獲取的默認策略。 這可被用來控制該方法所產生的部分格式化效果,因為指定的 policy 將被傳遞給BytesGenerator
。如果需要填充默認值以完成對字符串的轉換則展平消息可能觸發(fā)對
Message
的修改(例如,MIME 邊界可能會被生成或被修改)。請注意此方法是出于便捷原因提供的,可能無法總是以你想要的方式格式化消息。 例如,在默認情況下它不會按 unix mbox 格式的要求對以
From
打頭的行執(zhí)行調整。 為了獲得更高靈活性,請實例化一個BytesGenerator
實例并直接使用其flatten()
方法。 例如:from io import BytesIO from email.generator import BytesGenerator fp = BytesIO() g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60) g.flatten(msg) text = fp.getvalue()
3.4 新版功能.
- __bytes__()?
與
as_bytes()
等價。 這將讓bytes(msg)
產生一個包含已格式化消息的字節(jié)串對象。3.4 新版功能.
- is_multipart()?
如果該消息的載荷是一個子
Message
對象列表則返回True
,否則返回False
。 當is_multipart()
返回False
時,載荷應當是一個字符串對象(有可能是一個 CTE 編碼的二進制載荷)。 (請注意is_multipart()
返回True
并不意味著 "msg.get_content_maintype() == 'multipart'" 將返回True
。 例如,is_multipart
在Message
類型為message/rfc822
時也將返回True
。)
- set_unixfrom(unixfrom)?
將消息的封包標頭設為 unixfrom,這應當是一個字符串。
- get_unixfrom()?
返回消息的信封頭。如果信封頭從未被設置過,默認返回
None
。
- attach(payload)?
將給定的 payload 添加到當前載荷中,當前載荷在該調用之前必須為
None
或是一個Message
對象列表。 在調用之后,此載荷將總是一個Message
對象列表。 如果你想將此載荷設為一個標量對象(如字符串),請改用set_payload()
。這是一個過時的方法。 在
EmailMessage
類上它的功能已被set_content()
及相應的make
和add
方法所替代。
- get_payload(i=None, decode=False)?
返回當前的載荷,它在
is_multipart()
為True
時將是一個Message
對象列表,在is_multipart()
為False
時則是一個字符串。 如果該載荷是一個列表且你修改了這個列表對象,那么你就是原地修改了消息的載荷。傳入可選參數(shù) i 時,如果
is_multipart()
為True
,get_payload()
將返回載荷從零開始計數(shù)的第 i 個元素。 如果 i 小于 0 或大于等于載荷中的條目數(shù)則將引發(fā)IndexError
。 如果載荷是一個字符串 (即is_multipart()
為False
) 且給出了 i,則會引發(fā)TypeError
。可選的 decode 是一個指明載荷是否應根據(jù) Content-Transfer-Encoding 標頭被解碼的旗標。 當其值為
True
且消息沒有多個部分時,如果此標頭值為quoted-printable
或base64
則載荷將被解碼。 如果使用了其他編碼格式,或者找不到 Content-Transfer-Encoding 標頭時,載荷將被原樣返回(不編碼)。 在所有情況下返回值都是二進制數(shù)據(jù)。 如果消息有多個部分且 decode 旗標為True
,則將返回None
。 如果載荷為 base64 但內容不完全正確(如缺少填充符、存在 base64 字母表以外的字符等),則將在消息的缺陷屬性中添加適當?shù)娜毕葜?(分別為InvalidBase64PaddingDefect
或InvalidBase64CharactersDefect
)。當 decode 為
False
(默認值) 時消息體會作為字符串返回而不解碼 Content-Transfer-Encoding。 但是,對于 Content-Transfer-Encoding 為 8bit 的情況,會嘗試使用 Content-Type 標頭指定的charset
來解碼原始字節(jié)串,并使用replace
錯誤處理程序。 如果未指定charset
,或者如果指定的charset
未被 email 包所識別,則會使用默認的 ASCII 字符集來解碼消息體。這是一個過時的方法。 在
EmailMessage
類上它的功能已被get_content()
和iter_parts()
方法所替代。
- set_payload(payload, charset=None)?
將整個消息對象的載荷設為 payload。 客戶端要負責確保載荷的不變性。 可選的 charset 用于設置消息的默認字符集;詳情請參閱
set_charset()
。這是一個過時的方法。 在
EmailMessage
類上它的功能已被set_content()
方法所替代。
- set_charset(charset)?
將載荷的字符集設為 charset,它可以是
Charset
實例 (參見email.charset
)、字符集名稱字符串或None
。 如果是字符串,它將被轉換為一個Charset
實例。 如果 charset 是None
,charset
形參將從 Content-Type 標頭中被刪除(消息將不會進行其他修改)。 任何其他值都將導致TypeError
。如果 MIME-Version 標頭不存在則將被添加。 如果 Content-Type 標頭不存在,則將添加一個值為 text/plain 的該標頭。 無論 Content-Type 標頭是否已存在,其
charset
形參都將被設為 charset.output_charset。 如果 charset.input_charset 和 charset.output_charset 不同,則載荷將被重編碼為 output_charset。 如果 Content-Transfer-Encoding 標頭不存在,則載荷將在必要時使用指定的Charset
來轉換編碼,并將添加一個具有相應值的標頭。 如果 Content-Transfer-Encoding 標頭已存在,則會假定載荷已使用該 Content-Transfer-Encoding 進行正確編碼并不會再被修改。這是一個過時的方法。 在
EmailMessage
類上它的功能已被email.emailmessage.EmailMessage.set_content()
方法的 charset 形參所替代。
以下方法實現(xiàn)了用于訪問消息的 RFC 2822 標頭的類映射接口。 請注意這些方法和普通映射(例如字典)接口之間存在一些語義上的不同。 舉例來說,在一個字典中不能有重復的鍵,但消息標頭則可能有重復。 并且,在字典中由
keys()
返回的鍵的順序是沒有保證的,但在Message
對象中,標頭總是會按它們在原始消息中的出現(xiàn)或后繼加入順序返回。 任何已刪除再重新加入的標頭總是會添加到標頭列表的末尾。這些語義上的差異是有意為之且其目的是為了提供最大的便利性。
請注意在任何情況下,消息當中的任何封包標頭都不會包含在映射接口當中。
在由字節(jié)串生成的模型中,任何包含非 ASCII 字節(jié)數(shù)據(jù)(違反 RFC)的標頭值當通過此接口來獲取時,將被表示為使用 unknown-8bit 字符集的
Header
對象。- __len__()?
返回標頭的總數(shù),包括重復項。
- __contains__(name)?
如果消息對象中有一個名為 name 的字段則返回
True
。 匹配操作對大小寫不敏感并且 name 不應包括末尾的冒號。 用于in
運算符,例如:if 'message-id' in myMessage: print('Message-ID:', myMessage['message-id'])
- __getitem__(name)?
返回指定名稱標頭字段的值。 name 不應包括作為字段分隔符的冒號。 如果標頭未找到,則返回
None
;KeyError
永遠不會被引發(fā)。請注意如果指定名稱的字段在消息標頭中多次出現(xiàn),具體將返回哪個字段值是未定義的。 請使用
get_all()
方法來獲取所有指定名稱標頭的值。
- __setitem__(name, val)?
將具有字段名 name 和值 val 的標頭添加到消息中。 字段會被添加到消息的現(xiàn)有字段的末尾。
請注意,這個方法 既不會 覆蓋 也不會 刪除任何字段名重名的已有字段。如果你確實想保證新字段是整個信息頭當中唯一擁有 name 字段名的字段,你需要先把舊字段刪除。例如:
del msg['subject'] msg['subject'] = 'Python roolz!'
- __delitem__(name)?
刪除信息頭當中字段名匹配 name 的所有字段。如果匹配指定名稱的字段沒有找到,也不會拋出任何異常。
- keys()?
以列表形式返回消息頭中所有的字段名。
- values()?
以列表形式返回消息頭中所有的字段值。
- items()?
以二元元組的列表形式返回消息頭中所有的字段名和字段值。
- get(name, failobj=None)?
返回指定名稱標頭字段的值。 這與
__getitem__()
是一樣的,不同之處在于如果指定名稱標頭未找到則會返回可選的 failobj (默認為None
)。
以下是一些有用的附加方法:
- get_all(name, failobj=None)?
返回字段名為 name 的所有字段值的列表。如果信息內不存在匹配的字段,返回 failobj (其默認值為
None
)。
- add_header(_name, _value, **_params)?
高級頭字段設定。這個方法與
__setitem__()
類似,不過你可以使用關鍵字參數(shù)為字段提供附加參數(shù)。 _name 是字段名, _value 是字段 主 值。對于關鍵字參數(shù)字典 _params 中的每一項,其鍵會被當作形參名,并執(zhí)行下劃線和連字符間的轉換(因為連字符不是合法的 Python 標識符)。 通常,形參將以
key="value"
的形式添加,除非值為None
,在這種情況下將只添加鍵。 如果值包含非 ASCII 字符,可將其指定為格式為(CHARSET, LANGUAGE, VALUE)
的三元組,其中CHARSET
為要用來編碼值的字符集名稱字符串,LANGUAGE
通??稍O為None
或空字符串(請參閱 RFC 2231 了解其他可能的取值),而VALUE
為包含非 ASCII 碼位的字符串值。 如果不是傳入一個三元組且值包含非 ASCII 字符,則會自動以 RFC 2231 格式使用CHARSET
為utf-8
和LANGUAGE
為None
對其進行編碼。以下是為示例代碼:
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'))
它的輸出結果為
Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"
- replace_header(_name, _value)?
替換一個標頭。 將替換在匹配 _name 的消息中找到的第一個標頭,標頭順序和字段名大小寫保持不變。 如果未找到匹配的標頭,則會引發(fā)
KeyError
。
- get_content_type()?
返回消息的內容類型。 返回的字符串會強制轉換為 maintype/subtype 的全小寫形式。 如果消息中沒有 Content-Type 標頭則將返回由
get_default_type()
給出的默認類型。 因為根據(jù) RFC 2045,消息總是要有一個默認類型,所以get_content_type()
將總是返回一個值。RFC 2045 將消息的默認類型定義為 text/plain,除非它是出現(xiàn)在 multipart/digest 容器內,在這種情況下其類型應為 message/rfc822。 如果 Content-Type 標頭指定了無效的類型,RFC 2045 規(guī)定其默認類型應為 text/plain。
- get_content_maintype()?
返回信息的主要內容類型。準確來說,此方法返回的是
get_content_type()
方法所返回的形如 maintype/subtype 的字符串當中的 maintype 部分。
- get_content_subtype()?
返回信息的子內容類型。準確來說,此方法返回的是
get_content_type()
方法所返回的形如 maintype/subtype 的字符串當中的 subtype 部分。
- get_default_type()?
返回默認的內容類型。絕大多數(shù)的信息,其默認內容類型都是 text/plain 。作為 multipart/digest 容器內子部分的信息除外,它們的默認內容類型是 message/rfc822 。
- set_default_type(ctype)?
設置默認的內容類型。 ctype 應當為 text/plain 或者 message/rfc822,盡管這并非強制。 默認的內容類型不會存儲在 Content-Type 標頭中。
- get_params(failobj=None, header='content-type', unquote=True)?
將消息的 Content-Type 形參作為列表返回。 所返回列表的元素為以
'='
號拆分出的鍵/值對 2 元組。'='
左側的為鍵,右側的為值。 如果形參值中沒有'='
號,否則該將值如get_param()
描述并且在可選 unquote 為True
(默認值) 時會被取消轉義。可選的 failobj 是在沒有 Content-Type 標頭時要返回的對象。 可選的 header 是要替代 Content-Type 被搜索的標頭。
這是一個過時的方法。 在
EmailMessage
類上它的功能已被標頭訪問方法所返回的單獨標頭對象的 params 特征屬性所替代。
- get_param(param, failobj=None, header='content-type', unquote=True)?
將 Content-Type 標頭的形參 param 作為字符串返回。 如果消息沒有 Content-Type 標頭或者沒有這樣的形參,則返回 failobj (默認為
None
)。如果給出可選的 header,它會指定要替代 Content-Type 來使用的消息標頭。
形參的鍵總是以大小寫不敏感的方式來比較的。 返回值可以是一個字符串,或者如果形參以 RFC 2231 編碼則是一個 3 元組。 當為 3 元組時,值中的元素采用
(CHARSET, LANGUAGE, VALUE)
的形式。 請注意CHARSET
和LANGUAGE
都可以為None
,在此情況下你應當將VALUE
當作以us-ascii
字符集來編碼。 你可以總是忽略LANGUAGE
。如果你的應用不關心形參是否以 RFC 2231 來編碼,你可以通過調用
email.utils.collapse_rfc2231_value()
來展平形參值,傳入來自get_param()
的返回值。 當值為元組時這將返回一個經適當編碼的 Unicode 字符串,否則返回未經轉換的原字符串。 例如:rawparam = msg.get_param('foo') param = email.utils.collapse_rfc2231_value(rawparam)
無論在哪種情況下,形參值(或為返回的字符串,或為 3 元組形式的
VALUE
條目)總是未經轉換的,除非 unquote 被設為False
。這是一個過時的方法。 在
EmailMessage
類上它的功能已被標頭訪問方法所返回的單獨標頭對象的 params 特征屬性所替代。
- set_param(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)?
在 Content-Type 標頭中設置一個形參。 如果該形參已存在于標頭中,它的值將被替換為 value。 如果此消息還未定義 Content-Type 標頭,它將被設為 text/plain 且新的形參值將按 RFC 2045 的要求添加。
可選的 header 指定一個 Content-Type 的替代標頭,并且所有形參將根據(jù)需要被轉換,除非可選的 requote 為
False
(默認為True
)。如果指定了可選的 charset,形參將按照 RFC 2231 來編碼。 可選的 language 指定了 RFC 2231 的語言,默認為空字符串。 charset 和 language 都應為字符串。
如果 replace 為
False
(默認值),該頭字段會被移動到所有頭字段列表的末尾。如果 replace 為True
,字段會被原地更新。在 3.4 版更改: 添加了
replace
關鍵字。
- del_param(param, header='content-type', requote=True)?
從 Content-Type 標頭中完全移除給定的形參。 標頭將被原地重寫并不帶該形參或它的值。 所有的值將根據(jù)需要被轉換,除非 requote 為
False
(默認為True
)。 可選的 header 指定 Content-Type 的一個替代項。
- set_type(type, header='Content-Type', requote=True)?
設置 Content-Type 標頭的主類型和子類型。 type 必須為 maintype/subtype 形式的字符串,否則會引發(fā)
ValueError
。此方法可替換 Content-Type 標頭,并保持所有形參不變。 如果 requote 為
False
,這會保持原有標頭引用轉換不變,否則形參將被引用轉換(默認行為)。可以在 header 參數(shù)中指定一個替代標頭。 當 Content-Type 標頭被設置時也會添加一個 MIME-Version 標頭。
這是一個過時的方法。 在
EmailMessage
類上它的功能已被make_
和add_
方法所替代。
- get_filename(failobj=None)?
返回信息頭當中 Content-Disposition 字段當中名為
filename
的參數(shù)值。如果該字段當中沒有此參數(shù),該方法會退而尋找 Content-Type 字段當中的name
參數(shù)值。如果這個也沒有找到,或者這些個字段壓根就不存在,返回 failobj 。返回的字符串永遠按照email.utils.unquote()
方法去除引號。
- get_boundary(failobj=None)?
返回信息頭當中 Content-Type 字段當中名為
boundary
的參數(shù)值。如果字段當中沒有此參數(shù),或者這些個字段壓根就不存在,返回 failobj 。返回的字符串永遠按照email.utils.unquote()
方法去除引號。
- set_boundary(boundary)?
將 Content-Type 頭字段的
boundary
參數(shù)設置為 boundary 。set_boundary()
方法永遠都會在必要的時候為 boundary 添加引號。如果信息對象中沒有 Content-Type 頭字段,拋出HeaderParseError
異常。請注意使用這個方法與刪除舊的 Content-Type 標頭并通過
add_header()
添加一個帶有新邊界的新標頭有細微的差異,因為set_boundary()
會保留 Content-Type 標頭在原標頭列表中的順序。 但是,它 不會 保留原 Content-Type 標頭中可能存在的任何連續(xù)的行。
- get_content_charset(failobj=None)?
返回 Content-Type 頭字段中的
charset
參數(shù),強制小寫。如果字段當中沒有此參數(shù),或者這個字段壓根不存在,返回 failobj 。請注意此方法不同于
get_charset()
,后者會返回Charset
實例作為消息體的默認編碼格式。
- get_charsets(failobj=None)?
返回一個包含了信息內所有字符集名字的列表。 如果信息是 multipart 類型的,那么列表當中的每一項都對應其載荷的子部分的字符集名字。 否則,該列表是一個長度為 1 的列表。
列表中的每一項都是字符串,它們是其所表示的子部分的 Content-Type 標頭中
charset
形參的值。 但是,如果該子部分沒有 Content-Type 標頭,或沒有charset
形參,或者主 MIME 類型不是 text,則所返回列表中的對應項將為 failobj。
- get_content_disposition()?
如果信息的 Content-Disposition 頭字段存在,返回其字段值;否則返回
None
。返回的值均為小寫,不包含參數(shù)。如果信息遵循 RFC 2183 標準,則此方法的返回值只可能在 inline 、 attachment 和None
之間選擇。3.5 新版功能.
- walk()?
walk()
方法是一個多功能生成器。它可以被用來以深度優(yōu)先順序遍歷信息對象樹的所有部分和子部分。一般而言,walk()
會被用作for
循環(huán)的迭代器,每一次迭代都返回其下一個子部分。以下例子會打印出一封具有多部分結構之信息的每個部分的 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
除錯幫助函數(shù)可以幫助我們在下面這個例子當中看清楚這一點:>>> 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
的部分并非multiparts
,但是它們真的包含子部分!is_multipart()
返回True
,walk
也深入進這些子部分中。
Message
對象也可以包含兩個可選的實例屬性,它們可被用于生成純文本的 MIME 消息。- preamble?
MIME 文檔格式在標頭之后的空白行以及第一個多部分的分界字符串之間允許添加一些文本, 通常,此文本在支持 MIME 的郵件閱讀器中永遠不可見,因為它處在標準 MIME 保護范圍之外。 但是,當查看消息的原始文本,或當在不支持 MIME 的閱讀器中查看消息時,此文本會變得可見。
preamble 屬性包含 MIME 文檔開頭部分的這些處于保護范圍之外的文本。 當
Parser
在標頭之后及第一個分界字符串之前發(fā)現(xiàn)一些文本時,它會將這些文本賦值給消息的 preamble 屬性。 當Generator
寫出 MIME 消息的純文本表示形式時,如果它發(fā)現(xiàn)消息具有 preamble 屬性,它將在標頭及第一個分界之間區(qū)域寫出這些文本。 請參閱email.parser
和email.generator
了解更多細節(jié)。請注意如果消息對象沒有前導文本,則 preamble 屬性將為
None
。
- epilogue?
epilogue 屬性的作用方式與 preamble 屬性相同,區(qū)別在于它包含出現(xiàn)于最后一個分界與消息結尾之間的文本。
你不需要將 epilogue 設為空字符串以便讓
Generator
在文件末尾打印一個換行符。
- defects?
defects 屬性包含在解析消息時發(fā)現(xiàn)的所有問題的列表。 請參閱
email.errors
了解可能的解析缺陷的詳細描述。