mailbox --- 操作多種格式的郵箱?

源代碼: Lib/mailbox.py


本模塊定義了兩個類,MailboxMessage,用于訪問和操作磁盤中的郵箱及其所包含的電子郵件。 Mailbox 提供了類似字典的從鍵到消息的映射。 Messageemail.message 模塊的 Message 類增加了特定格式專屬的狀態(tài)和行為。 支持的郵箱格式有 Maildir, mbox, MH, Babyl 以及 MMDF。

參見

模塊 email

表示和操作郵件消息。

Mailbox 對象?

class mailbox.Mailbox?

一個郵箱,它可以被檢視和修改。

Mailbox 類定義了一個接口并且它不應(yīng)被實例化。 而是應(yīng)該讓格式專屬的子類繼承 Mailbox 并且你的代碼應(yīng)當(dāng)實例化一個特定的子類。

Mailbox 接口類似于字典,其中每個小鍵都有對應(yīng)的消息。 鍵是由 Mailbox 實例發(fā)出的,它們將由實例來使用并且只對該 Mailbox 實例有意義。 鍵會持續(xù)標(biāo)識一條消息,即使對應(yīng)的消息已被修改,例如被另一條消息所替代。

可以使用 set 型方法 add() 將消息添加到 Mailbox 并可以使用 del 語句或 set 型方法 remove()discard() 將其移除。

Mailbox 接口語義在某些值得注意的方面與字典語義有所不同。 每次請求消息時,都會基于郵箱的當(dāng)前狀態(tài)生成一個新的表示形式(通常為 Message 實例)。 類似地,當(dāng)向 Mailbox 實例添加消息時,所提供的消息表示形式的內(nèi)容將被復(fù)制。 無論在哪種情況下 Mailbox 實例都不會保留對消息表示形式的引用。

默認(rèn)的 Mailbox 迭代器會迭代消息表示形式,而不像默認(rèn)的字典迭代器那樣迭代鍵。 此外,在迭代期間修改郵箱是安全且有明確定義的。 在創(chuàng)建迭代器之后被添加到郵箱的消息將對該迭代不可見。 在迭代器產(chǎn)出消息之前被從郵箱移除的消息將被靜默地跳過,但是使用來自迭代器的鍵也有可能導(dǎo)致 KeyError 異常,如果對應(yīng)的消息后來被移除的話。

警告

在修改可能同時被其他某個進(jìn)程修改的郵箱時要非常小心。 用于此種任務(wù)的最安全郵箱格式是 Maildir;請盡量避免使用 mbox 之類的單文件格式進(jìn)行并發(fā)寫入。 如果你正在修改一個郵箱,你 必須 在讀取文件中的任何消息或者執(zhí)行添加或刪除消息等修改操作 之前 通過調(diào)用 lock() 以及 unlock() 方法來鎖定它。 如果未鎖定郵箱則將導(dǎo)致丟失消息或損壞整個郵箱的風(fēng)險。

Mailbox 實例具有下列方法:

add(message)?

message 添加到郵箱并返回分配給它的鍵。

形參 message 可以是 Message 實例、email.message.Message 實例、字符串、字節(jié)串或文件類對象(應(yīng)當(dāng)以二進(jìn)制模式打開)。 如果 message 是適當(dāng)?shù)母袷綄?Message 子類的實例(舉例來說,如果它是一個 mboxMessage 實例而這是一個 mbox 實例),將使用其格式專屬的信息。 在其他情況下,則會使用合理的默認(rèn)值作為格式專屬的信息。

在 3.2 版更改: 增加了對二進(jìn)制輸入的支持。

remove(key)?
__delitem__(key)?
discard(key)?

從郵箱中刪除對應(yīng)于 key 的消息。

當(dāng)消息不存在時,如果此方法是作為 remove()__delitem__() 調(diào)用則會引發(fā) KeyError 異常,而如果此方法是作為 discard() 調(diào)用則不會引發(fā)異常。 如果下層郵箱格式支持來自其他進(jìn)程的并發(fā)修改則 discard() 的行為可能是更為適合的。

__setitem__(key, message)?

key 所對應(yīng)的消息替換為 message。 如果沒有與 key 所對應(yīng)的消息則會引發(fā) KeyError 異常。

add() 一樣,形參 message 可以是 Message 實例、email.message.Message 實例、字符串、字節(jié)串或文件類對象(應(yīng)當(dāng)以二進(jìn)制模式打開)。 如果 message 是適當(dāng)?shù)母袷綄?Message 子類的實例(舉例來說,如果它是一個 mboxMessage 實例而這是一個 mbox 實例),將使用其格式專屬的信息。 在其他情況下,當(dāng)前與 key 所對應(yīng)的消息的格式專屬信息則會保持不變。

iterkeys()?
keys()?

如果通過 iterkeys() 調(diào)用則返回一個迭代所有鍵的迭代器,或者如果通過 keys() 調(diào)用則返回一個鍵列表。

itervalues()?
__iter__()?
values()?

如果通過 itervalues()__iter__() 調(diào)用則返回一個迭代所有消息的表示形式的迭代器,或者如果通過 values() 調(diào)用則返回一個由這些表示形式組成的列表。 消息會被表示為適當(dāng)?shù)母袷綄?Message 子類的實例,除非當(dāng) Mailbox 實例被初始化時指定了自定義的消息工廠函數(shù)。

備注

__iter__() 的行為與字典不同,后者是對鍵進(jìn)行迭代。

iteritems()?
items()?

如果通過 iteritems() 調(diào)用則返回一個迭代 (key, message) 對的迭代器,其中 key 為鍵而 message 為消息的表示形式,或者如果通過 items() 調(diào)用則返回一個由這種鍵值對組成的列表。 消息會被表示為適當(dāng)?shù)母袷綄?Message 子類的實例,除非當(dāng) Mailbox 實例被初始化時指定了自定義的消息工廠函數(shù)。

get(key, default=None)?
__getitem__(key)?

返回對應(yīng)于 key 的消息的表示形式。 當(dāng)對應(yīng)的消息不存在時,如果通過 get() 調(diào)用則返回 default 而如果通過 __getitem__() 調(diào)用此方法則會引發(fā) KeyError 異常。 消息會被表示為適當(dāng)?shù)母袷綄?Message 子類的實例,除非當(dāng) Mailbox 實例被初始化時指定了自定義的消息工廠函數(shù)。

get_message(key)?

將對應(yīng)于 key 的消息的表示形式作為適當(dāng)?shù)母袷綄?Message 子類的實例返回,或者如果對應(yīng)的消息不存在則會引發(fā) KeyError 異常。

get_bytes(key)?

返回對應(yīng)于 key 的消息的字節(jié)表示形式,或者如果對應(yīng)的消息不存在則會引發(fā) KeyError 異常。

3.2 新版功能.

get_string(key)?

返回對應(yīng)于 key 的消息的字符串表示形式,或者如果對應(yīng)的消息不存在則會引發(fā) KeyError 異常。 消息是通過 email.message.Message 處理來將其轉(zhuǎn)換為純 7bit 表示形式的。

get_file(key)?

返回對應(yīng)于 key 的消息的文件類表示形式,或者如果對應(yīng)的消息不存在則會引發(fā) KeyError 異常。 文件類對象的行為相當(dāng)于以二進(jìn)制模式打開。 當(dāng)不再需要此文件時應(yīng)當(dāng)將其關(guān)閉。

在 3.2 版更改: 此文件對象實際上是二進(jìn)制文件;之前它被不正確地以文本模式返回。 并且,此文件類對象現(xiàn)在還支持上下文管理協(xié)議:你可以使用 with 語句來自動關(guān)閉它。

備注

不同于其他消息表示形式,文件類表示形式并不一定獨立于創(chuàng)建它們的 Mailbox 實例或下層的郵箱。 每個子類都會提供更具體的文檔。

__contains__(key)?

如果 key 有對應(yīng)的消息則返回 True,否則返回 False。

__len__()?

返回郵箱中消息的數(shù)量。

clear()?

從郵箱中刪除所有消息。

pop(key, default=None)?

返回對應(yīng)于 key 的消息的表示形式并刪除該消息。 如果對應(yīng)的消息不存在則返回 default。 消息會被表示為適當(dāng)?shù)母袷綄?Message 子類的實例,除非當(dāng) Mailbox 實例被初始化時指定了自定義的消息工廠函數(shù)。

popitem()?

返回一個任意的 (key, message) 對,其中 key 為鍵而 message 為消息的表示形式,并刪除對應(yīng)的消息。 如果郵箱為空,則會引發(fā) KeyError 異常。 消息會被表示為適當(dāng)?shù)母袷綄?Message 子類的實例,除非當(dāng) Mailbox 實例被初始化時指定了自定義的消息工廠函數(shù)。

update(arg)?

形參 arg 應(yīng)當(dāng)是 keymessage 的映射或 (key, message) 對的可迭代對象。 用來更新郵箱以使得對于每個給定的 keymessage,與 key 相對應(yīng)的消息會被設(shè)為 message,就像通過使用 __setitem__() 一樣。 類似于 __setitem__(),每個 key 都必須在郵箱中有一個對應(yīng)的消息否則將會引發(fā) KeyError 異常,因此在通常情況下將 arg 設(shè)為 Mailbox 實例是不正確的。

備注

與字典不同,關(guān)鍵字參數(shù)是不受支持的。

flush()?

將所有待定的更改寫入到文件系統(tǒng)。 對于某些 Mailbox 子類來說,更改總是被立即寫入因而 flush() 并不會做任何事,但您仍然應(yīng)當(dāng)養(yǎng)成調(diào)用此方法的習(xí)慣。

lock()?

在郵箱上獲取一個獨占式咨詢鎖以使其他進(jìn)程知道不能修改它。 如果鎖無法被獲取則會引發(fā) ExternalClashError。 所使用的具體鎖機制取決于郵箱的格式。 在對郵箱內(nèi)容進(jìn)行任何修改之前你應(yīng)當(dāng) 總是 鎖定它。

unlock()?

釋放郵箱上的鎖,如果存在的話。

close()?

刷新郵箱,如果必要則將其解鎖。 并關(guān)閉所有打開的文件。 對于某些 Mailbox 子類來說,此方法并不會做任何事。

Maildir?

class mailbox.Maildir(dirname, factory=None, create=True)?

Mailbox 的一個子類,用于 Maildir 格式的郵箱。 形參 factory 是一個可調(diào)用對象,它接受一個文件類消息表示形式(其行為相當(dāng)于以二進(jìn)制模式打開)并返回一個自定義的表示形式。 如果 factoryNone,則會使用 MaildirMessage 作為默認(rèn)的消息表示形式。 如果 createTrue,則當(dāng)郵箱不存在時會創(chuàng)建它。

如果 createTruedirname 路徑存在,它將被視為已有的 maildir 而無需嘗試驗證其目錄布局。

使用 dirname 這個名稱而不使用 path 是出于歷史原因。

Maildir 是一種基于目錄的郵箱格式,它是針對 qmail 郵件傳輸代理而發(fā)明的,現(xiàn)在也得到了其他程序的廣泛支持。 Maildir 郵箱中的消息存儲在一個公共目錄結(jié)構(gòu)中的單獨文件內(nèi)。 這樣的設(shè)計允許 Maildir 郵箱被多個彼此無關(guān)的程序訪問和修改而不會導(dǎo)致數(shù)據(jù)損壞,因此文件鎖定操作是不必要的。

Maildir 郵箱包含三個子目錄,分別是: tmp, newcur。 消息會不時地在 tmp 子目錄中創(chuàng)建然后移至 new 子目錄來結(jié)束投遞。 后續(xù)電子郵件客戶端可能將消息移至 cur 子目錄并將有關(guān)消息狀態(tài)的信息存儲在附帶到其文件名的特殊 "info" 小節(jié)中。

Courier 電子郵件傳輸代理所引入的文件夾風(fēng)格也是受支持的。 主郵箱中任何子目錄只要其名稱的第一個字符是 '.' 就會被視為文件夾。 文件夾名稱會被 Maildir 表示為不帶前綴 '.' 的形式。 每個文件夾自身都是一個 Maildir 郵箱但不應(yīng)包含其他文件夾。 邏輯嵌套關(guān)系是使用 '.' 來劃定層級,例如 "Archived.2005.07"。

備注

Maildir 規(guī)范要求使用在特定消息文件名中使用冒號 (':')。 但是,某些操作系統(tǒng)不允許將此字符用于文件名,如果你希望在這些操作系統(tǒng)上使用類似 Maildir 的格式,你應(yīng)當(dāng)指定改用另一個字符。 嘆號 ('!') 是一個受歡迎的選擇。 例如:

import mailbox
mailbox.Maildir.colon = '!'

colon 屬性也可以在每個實例上分別設(shè)置。

Maildir 實例具有 Mailbox 的所有方法及下列附加方法:

list_folders()?

返回所有文件夾名稱的列表。

get_folder(folder)?

返回表示名稱為 folder 的文件夾的 Maildir 實例。 如果文件夾不存在則會引發(fā) NoSuchMailboxError 異常。

add_folder(folder)?

創(chuàng)建名稱為 folder 的文件夾并返回表示它的 Maildir 實例。

remove_folder(folder)?

刪除名稱為 folder 的文件夾。 如果文件夾包含任何消息,則將引發(fā) NotEmptyError 異常且該文件夾將不會被刪除。

clean()?

從郵箱中刪除最近 36 小時內(nèi)未被訪問過的臨時文件。 Maildir 規(guī)范要求郵件閱讀程序應(yīng)當(dāng)時常進(jìn)行此操作。

Maildir 所實現(xiàn)的某些 Mailbox 方法值得進(jìn)行特別的說明:

add(message)?
__setitem__(key, message)?
update(arg)?

警告

這些方法會基于當(dāng)前進(jìn)程 ID 來生成唯一文件名。 當(dāng)使用多線程時,可能發(fā)生未被檢測到的名稱沖突并導(dǎo)致郵箱損壞,除非是對線程進(jìn)行協(xié)調(diào)以避免使用這些方法同時操作同一個郵箱。

flush()?

對 Maildir 郵箱的所有更改都會立即被應(yīng)用,所以此方法并不會做任何事情。

lock()?
unlock()?

Maildir 郵箱不支持(或要求)鎖定操作,所以此方法并不會做任何事情。

close()?

Maildir 實例不保留任何打開的文件并且下層的郵箱不支持鎖定操作,所以此方法不會做任何事情。

get_file(key)?

根據(jù)主機平臺的不同,當(dāng)返回的文件保持打開狀態(tài)時可能無法修改或移除下層的消息。

參見

Courier 上的 maildir 指南頁面

該格式的規(guī)格說明。 描述了用于支持文件夾的通用擴展。

使用 maildir 格式

Maildir 發(fā)明者對它的說明。 包括已更新的名稱創(chuàng)建方案和 "info" 語義的相關(guān)細(xì)節(jié)。

mbox?

class mailbox.mbox(path, factory=None, create=True)?

Mailbox 的子類,用于 mbox 格式的郵箱。 形參 factory 是一個可調(diào)用對象,它接受一個文件類消息表示形式(其行為相當(dāng)于以二進(jìn)制模式打開)并返回一個自定義的表示形式。 如果 factoryNone,則會使用 mboxMessage 作為默認(rèn)的消息表示形式。 如果 createTrue,則當(dāng)郵箱不存在時會創(chuàng)建它。

mbox 格式是在 Unix 系統(tǒng)上存儲電子郵件的經(jīng)典格式。 mbox 郵箱中的所有消息都存儲在一個單獨文件中,每條消息的開頭由前五個字符為 "From " 的行來指明。

還有一些 mbox 格式變種對原始格式中發(fā)現(xiàn)的缺點做了改進(jìn),mbox 只實現(xiàn)原始格式,有時被稱為 mboxo。 這意味著當(dāng)存儲消息時 Content-Length 標(biāo)頭如果存在則會被忽略并且消息體中出現(xiàn)于行開頭的任何 "From " 會被轉(zhuǎn)換為 ">From ",但是當(dāng)讀取消息時 ">From " 則不會被轉(zhuǎn)換為 "From "。

mbox 所實現(xiàn)的某些 Mailbox 方法值得進(jìn)行特別的說明:

get_file(key)?

mbox 實例上調(diào)用 flush()close() 之后再使用文件可能產(chǎn)生無法預(yù)料的結(jié)果或者引發(fā)異常。

lock()?
unlock()?

使用三種鎖機制 --- dot 鎖,以及可能情況下的 flock()lockf() 系統(tǒng)調(diào)用。

參見

tin 上的 mbox 指南頁面

該格式的規(guī)格說明,包括有關(guān)鎖的詳情。

在 Unix 上配置 Netscape Mail: 為何 Content-Length 格式是不好的

使用原始 mbox 格式而非其變種的一些理由。

"mbox" 是由多個彼此不兼容的郵箱格式構(gòu)成的家族

有關(guān) mbox 變種的歷史。

MH?

class mailbox.MH(path, factory=None, create=True)?

Mailbox 的子類,用于 MH 格式的郵箱。 形參 factory 是一個可調(diào)用對象,它接受一個文件類消息表示形式(其行為相當(dāng)于以二進(jìn)制模式打開)并返回一個自定義的表示形式。 如果 factoryNone,則會使用 MHMessage 作為默認(rèn)的消息表示形式。 如果 createTrue,則當(dāng)郵箱不存在時會創(chuàng)建它。

MH 是一種基于目錄的郵箱格式,它是針對 MH Message Handling System 電子郵件用戶代理而發(fā)明的。 在 MH 郵箱的每條消息都放在單獨文件中。 MH 郵箱中除了郵件消息還可以包含其他 MH 郵箱 (稱為 文件夾)。 文件夾可以無限嵌套。 MH 郵箱還支持 序列,這是一種命名列表,用來對消息進(jìn)行邏輯分組而不必將其移入子文件夾。 序列是在每個文件夾中名為 .mh_sequences 的文件內(nèi)定義的。

MH 類可以操作 MH 郵箱,但它并不試圖模擬 mh 的所有行為。 特別地,它并不會修改 context.mh_profile 文件也不會受其影響,這兩個文件是 mh 用來存儲狀態(tài)和配置數(shù)據(jù)的。

MH 實例具有 Mailbox 的所有方法及下列附加方法:

list_folders()?

返回所有文件夾名稱的列表。

get_folder(folder)?

返回表示名稱為 folder 的文件夾的 MH 實例。 如果文件夾不存在則會引發(fā) NoSuchMailboxError 異常。

add_folder(folder)?

創(chuàng)建名稱為 folder 的文件夾并返回表示它的 MH 實例。

remove_folder(folder)?

刪除名稱為 folder 的文件夾。 如果文件夾包含任何消息,則將引發(fā) NotEmptyError 異常且該文件夾將不會被刪除。

get_sequences()?

返回映射到鍵列表的序列名稱字典。 如果不存在任何序列,則返回空字典。

set_sequences(sequences)?

根據(jù)由映射到鍵列表的名稱組成的字典 sequences 來重新定義郵箱中的序列,該字典與 get_sequences() 返回值的形式一樣。

pack()?

根據(jù)需要重命名郵箱中的消息以消除序號中的空缺。 序列列表中的條目會做相應(yīng)的修改。

備注

已發(fā)送的鍵會因此操作而失效并且不應(yīng)當(dāng)被繼續(xù)使用。

MH 所實現(xiàn)的某些 Mailbox 方法值得進(jìn)行特別的說明:

remove(key)?
__delitem__(key)?
discard(key)?

這些方法會立即刪除消息。 通過在名稱前加綴一個冒號作為消息刪除標(biāo)記的 MH 慣例不會被使用。

lock()?
unlock()?

使用三種鎖機制 --- dot 鎖,以及可能情況下下 flock()lockf() 系統(tǒng)調(diào)用。 對于 MH 郵箱來說,鎖定郵箱意味著鎖定 .mh_sequences 文件,并且僅在執(zhí)行會影響單獨消息文件的操作期間鎖定單獨消息文件。

get_file(key)?

根據(jù)主機平臺的不同,當(dāng)返回的文件保持打開狀態(tài)時可能無法移除下層的消息。

flush()?

對 MH 郵箱的所有更改都會立即被應(yīng)用,所以此方法并不會做任何事情。

close()?

MH 實例不保留任何打開的文件,所以此方法等價于 unlock()。

參見

nmh - Message Handling System

nmh 的主頁,這是原始 mh 的更新版本。

MH & nmh: Email for Users & Programmers

使用 GPL 許可證的介紹 mhnmh 的圖書,包含有關(guān)該郵箱格式的各種信息。

Babyl?

class mailbox.Babyl(path, factory=None, create=True)?

Mailbox 的子類,用于 Babyl 格式的郵箱。 形參 factory 是一個可調(diào)用對象,它接受一個文件類表示形式(其行為相當(dāng)于以二進(jìn)制模式打開)并返回一個自定義的表示形式。 如果 factoryNone,則會使用 BabylMessage 作為默認(rèn)的消息表示形式。 如果 createTrue,則當(dāng)郵箱不存在時會創(chuàng)建它。

Babyl 是 Rmail 電子郵箱用戶代理所使用單文件郵箱格式,包括在 Emacs 中。 每條消息的開頭由一個包含 Control-Underscore ('\037') 和 Control-L ('\014') 這兩個字符的行來指明。 消息的結(jié)束由下一條消息的開頭來指明,或者當(dāng)為最后一條消息時則由一個包含 Control-Underscore ('\037') 字符的行來指明。

Babyl 郵箱中的消息帶有兩組標(biāo)頭:原始標(biāo)頭和所謂的可見標(biāo)頭。 可見標(biāo)頭通常為原始標(biāo)頭經(jīng)過重格式化和刪減以更易讀的子集。 Babyl 郵箱中的每條消息都附帶了一個 標(biāo)簽 列表,即記錄消息相關(guān)額外信息的短字符串,郵箱中所有的用戶定義標(biāo)簽列表會存儲于 Babyl 的選項部分。

Babyl 實例具有 Mailbox 的所有方法及下列附加方法:

get_labels()?

返回郵箱中使用的所有用戶定義標(biāo)簽名稱的列表。

備注

郵箱中存在哪些標(biāo)簽會通過檢查實際的消息而非查詢 Babyl 選項部分的標(biāo)簽列表,但 Babyl 選項部分會在郵箱被修改時更新。

Babyl 所實現(xiàn)的某些 Mailbox 方法使得進(jìn)行特別的說明:

get_file(key)?

在 Babyl 郵箱中,消息的標(biāo)頭并不是與消息體存儲在一起的。 要生成文件類表示形式,標(biāo)頭和消息體會被一起拷貝到一個 io.BytesIO 實例中,它具有與文件相似的 API。 因此,文件類對象實際上獨立于下層郵箱,但與字符串表達(dá)形式相比并不會更節(jié)省內(nèi)存。

lock()?
unlock()?

使用三種鎖機制 --- dot 鎖,以及可能情況下的 flock()lockf() 系統(tǒng)調(diào)用。

參見

Format of Version 5 Babyl Files

Babyl 格式的規(guī)格說明。

Reading Mail with Rmail

Rmail 的幫助手冊,包含了有關(guān) Babyl 語義的一些信息。

MMDF?

class mailbox.MMDF(path, factory=None, create=True)?

Mailbox 的子類,用于 MMDF 格式的郵箱。 形參 factory 是一個可調(diào)用對象,它接受一個文件類消息表示形式(其行為相當(dāng)于以二進(jìn)制模式打開)并返回一個自定義的表示形式。 如果 factoryNone,則會使用 MMDFMessage 作為默認(rèn)的消息表示形式。 如果 createTrue,則當(dāng)郵箱不存在時會創(chuàng)建它。

MMDF 是一種專用于電子郵件傳輸代理 Multichannel Memorandum Distribution Facility 的單文件郵箱格式。 每條消息使用與 mbox 消息相同的形式,但其前后各有包含四個 Control-A ('\001') 字符的行。 與 mbox 格式一樣,每條消息的開頭由一個前五個字符為 "From " 的行來指明,但當(dāng)存儲消息時額外出現(xiàn)的 "From " 不會被轉(zhuǎn)換為 ">From " 因為附加的消息分隔符可防止將這些內(nèi)容誤認(rèn)為是后續(xù)消息的開頭。

MMDF 所實現(xiàn)的某些 Mailbox 方法值得進(jìn)行特別的說明:

get_file(key)?

MMDF 實例上調(diào)用 flush()close() 之后再使用文件可能產(chǎn)生無法預(yù)料的結(jié)果或者引發(fā)異常。

lock()?
unlock()?

使用三種鎖機制 --- dot 鎖,以及可能情況下的 flock()lockf() 系統(tǒng)調(diào)用。

參見

tin 上的 mmdf 指南頁面

MMDF 格式的規(guī)格說明,來自新聞閱讀器 tin 的文檔。

MMDF

一篇描述 Multichannel Memorandum Distribution Facility 的維基百科文章。

Message 對象?

class mailbox.Message(message=None)?

email.message 模塊的 Message 的子類。 mailbox.Message 的子類添加了特定郵箱格式專屬的狀態(tài)和行為。

如果省略了 message,則新實例會以默認(rèn)的空狀態(tài)被創(chuàng)建。 如果 message 是一個 email.message.Message 實例,其內(nèi)容會被拷貝;此外,如果 message 是一個 Message 實例,則任何格式專屬信息會盡可能地被拷貝。 如果 message 是一個字符串、字節(jié)串或文件,則它應(yīng)當(dāng)包含兼容 RFC 2822 的消息,該消息會被讀取和解析。 文檔應(yīng)當(dāng)以二進(jìn)制模式打開,但文本模式的文件也會被接受以向下兼容。

各個子類所提供的格式專屬狀態(tài)和行為各有不同,但總的來說只有那些不僅限于特定郵箱的特性才會被支持(雖然這些特性可能專屬于特定郵箱格式)。 例如,例如,單文件郵箱格式的文件偏移量和基于目錄的郵箱格式的文件名都不會被保留,因為它們都僅適用于對應(yīng)的原始郵箱。 但消息是否已被用戶讀取或標(biāo)記為重要等狀態(tài)則會被保留,因為它們適用于消息本身。

不要求用 Message 實例來表示使用 Mailbox 實例所提取到的消息。 在某些情況下,生成 Message 表示形式所需的時間和內(nèi)存空間可能是不可接受的。 對于此類情況,Mailbox 實例還提供了字符串和文件類表示形式,并可在初始化 Mailbox 實例時指定自定義的消息工廠函數(shù)。

MaildirMessage?

class mailbox.MaildirMessage(message=None)?

具有 Maildir 專屬行為的消息。 形參 message 的含義與 Message 構(gòu)造器一致。

通常,郵件用戶代理應(yīng)用程序會在用戶第一次打開并關(guān)閉郵箱之后將 new 子目錄中的所有消息移至 cur 子目錄,將這些消息記錄為舊消息,無論它們是否真的已被閱讀。 cur 下的每條消息都有一個 "info" 部分被添加到其文件名中以存儲有關(guān)其狀態(tài)的信息。 (某些郵件閱讀器還會把 "info" 部分也添加到 new 下的消息中。) "info" 部分可以采用兩種形式之一:它可能包含 "2," 后面跟一個經(jīng)標(biāo)準(zhǔn)化的旗標(biāo)列表(例如 "2,FR")或者它可能包含 "1," 后面跟所謂的實驗性信息。 Maildir 消息的標(biāo)準(zhǔn)旗標(biāo)如下:

旗標(biāo)

含意

說明

D

草稿

正在撰寫中

F

已標(biāo)記

已被標(biāo)記為重要

P

已檢視

轉(zhuǎn)發(fā),重新發(fā)送或退回

R

已回復(fù)

回復(fù)給

S

已查看

已閱讀

T

已刪除

標(biāo)記為可被刪除

MaildirMessage 實例提供以下方法:

get_subdir()?

返回 "new" (如果消息應(yīng)當(dāng)被存儲在 new 子目錄下) 或者 "cur" (如果消息應(yīng)當(dāng)被存儲在 cur 子目錄下)。

備注

消息通常會在其郵箱被訪問后被從 new 移至 cur,無論該消息是否已被閱讀。 如果 msg.get_flags()`` 中的 "S" ``True 則說明消息 msg 已被閱讀。

set_subdir(subdir)?

設(shè)置消息應(yīng)當(dāng)被存儲到的子目錄。 形參 subdir 必須為 "new" 或 "cur"。

get_flags()?

返回一個指明當(dāng)前所設(shè)旗標(biāo)的字符串。 如果消息符合標(biāo)準(zhǔn)的 Maildir 格式,則結(jié)果為零或按字母順序各自出現(xiàn)一次的 'D', 'F', 'P', 'R', 'S''T' 的拼接。 如果未設(shè)任何旗標(biāo)或者如果 "info" 包含實驗性語義則返回空字符串。

set_flags(flags)?

設(shè)置由 flags 所指定的旗標(biāo)并重置所有其它旗標(biāo)。

add_flag(flag)?

設(shè)置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性添加一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。 當(dāng)前 "info" 會被覆蓋,無論它是否只包含實驗性信息而非旗標(biāo)。

remove_flag(flag)?

重置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性移除一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。 如果 "info" 包含實驗性信息而非旗標(biāo),則當(dāng)前的 "info" 不會被修改。

get_date()?

以表示 Unix 紀(jì)元秒數(shù)的浮點數(shù)形式返回消息的發(fā)送日期。

set_date(date)?

將消息的發(fā)送日期設(shè)為 date,一個表示 Unix 紀(jì)元秒數(shù)的浮點數(shù)。

get_info()?

返回一個包含消息的 "info" 的字符串。 這適用于訪問和修改實驗性的 "info" (即不是由旗標(biāo)組成的列表)。

set_info(info)?

將 "info" 設(shè)為 info,這應(yīng)當(dāng)是一個字符串。

當(dāng)一個 MaildirMessage 實例基于 mboxMessageMMDFMessage 實例被創(chuàng)建時,將會忽略 StatusX-Status 標(biāo)頭并進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

mboxMessageMMDFMessage 狀態(tài)

"cur" 子目錄

O 旗標(biāo)

F 旗標(biāo)

F 旗標(biāo)

R 旗標(biāo)

A 旗標(biāo)

S 旗標(biāo)

R 旗標(biāo)

T 旗標(biāo)

D 旗標(biāo)

當(dāng)一個 MaildirMessage 實例基于 MHMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MHMessage 狀態(tài)

"cur" 子目錄

"unseen" 序列

"cur" 子目錄和 S 旗標(biāo)

非 "unseen" 序列

F 旗標(biāo)

"flagged" 序列

R 旗標(biāo)

"replied" 序列

當(dāng)一個 MaildirMessage 實例基于 BabylMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

BabylMessage 狀態(tài)

"cur" 子目錄

"unseen" 標(biāo)簽

"cur" 子目錄和 S 旗標(biāo)

非 "unseen" 標(biāo)簽

P 旗標(biāo)

"forwarded" 或 "resent" 標(biāo)簽

R 旗標(biāo)

"answered" 標(biāo)簽

T 旗標(biāo)

"deleted" 標(biāo)簽

mboxMessage?

class mailbox.mboxMessage(message=None)?

具有 mbox 專屬行為的消息。 形參 message 的含義與 Message 構(gòu)造器一致。

mbox 郵箱中的消息會一起存儲在單個文件中。 發(fā)件人的信封地址和發(fā)送時間通常存儲在指明每條消息的起始的以 "From " 打頭的行中,不過在 mbox 的各種實現(xiàn)之間此數(shù)據(jù)的確切格式具有相當(dāng)大的差異。 指明消息狀態(tài)的各種旗標(biāo),例如是否已讀或標(biāo)記為重要等等通常存儲在 StatusX-Status 標(biāo)頭中。

傳統(tǒng)的 mbox 消息旗標(biāo)如下:

旗標(biāo)

含意

說明

R

已閱讀

已閱讀

O

舊消息

之前已經(jīng)過 MUA 檢測

D

已刪除

標(biāo)記為可被刪除

F

已標(biāo)記

已被標(biāo)記為重要

A

已回復(fù)

回復(fù)給

"R" 和 "O" 旗標(biāo)存儲在 Status 標(biāo)頭中,而 "D", "F" 和 "A" 旗標(biāo)存儲在 X-Status 標(biāo)頭中。 旗標(biāo)和標(biāo)頭通常會按上述順序顯示。

mboxMessage 實例提供了下列方法:

get_from()?

返回一個表示在 mbox 郵箱中標(biāo)記消息起始的 "From " 行的字符串。 開頭的 "From " 和末尾的換行符會被去除。

set_from(from_, time_=None)?

將 "From " 行設(shè)為 from_,這應(yīng)當(dāng)被指定為不帶開頭的 "From " 或末尾的換行符。 為方便起見,可以指定 time_ 并將經(jīng)過適當(dāng)?shù)母袷交偬砑拥?from_。 如果指定了 time_,它應(yīng)當(dāng)是一個 time.struct_time 實例,適合傳入 time.strftime() 的元組或者 True (以使用 time.gmtime())。

get_flags()?

返回一個指明當(dāng)前所設(shè)旗標(biāo)的字符串。 如果消息符合規(guī)范格式,則結(jié)果為零或各自出現(xiàn)一次的 'R', 'O', 'D', 'F''A' 按上述順序的拼接。

set_flags(flags)?

設(shè)置由 flags 所指明的旗標(biāo)并重啟所有其他旗標(biāo)。 形參 flags 應(yīng)當(dāng)為零或各自出現(xiàn)多次的 'R', 'O', 'D', 'F''A' 按任意順序的拼接。

add_flag(flag)?

設(shè)置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性添加一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。

remove_flag(flag)?

重置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性移除一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。

當(dāng)一個 mboxMessage 實例基于 MaildirMessage 實例被創(chuàng)建時,"From " 行會基于 MaildirMessage 實例的發(fā)送時間被生成,并進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MaildirMessage 狀態(tài)

R 旗標(biāo)

S 旗標(biāo)

O 旗標(biāo)

"cur" 子目錄

D 旗標(biāo)

T 旗標(biāo)

F 旗標(biāo)

F 旗標(biāo)

A 旗標(biāo)

R 旗標(biāo)

當(dāng)一個 mboxMessage 實例基于 MHMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MHMessage 狀態(tài)

R 旗標(biāo) 和 O 旗標(biāo)

非 "unseen" 序列

O 旗標(biāo)

"unseen" 序列

F 旗標(biāo)

"flagged" 序列

A 旗標(biāo)

"replied" 序列

當(dāng)一個 mboxMessage 實例基于 BabylMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

BabylMessage 狀態(tài)

R 旗標(biāo) 和 O 旗標(biāo)

非 "unseen" 標(biāo)簽

O 旗標(biāo)

"unseen" 標(biāo)簽

D 旗標(biāo)

"deleted" 標(biāo)簽

A 旗標(biāo)

"answered" 標(biāo)簽

當(dāng)一個 Message 實例基于 MMDFMessage 實例被創(chuàng)建時,"From " 行會被拷貝并直接對應(yīng)所有旗標(biāo)。

結(jié)果狀態(tài)

MMDFMessage 狀態(tài)

R 旗標(biāo)

R 旗標(biāo)

O 旗標(biāo)

O 旗標(biāo)

D 旗標(biāo)

D 旗標(biāo)

F 旗標(biāo)

F 旗標(biāo)

A 旗標(biāo)

A 旗標(biāo)

MHMessage?

class mailbox.MHMessage(message=None)?

具有 MH 專屬行為的消息。 形參 message 的含義與 Message 構(gòu)造器一致。

MH 消息不支持傳統(tǒng)意義上的標(biāo)記或旗標(biāo),但它們支持序列,即對任意消息的邏輯分組。 某些郵件閱讀程序 (但不包括標(biāo)準(zhǔn) mhnmh) 以與其他格式使用旗標(biāo)類似的方式來使用序列,如下所示:

序列

說明

unseen

未閱讀,但之前已經(jīng)過 MUA 檢測

已回復(fù)

回復(fù)給

已標(biāo)記

已被標(biāo)記為重要

MHMessage 實例提供了下列方法:

get_sequences()?

返回一個包含此消息的序列的名稱的列表。

set_sequences(sequences)?

設(shè)置包含此消息的序列的列表。

add_sequence(sequence)?

sequence 添加到包含此消息的序列的列表。

remove_sequence(sequence)?

sequence 從包含此消息的序列的列表中移除。

當(dāng)一個 MHMessage 實例基于 MaildirMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MaildirMessage 狀態(tài)

"unseen" 序列

非 S 旗標(biāo)

"replied" 序列

R 旗標(biāo)

"flagged" 序列

F 旗標(biāo)

當(dāng)一個 MHMessage 實例基于 mboxMessageMMDFMessage 實例被創(chuàng)建時,將會忽略 StatusX-Status 標(biāo)頭并進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

mboxMessageMMDFMessage 狀態(tài)

"unseen" 序列

非 R 旗標(biāo)

"replied" 序列

A 旗標(biāo)

"flagged" 序列

F 旗標(biāo)

當(dāng)一個 MHMessage 實例基于 BabylMessage 實例被創(chuàng)建時,將進(jìn)入下列轉(zhuǎn)換:

結(jié)果狀態(tài)

BabylMessage 狀態(tài)

"unseen" 序列

"unseen" 標(biāo)簽

"replied" 序列

"answered" 標(biāo)簽

BabylMessage?

class mailbox.BabylMessage(message=None)?

具有 Babyl 專屬行為的消息。 形參 message 的含義與 Message 構(gòu)造器一致。

某些消息標(biāo)簽被稱為 屬性,根據(jù)慣例被定義為具有特殊的含義。 這些屬性如下所示:

標(biāo)簽

說明

unseen

未閱讀,但之前已經(jīng)過 MUA 檢測

deleted

標(biāo)記為可被刪除

filed

復(fù)制到另一個文件或郵箱

answered

回復(fù)給

forwarded

已轉(zhuǎn)發(fā)

edited

已被用戶修改

resent

已重發(fā)

默認(rèn)情況下,Rmail 只顯示可見標(biāo)頭。 不過 BabylMessage 類會使用原始標(biāo)頭因為它們更完整。 如果需要可以顯式地訪問可見標(biāo)頭。

BabylMessage 實例提供了下列方法:

get_labels()?

返回郵件上的標(biāo)簽列表。

set_labels(labels)?

將消息上的標(biāo)簽列表設(shè)置為 labels 。

add_label(label)?

label 添加到消息上的標(biāo)簽列表中。

remove_label(label)?

從消息上的標(biāo)簽列表中刪除 label 。

get_visible()?

返回一個 Message 實例,其標(biāo)頭為消息的可見標(biāo)頭而其消息體為空。

set_visible(visible)?

將消息的可見標(biāo)頭設(shè)為與 message 中的標(biāo)頭一致。 形參 visible 應(yīng)當(dāng)是一個 Message 實例,email.message.Message 實例,字符串或文件類對象(且應(yīng)當(dāng)以文本模式打開)。

update_visible()?

當(dāng)一個 BabylMessage 實例的原始標(biāo)頭被修改時,可見標(biāo)頭不會自動進(jìn)行對應(yīng)修改。 此方法將按以下方式更新可見標(biāo)頭:每個具有對應(yīng)原始標(biāo)頭的可見標(biāo)頭會被設(shè)為原始標(biāo)頭的值,每個沒有對應(yīng)原始標(biāo)頭的可見標(biāo)頭會被移除,而任何存在于原始標(biāo)頭但不存在于可見標(biāo)頭中的 Date, From, Reply-To, To, CCSubject 會被添加至可見標(biāo)頭。

當(dāng)一個 BabylMessage 實例基于 MaildirMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MaildirMessage 狀態(tài)

"unseen" 標(biāo)簽

非 S 旗標(biāo)

"deleted" 標(biāo)簽

T 旗標(biāo)

"answered" 標(biāo)簽

R 旗標(biāo)

"forwarded" 標(biāo)簽

P 旗標(biāo)

當(dāng)一個 BabylMessage 實例基于 mboxMessageMMDFMessage 實例被創(chuàng)建時,將會忽略 StatusX-Status 標(biāo)頭并進(jìn)入下列轉(zhuǎn)換:

結(jié)果狀態(tài)

mboxMessageMMDFMessage 狀態(tài)

"unseen" 標(biāo)簽

非 R 旗標(biāo)

"deleted" 標(biāo)簽

D 旗標(biāo)

"answered" 標(biāo)簽

A 旗標(biāo)

當(dāng)一個 BabylMessage 實例基于 MHMessage 實例被創(chuàng)建時,將進(jìn)入下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MHMessage 狀態(tài)

"unseen" 標(biāo)簽

"unseen" 序列

"answered" 標(biāo)簽

"replied" 序列

MMDFMessage?

class mailbox.MMDFMessage(message=None)?

具有 MMDF 專屬行為的消息。 形參 message 的含義與 Message 構(gòu)造器一致。

與 mbox 郵箱中的消息類似,MMDF 消息會與將發(fā)件人的地址和發(fā)送日期作為以 "From " 打頭的初始行一起存儲。 同樣地,指明消息狀態(tài)的旗標(biāo)通常存儲在 StatusX-Status 標(biāo)頭中。

傳統(tǒng)的 MMDF 消息旗標(biāo)與 mbox 消息的類似,如下所示:

旗標(biāo)

含意

說明

R

已閱讀

已閱讀

O

舊消息

之前已經(jīng)過 MUA 檢測

D

已刪除

標(biāo)記為可被刪除

F

已標(biāo)記

已被標(biāo)記為重要

A

已回復(fù)

回復(fù)給

"R" 和 "O" 旗標(biāo)存儲在 Status 標(biāo)頭中,而 "D", "F" 和 "A" 旗標(biāo)存儲在 X-Status 標(biāo)頭中。 旗標(biāo)和標(biāo)頭通常會按上述順序顯示。

MMDFMessage 實例提供了下列方法,與 mboxMessage 所提供的類似:

get_from()?

返回一個表示在 mbox 郵箱中標(biāo)記消息起始的 "From " 行的字符串。 開頭的 "From " 和末尾的換行符會被去除。

set_from(from_, time_=None)?

將 "From " 行設(shè)為 from_,這應(yīng)當(dāng)被指定為不帶開頭的 "From " 或末尾的換行符。 為方便起見,可以指定 time_ 并將經(jīng)過適當(dāng)?shù)母袷交偬砑拥?from_。 如果指定了 time_,它應(yīng)當(dāng)是一個 time.struct_time 實例,適合傳入 time.strftime() 的元組或者 True (以使用 time.gmtime())。

get_flags()?

返回一個指明當(dāng)前所設(shè)旗標(biāo)的字符串。 如果消息符合規(guī)范格式,則結(jié)果為零或各自出現(xiàn)一次的 'R', 'O', 'D', 'F''A' 按上述順序的拼接。

set_flags(flags)?

設(shè)置由 flags 所指明的旗標(biāo)并重啟所有其他旗標(biāo)。 形參 flags 應(yīng)當(dāng)為零或各自出現(xiàn)多次的 'R', 'O', 'D', 'F''A' 按任意順序的拼接。

add_flag(flag)?

設(shè)置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性添加一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。

remove_flag(flag)?

重置由 flag 所指明的旗標(biāo)而不改變其他旗標(biāo)。 要一次性移除一個以上的旗標(biāo),flag 可以為包含一個以上字符的字符串。

當(dāng)一個 MMDFMessage 實例基于 MaildirMessage 實例被創(chuàng)建時,"From " 行會基于 MaildirMessage 實例的發(fā)送日期被生成,并進(jìn)入下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MaildirMessage 狀態(tài)

R 旗標(biāo)

S 旗標(biāo)

O 旗標(biāo)

"cur" 子目錄

D 旗標(biāo)

T 旗標(biāo)

F 旗標(biāo)

F 旗標(biāo)

A 旗標(biāo)

R 旗標(biāo)

當(dāng)一個 MMDFMessage 實例基于 MHMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

MHMessage 狀態(tài)

R 旗標(biāo) 和 O 旗標(biāo)

非 "unseen" 序列

O 旗標(biāo)

"unseen" 序列

F 旗標(biāo)

"flagged" 序列

A 旗標(biāo)

"replied" 序列

當(dāng)一個 MMDFMessage 實例基于 BabylMessage 實例被創(chuàng)建時,將進(jìn)行下列轉(zhuǎn)換:

結(jié)果狀態(tài)

BabylMessage 狀態(tài)

R 旗標(biāo) 和 O 旗標(biāo)

非 "unseen" 標(biāo)簽

O 旗標(biāo)

"unseen" 標(biāo)簽

D 旗標(biāo)

"deleted" 標(biāo)簽

A 旗標(biāo)

"answered" 標(biāo)簽

當(dāng)一個 MMDFMessage 實例基于 mboxMessage 實例被創(chuàng)建時,"From " 行會被拷貝并直接對應(yīng)所有旗標(biāo):

結(jié)果狀態(tài)

mboxMessage 狀態(tài)

R 旗標(biāo)

R 旗標(biāo)

O 旗標(biāo)

O 旗標(biāo)

D 旗標(biāo)

D 旗標(biāo)

F 旗標(biāo)

F 旗標(biāo)

A 旗標(biāo)

A 旗標(biāo)

異常?

mailbox 模塊中定義了下列異常類:

exception mailbox.Error?

所有其他模塊專屬異常的基類。

exception mailbox.NoSuchMailboxError?

在期望獲得一個郵箱但未找到時被引發(fā),例如當(dāng)使用不存在的路徑來實例化一個 Mailbox 子類時 (且將 create 形參設(shè)為 False),或是當(dāng)打開一個不存在的路徑時。

exception mailbox.NotEmptyError?

在期望一個郵箱為空但不為空時被引發(fā),例如當(dāng)刪除一個包含消息的文件夾時。

exception mailbox.ExternalClashError?

在某些郵箱相關(guān)條件超出了程序控制范圍導(dǎo)致其無法繼續(xù)運行時被引發(fā),例如當(dāng)要獲取的鎖已被另一個程序獲取時,或是當(dāng)要生成的唯一性文件名已存在時。

exception mailbox.FormatError?

在某個文件中的數(shù)據(jù)無法被解析時被引發(fā),例如當(dāng)一個 MH 實例嘗試讀取已損壞的 .mh_sequences 文件時。

例子?

一個打印指定郵箱中所有消息的主題的簡單示例:

import mailbox
for message in mailbox.mbox('~/mbox'):
    subject = message['subject']       # Could possibly be None.
    if subject and 'python' in subject.lower():
        print(subject)

要將所有郵件從 Babyl 郵箱拷貝到 MH 郵箱,請轉(zhuǎn)換所有可轉(zhuǎn)換的格式專屬信息:

import mailbox
destination = mailbox.MH('~/Mail')
destination.lock()
for message in mailbox.Babyl('~/RMAIL'):
    destination.add(mailbox.MHMessage(message))
destination.flush()
destination.unlock()

這個示例將來自多個郵件列表的郵件分類放入不同的郵箱,小心避免由于其他程序的并發(fā)修改導(dǎo)致的郵件損壞,由于程序中斷導(dǎo)致的郵件丟失,或是由于郵箱中消息格式錯誤導(dǎo)致的意外終止:

import mailbox
import email.errors

list_names = ('python-list', 'python-dev', 'python-bugs')

boxes = {name: mailbox.mbox('~/email/%s' % name) for name in list_names}
inbox = mailbox.Maildir('~/Maildir', factory=None)

for key in inbox.iterkeys():
    try:
        message = inbox[key]
    except email.errors.MessageParseError:
        continue                # The message is malformed. Just leave it.

    for name in list_names:
        list_id = message['list-id']
        if list_id and name in list_id:
            # Get mailbox to use
            box = boxes[name]

            # Write copy to disk before removing original.
            # If there's a crash, you might duplicate a message, but
            # that's better than losing a message completely.
            box.lock()
            box.add(message)
            box.flush()
            box.unlock()

            # Remove original message
            inbox.lock()
            inbox.discard(key)
            inbox.flush()
            inbox.unlock()
            break               # Found destination, so stop looking.

for box in boxes.itervalues():
    box.close()