email.headerregistry: 自定義標(biāo)頭對象?

源代碼: Lib/email/headerregistry.py


3.6 新版功能: 1

標(biāo)頭是由 str 的自定義子類來表示的。 用于表示給定標(biāo)頭的特定類則由創(chuàng)建標(biāo)頭時(shí)生效的 policyheader_factory 確定。 這一節(jié)記錄了 email 包為處理兼容 RFC 5322 的電子郵件消息所實(shí)現(xiàn)的特定 header_factory,它不僅為各種標(biāo)頭類型提供了自定義的標(biāo)頭對象,還為應(yīng)用程序提供了添加其自定義標(biāo)頭類型的擴(kuò)展機(jī)制。

當(dāng)使用派生自 EmailPolicy 的任何策略對象時(shí),所有標(biāo)頭都通過 HeaderRegistry 產(chǎn)生并且以 BaseHeader 作為其最后一個(gè)基類。 每個(gè)標(biāo)頭類都有一個(gè)由該標(biāo)頭類型確定的附加基類。 例如,許多標(biāo)頭都以 UnstructuredHeader 類作為其另一個(gè)基類。 一個(gè)標(biāo)頭專用的第二個(gè)類是由標(biāo)頭名稱使用存儲(chǔ)在 HeaderRegistry 中的查找表來確定的。 所有這些都針對典型應(yīng)用程序進(jìn)行透明的管理,但也為修改默認(rèn)行為提供了接口,以便由更復(fù)雜的應(yīng)用使用。

以下各節(jié)首先記錄了標(biāo)頭基類及其屬性,然后是用于修改 HeaderRegistry 行為的 API,最后是用于表示從結(jié)構(gòu)化標(biāo)頭解析的數(shù)據(jù)的支持類。

class email.headerregistry.BaseHeader(name, value)?

namevalue 會(huì)從 header_factory 調(diào)用傳遞給 BaseHeader。 任何標(biāo)頭對象的字符串值都是完成解碼為 unicode 的 value。

這個(gè)基類定義了下列只讀屬性:

name?

標(biāo)頭的名稱(字段在 ':' 之前的部分)。 這就是 nameheader_factory 調(diào)用所傳遞的值;也就是說會(huì)保持大小寫形式。

defects?

一個(gè)包含 HeaderDefect 實(shí)例的元組,這些實(shí)例報(bào)告了在解析期間發(fā)現(xiàn)的任何 RFC 合規(guī)性問題。 email 包會(huì)嘗試盡可能地檢測合規(guī)性問題。 請參閱 errors 模塊了解可能被報(bào)告的缺陷類型的相關(guān)討論。

max_count?

此類型標(biāo)頭可具有相同 name 的最大數(shù)量。 None 值表示無限制。 此屬性的 BaseHeader 值為 None;專用的標(biāo)頭類預(yù)期將根據(jù)需要重載這個(gè)值。

BaseHeader 還提供了以下方法,它由 email 庫代碼調(diào)用,通常不應(yīng)當(dāng)由應(yīng)用程序來調(diào)用。

fold(*, policy)?

返回一個(gè)字符串,其中包含用來根據(jù) policy 正確地折疊標(biāo)頭的 linesep 字符。 cte_type8bit 時(shí)將被作為 7bit 來處理,因?yàn)闃?biāo)頭不能包含任意二進(jìn)制數(shù)據(jù)。 如果 utf8False,則非 ASCII 數(shù)據(jù)將根據(jù) RFC 2047 來編碼。

BaseHeader 本身不能被用于創(chuàng)建標(biāo)頭對象。 它定義了一個(gè)與每個(gè)專用標(biāo)頭相配合的協(xié)議以便生成標(biāo)頭對象。 具體來說,BaseHeader 要求專用類提供一個(gè)名為 parseclassmethod()。 此方法的調(diào)用形式如下:

parse(string, kwds)

kwds 是包含了一個(gè)預(yù)初始化鍵 defects 的字典。 defects 是一個(gè)空列表。 parse 方法應(yīng)當(dāng)將任何已檢測到的缺陷添加到此列表中。 在返回時(shí),kwds 字典 必須 至少包含 decodeddefects 等鍵的值。 decoded 應(yīng)當(dāng)是標(biāo)頭的字符串值(即完全解碼為 unicode 的標(biāo)頭值)。 parse 方法應(yīng)當(dāng)假定 string 可能包含 content-transfer-encoded 部分,但也應(yīng)當(dāng)正確地處理全部有效的 unicode 字符以便它能解析未經(jīng)編碼的標(biāo)頭值。

隨后 BaseHeader__new__ 會(huì)創(chuàng)建標(biāo)頭實(shí)例,并調(diào)用其 init 方法。 專屬類如果想要設(shè)置 BaseHeader 自身所提供的屬性之外的附加屬性,只需提供一個(gè) init 方法。 這樣的 init 看起來應(yīng)該是這樣:

def init(self, /, *args, **kw):
    self._myattr = kw.pop('myattr')
    super().init(*args, **kw)

也就是說,專屬類放入 kwds 字典的任何額外內(nèi)容都應(yīng)當(dāng)被移除和處理,并且 kw (和 args) 的剩余內(nèi)容會(huì)被傳遞給 BaseHeader init 方法。

class email.headerregistry.UnstructuredHeader?

"非結(jié)構(gòu)化" 標(biāo)頭是 RFC 5322 中默認(rèn)的標(biāo)頭類型。 任何沒有指定語法的標(biāo)頭都會(huì)被視為是非結(jié)構(gòu)化的。 非結(jié)構(gòu)化標(biāo)頭的經(jīng)典例子是 Subject 標(biāo)頭。

RFC 5322 中,非結(jié)構(gòu)化標(biāo)頭是指一段以 ASCII 字符集表示的任意文本。 但是 RFC 2047 具有一個(gè) RFC 5322 兼容機(jī)制用來將標(biāo)頭值中的非 ASCII 文本編碼為 ASCII 字符。 當(dāng)包含已編碼字的 value 被傳遞給構(gòu)造器時(shí),UnstructuredHeader 解析器會(huì)按照非結(jié)構(gòu)化文本的 RFC 2047 規(guī)則將此類已編碼字轉(zhuǎn)換為 unicode。 解析器會(huì)使用啟發(fā)式機(jī)制來嘗試解碼一些不合規(guī)的已編碼字。 在此種情況下各類缺陷,例如已編碼字或未編碼文本中的無效字符問題等缺陷將會(huì)被注冊。

此標(biāo)頭類型未提供附加屬性。

class email.headerregistry.DateHeader?

RFC 5322 為電子郵件標(biāo)頭內(nèi)的日期指定了非常明確的格式。 DateHeader 解析器會(huì)識別該日期格式,并且也能識別間或出現(xiàn)的一些“不規(guī)范”變種形式。

這個(gè)標(biāo)頭類型提供了以下附加屬性。

datetime?

如果標(biāo)頭值能被識別為某一種有效的日期形式,此屬性將包含一個(gè)代表該日期的 datetime 實(shí)例。 如果輸入日期的時(shí)區(qū)被指定為 -0000 (表示為 UTC 但不包含源時(shí)區(qū)的相關(guān)信息),則 datetime 將為簡單型 datetime。 如果找到了特定的時(shí)區(qū)時(shí)差值 (包括 +0000),則 datetime 將包含使用 datetime.timezone 來記錄時(shí)區(qū)時(shí)差時(shí)的感知型 datetime。

標(biāo)頭的 decoded 值是由按照 RFC 5322datetime 進(jìn)行格式化來確定的;也就是說,它會(huì)被設(shè)為:

email.utils.format_datetime(self.datetime)

當(dāng)創(chuàng)建 DateHeader 時(shí),value 可以為 datetime 實(shí)例。 例如這意味著以下代碼是有效的并能實(shí)現(xiàn)人們預(yù)期的行為:

msg['Date'] = datetime(2011, 7, 15, 21)

因?yàn)檫@是個(gè)簡單型 datetime 它將被解讀為 UTC 時(shí)間戳,并且結(jié)果值的時(shí)區(qū)將為 -0000。 使用來自 utils 模塊的 localtime() 函數(shù)會(huì)更有用:

msg['Date'] = utils.localtime()

這個(gè)例子將日期標(biāo)頭設(shè)為使用當(dāng)前時(shí)區(qū)時(shí)差值的當(dāng)前時(shí)間和日期。

class email.headerregistry.AddressHeader?

地址標(biāo)頭是最復(fù)雜的結(jié)構(gòu)化標(biāo)頭類型之一。 AddressHeader 類提供了適合任何地址標(biāo)頭的泛用型接口。

這個(gè)標(biāo)頭類型提供了以下附加屬性。

groups?

編碼了在標(biāo)頭值中找到的地址和分組的 Group 對象的元組。 非分組成員的地址在此列表中表示為 display_nameNone 的單地址 Groups。

addresses?

編碼了來自標(biāo)頭值的所有單獨(dú)地址的 Address 對象的元組。 如果標(biāo)頭值包含任何分組,則來自分組的單個(gè)地址將包含在該分組出現(xiàn)在值中的點(diǎn)上列出(也就是說,地址列表會(huì)被“展平”為一維列表)。

The decoded value of the header will have all encoded words decoded to unicode. idna encoded domain names are also decoded to unicode. The decoded value is set by joining the str value of the elements of the groups attribute with ', '.

可以使用 AddressGroup 對象的任意組合的列表來設(shè)置一個(gè)地址標(biāo)頭的值。 display_nameNoneGroup 對象將被解讀為單獨(dú)地址,這允許一個(gè)地址列表可以附帶通過使用從源標(biāo)頭的 groups 屬性獲取的列表而保留原分組。

class email.headerregistry.SingleAddressHeader?

AddressHeader 的子類,添加了一個(gè)額外的屬性:

address?

由標(biāo)頭值編碼的單個(gè)地址。 如果標(biāo)頭值實(shí)際上包含一個(gè)以上的地址(這在默認(rèn) policy 下將違反 RFC),則訪問此屬性將導(dǎo)致 ValueError

上述類中許多還具有一個(gè) Unique 變體 (例如 UniqueUnstructuredHeader)。 其唯一差別是在 Unique 變體中 max_count 被設(shè)為 1。

class email.headerregistry.MIMEVersionHeader?

實(shí)際上 MIME-Version 標(biāo)頭只有一個(gè)有效的值,即 1.0。 為了將來的擴(kuò)展,這個(gè)標(biāo)頭類還支持其他的有效版本號。 如果一個(gè)版本號是 RFC 2045 的有效值,則標(biāo)頭對象的以下屬性將具有不為 None 的值:

version?

字符串形式的版本號。 任何空格和/或注釋都會(huì)被移除。

major?

整數(shù)形式的主版本號

minor?

整數(shù)形式的次版本號

class email.headerregistry.ParameterizedMIMEHeader?

MIME 標(biāo)頭都以前綴 'Content-' 打頭。 每個(gè)特定標(biāo)頭都具有特定的值,其描述在該標(biāo)頭的類之中。 有些也可以接受一個(gè)具有通用格式的補(bǔ)充形參形表。 這個(gè)類被用作所有接受形參的 MIME 標(biāo)頭的基類。

params?

一個(gè)將形參名映射到形參值的字典。

class email.headerregistry.ContentTypeHeader?

處理 Content-Type 標(biāo)頭的 ParameterizedMIMEHeader 類。

content_type?

maintype/subtype 形式的內(nèi)容類型字符串。

maintype?
subtype?
class email.headerregistry.ContentDispositionHeader?

處理 Content-Disposition 標(biāo)頭的 ParameterizedMIMEHeader 類。

content_disposition?

inlineattachment 是僅有的常用有效值。

class email.headerregistry.ContentTransferEncoding?

處理 Content-Transfer-Encoding 標(biāo)頭。

cte?

可用的有效值為 7bit, 8bit, base64quoted-printable。 更多信息請參閱 RFC 2045。

class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)?

這是由 EmailPolicy 在默認(rèn)情況下使用的工廠函數(shù)。 HeaderRegistry 會(huì)使用 base_class 和從它所保存的注冊表中獲取的專用類來構(gòu)建用于動(dòng)態(tài)地創(chuàng)建標(biāo)頭實(shí)例的類。 當(dāng)給定的標(biāo)頭名稱未在注冊表中出現(xiàn)時(shí),則會(huì)使用由 default_class 所指定的類作為專用類。 當(dāng) use_default_mapTrue (默認(rèn)值) 時(shí),則會(huì)在初始化期間把將標(biāo)頭名稱與類的標(biāo)準(zhǔn)映射拷貝到注冊表中。 base_class 始終會(huì)是所生成類的 __bases__ 列表中的最后一個(gè)類。

默認(rèn)的映射有:

subject

UniqueUnstructuredHeader

date

UniqueDateHeader

resent-date

DateHeader

orig-date

UniqueDateHeader

sender

UniqueSingleAddressHeader

resent-sender

SingleAddressHeader

UniqueAddressHeader

resent-to

AddressHeader

cc

UniqueAddressHeader

resent-cc

AddressHeader

bcc

UniqueAddressHeader

resent-bcc

AddressHeader

UniqueAddressHeader

resent-from

AddressHeader

reply-to

UniqueAddressHeader

mime-version

MIMEVersionHeader

content-type

ContentTypeHeader

content-disposition

ContentDispositionHeader

content-transfer-encoding

ContentTransferEncodingHeader

message-id

MessageIDHeader

HeaderRegistry 具有下列方法:

map_to_type(self, name, cls)?

name 是要映射的標(biāo)頭名稱。 它將在注冊表中被轉(zhuǎn)換為小寫形式。 cls 是要與 base_class 一起被用來創(chuàng)建用于實(shí)例化與 name 相匹配的標(biāo)頭的類的專用類。

__getitem__(name)?

構(gòu)造并返回一個(gè)類來處理 name 標(biāo)頭的創(chuàng)建。

__call__(name, value)?

從注冊表獲得與 name 相關(guān)聯(lián)的專用標(biāo)頭 (如果 name 未在注冊表中出現(xiàn)則使用 default_class) 并將其與 base_class 相組合以產(chǎn)生類,調(diào)用被構(gòu)造類的構(gòu)造器,傳入相同的參數(shù)列表,并最終返回由此創(chuàng)建的類實(shí)例。

以下的類是用于表示從結(jié)構(gòu)化標(biāo)頭解析的數(shù)據(jù)的類,并且通常會(huì)由應(yīng)用程序使用以構(gòu)造結(jié)構(gòu)化的值并賦給特定的標(biāo)頭。

class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)?

用于表示電子郵件地址的類。 地址的一般形式為:

[display_name] <username@domain>

或者:

username@domain

其中每個(gè)部分都必須符合在 RFC 5322 中闡述的特定語法規(guī)則。

為了方便起見可以指定 addr_spec 來替代 usernamedomain,在此情況下 usernamedomain 將從 addr_spec 中解析。 addr_spec 應(yīng)當(dāng)是一個(gè)正確地引用了 RFC 的字符串;如果它不是 Address 則將引發(fā)錯(cuò)誤。 Unicode 字符也允許使用并將在序列化時(shí)被正確地編碼。 但是,根據(jù) RFC,地址的 username 部分 不允許 有 unicode。

display_name?

地址的顯示名稱部分(如果有的話)并去除所有引用項(xiàng)。 如果地址沒有顯示名稱,則此屬性將為空字符串。

username?

地址的 username 部分,去除所有引用項(xiàng)。

domain?

地址的 domain 部分。

addr_spec?

地址的 username@domain 部分,經(jīng)過正確引用處理以作為純地址使用(上面顯示的第二種形式)。 此屬性不可變。

__str__()?

對象的 str 值是根據(jù) RFC 5322 規(guī)則進(jìn)行引用處理的地址,但不帶任何非 ASCII 字符的 Content Transfer Encoding。

為了支持 SMTP (RFC 5321),Address 會(huì)處理一種特殊情況:如果 usernamedomain 均為空字符串 (或?yàn)?None),則 Address 的字符串值為 <>。

class email.headerregistry.Group(display_name=None, addresses=None)?

用于表示地址組的類。 地址組的一般形式為:

display_name: [address-list];

作為處理由組和單個(gè)地址混合構(gòu)成的列表的便捷方式,Group 也可以通過將 display_name 設(shè)為 None 以用來表示不是某個(gè)組的一部分的單獨(dú)地址并提供單獨(dú)地址的列表作為 addresses。

display_name?

組的 display_name。 如果其為 None 并且恰好有一個(gè) Addressaddresses 中,則 Group 表示一個(gè)不在某個(gè)組中的單獨(dú)地址。

addresses?

一個(gè)可能為空的表示組中地址的包含 Address 對象的元組。

__str__()?

Groupstr 值會(huì)根據(jù) RFC 5322 進(jìn)行格式化,但不帶任何非 ASCII 字符的 Content Transfer Encoding。 如果 display_name 為空值且只有一個(gè)單獨(dú) Addressaddresses 列表中,則 str 值將與該單獨(dú) Addressstr 相同。

備注

1

最初在 3.3 中作為 暫定模塊 添加