mailbox – メールアーカイブのアクセスと操作¶
目的: | 様々なローカルファイルフォーマットのメールを扱う |
---|---|
利用できるバージョン: | 1.4 以上 |
mailbox モジュールはローカルファイルフォーマットに格納されたメールのメッセージにアクセスする共通 API を定義します。
- Maildir
- mbox
- MH
- Babyl
- MMDF
Mailbox と Message という2つのベースクラスがあります。各メールボックスのフォーマットは、そのフォーマットの詳細を実装した対応するサブクラスのペアを含みます。
mbox¶
mbox フォーマットは全てプレーンテキストなので文章で説明することが最も簡単です。各メールボックスは全てのメッセージを連結した1つのファイルとして格納されます。”From ” (From の後にスペースが1個続く) で始まる行に遭遇すると、新たなメッセージの始まりとして扱われます。メッセージ本文の行頭に “From ” が現れたときその行の接頭辞として “>” でエスケープします。
mbox メールボックスを作成する¶
email.mbox クラスのコンストラクタにファイル名を渡してインスタンス化してください。もしそのファイルが存在しなかったら add() を使用してそのメールボックスにメッセージを追加するときにメールボックスが作成されます。
import mailbox
import email.utils
from_addr = email.utils.formataddr(('Author', 'author@example.com'))
to_addr = email.utils.formataddr(('Recipient', 'recipient@example.com'))
mbox = mailbox.mbox('example.mbox')
mbox.lock()
try:
msg = mailbox.mboxMessage()
msg.set_unixfrom('author Sat Feb 7 01:05:34 2009')
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = 'Sample message 1'
msg.set_payload('This is the body.\nFrom (should be escaped).\nThere are 3 lines.\n')
mbox.add(msg)
mbox.flush()
msg = mailbox.mboxMessage()
msg.set_unixfrom('author')
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = 'Sample message 2'
msg.set_payload('This is the second body.\n')
mbox.add(msg)
mbox.flush()
finally:
mbox.unlock()
print open('example.mbox', 'r').read()
このスクリプトの実行結果は2つのメッセージを持つ新たなメールボックスが作成されます。
$ python mailbox_mbox_create.py
From MAILER-DAEMON Sun Feb 17 16:32:33 2013
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 1
This is the body.
>From (should be escaped).
There are 3 lines.
From MAILER-DAEMON Sun Feb 17 16:32:33 2013
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 2
This is the second body.
mbox メールボックスを読み込む¶
既存のメールボックスを読むには、そのメールボックスをオープンして辞書のように mbox オブジェクトを扱います。メッセージオブジェクトはメールボックスインスタンスが定義した任意の値をキーに取りますが、そのオブジェクトの内部的な識別子として以外に意味はありません。
import mailbox
mbox = mailbox.mbox('example.mbox')
for message in mbox:
print message['subject']
オープンしたメールボックスは繰り返し処理することができますが、辞書とは違い、メールボックスのデフォルトイテレータは キー の代わりに 値 で動作します。
$ python mailbox_mbox_read.py
Sample message 1
Sample message 2
mbox メールボックスからメッセージを削除する¶
mbox ファイルから既存メッセージを削除するには remove() メソッドにそのキーを渡すか del を使用してください。
import mailbox
mbox = mailbox.mbox('example.mbox')
to_remove = []
for key, msg in mbox.iteritems():
if '2' in msg['subject']:
print 'Removing:', key
to_remove.append(key)
mbox.lock()
try:
for key in to_remove:
mbox.remove(key)
finally:
mbox.flush()
mbox.close()
print open('example.mbox', 'r').read()
メールボックスのファイルに対する同時アクセス問題を防ぐために lock() や unlock() を使用していることに注意してください。そして、強制的にその変更内容をディスクへ書き込むために flush() します。
$ python mailbox_mbox_remove.py
Removing: 1
From MAILER-DAEMON Sun Feb 17 16:32:33 2013
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 1
This is the body.
>From (should be escaped).
There are 3 lines.
Maildir¶
1つの mbox ファイルの同時アクセスによる変更の問題を解決するために Maildir フォーマットが作成されました。1つのファイルを使用するのではなく、メールボックスをディレクトリとして構成して各メッセージをそのディレクトリ内に保存します。また Maildir メールボックスの API はサブフォルダでも動作するようにメソッドが拡張されているのでネストされたメールボックスも扱うことができます。
Maildir メールボックスを作成する¶
Maildir と mbox の使用における実際の違いは email.Maildir オブジェクトをインスタンス化するためにコンストラクタへメールボックスを含むディレクトリを渡す必要がある点のみになります。mbox のセクションで説明した通り、もしディレクトリが存在しなかったら add() を使用してメッセージを追加したときにメールボックスが作成されます。
import mailbox
import email.utils
import os
from_addr = email.utils.formataddr(('Author', 'author@example.com'))
to_addr = email.utils.formataddr(('Recipient', 'recipient@example.com'))
mbox = mailbox.Maildir('Example')
mbox.lock()
try:
msg = mailbox.mboxMessage()
msg.set_unixfrom('author Sat Feb 7 01:05:34 2009')
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = 'Sample message 1'
msg.set_payload('This is the body.\nFrom (will not be escaped).\nThere are 3 lines.\n')
mbox.add(msg)
mbox.flush()
msg = mailbox.mboxMessage()
msg.set_unixfrom('author Sat Feb 7 01:05:34 2009')
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = 'Sample message 2'
msg.set_payload('This is the second body.\n')
mbox.add(msg)
mbox.flush()
finally:
mbox.unlock()
for dirname, subdirs, files in os.walk('Example'):
print dirname
print '\tDirectories:', subdirs
for name in files:
fullname = os.path.join(dirname, name)
print
print '***', fullname
print open(fullname).read()
print '*' * 20
メールボックスへメッセージを追加すると “new” サブディレクトリにそのメッセージが追加されます。メールクライアントがそのメッセージを “読み込む” と “cur” サブディレクトリへ移動されます。
Warning
複数プロセスから同じ Maildir へ書き込むことは安全ですが add() はスレッドセーフではありません。そのため、同一プロセスの複数スレッドからメールボックスへ同時アクセスによる変更を防ぐためにセマフォ又はロックの仕組みを使用するようにしてください。
$ python mailbox_maildir_create.py
Example
Directories: ['cur', 'new', 'tmp']
Example/cur
Directories: []
Example/new
Directories: []
*** Example/new/1361118753.M257292P70977Q1.hubert.local
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 1
This is the body.
From (will not be escaped).
There are 3 lines.
********************
*** Example/new/1361118753.M258130P70977Q2.hubert.local
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 2
This is the second body.
********************
Example/tmp
Directories: []
Maildir メールボックスを読み込む¶
やはり mbox と同じように既存の Maildir メールボックスから読み込んでください。
import mailbox
mbox = mailbox.Maildir('Example')
for message in mbox:
print message['subject']
メッセージは指定した特定の順番で読めないことに注意してください。
$ python mailbox_maildir_read.py
Sample message 2
Sample message 1
Maildir メールボックスからメッセージを削除する¶
Maildir メールボックスから既存メッセージを削除するには remove() メソッドにそのキーを渡すか del を使用してください。
import mailbox
import os
mbox = mailbox.Maildir('Example')
to_remove = []
for key, msg in mbox.iteritems():
if '2' in msg['subject']:
print 'Removing:', key
to_remove.append(key)
mbox.lock()
try:
for key in to_remove:
mbox.remove(key)
finally:
mbox.flush()
mbox.close()
for dirname, subdirs, files in os.walk('Example'):
print dirname
print '\tDirectories:', subdirs
for name in files:
fullname = os.path.join(dirname, name)
print
print '***', fullname
print open(fullname).read()
print '*' * 20
$ python mailbox_maildir_remove.py
Removing: 1361118753.M258130P70977Q2.hubert.local
Example
Directories: ['cur', 'new', 'tmp']
Example/cur
Directories: []
Example/new
Directories: []
*** Example/new/1361118753.M257292P70977Q1.hubert.local
From: Author <author@example.com>
To: Recipient <recipient@example.com>
Subject: Sample message 1
This is the body.
From (will not be escaped).
There are 3 lines.
********************
Example/tmp
Directories: []
Maildir フォルダ¶
Maildir メールボックスのサブディレクトリ又は フォルダ は Maildir クラスのメソッドを通して直接管理できます。メソッドを呼び出すと、所定のメールボックスのサブフォルダに対する一覧表示、取り出し、作成、削除ができます。
import mailbox
import os
def show_maildir(name):
os.system('find %s -print' % name)
mbox = mailbox.Maildir('Example')
print 'Before:', mbox.list_folders()
show_maildir('Example')
print
print '#' * 30
print
mbox.add_folder('subfolder')
print 'subfolder created:', mbox.list_folders()
show_maildir('Example')
subfolder = mbox.get_folder('subfolder')
print 'subfolder contents:', subfolder.list_folders()
print
print '#' * 30
print
subfolder.add_folder('second_level')
print 'second_level created:', subfolder.list_folders()
show_maildir('Example')
print
print '#' * 30
print
subfolder.remove_folder('second_level')
print 'second_level removed:', subfolder.list_folders()
show_maildir('Example')
フォルダのディレクトリ名は . から始まるフォルダ名で構成されます。
$ python mailbox_maildir_folders.py
Example
Example/cur
Example/new
Example/new/1361118753.M257292P70977Q1.hubert.local
Example/tmp
Example
Example/.subfolder
Example/.subfolder/cur
Example/.subfolder/maildirfolder
Example/.subfolder/new
Example/.subfolder/tmp
Example/cur
Example/new
Example/new/1361118753.M257292P70977Q1.hubert.local
Example/tmp
Example
Example/.subfolder
Example/.subfolder/.second_level
Example/.subfolder/.second_level/cur
Example/.subfolder/.second_level/maildirfolder
Example/.subfolder/.second_level/new
Example/.subfolder/.second_level/tmp
Example/.subfolder/cur
Example/.subfolder/maildirfolder
Example/.subfolder/new
Example/.subfolder/tmp
Example/cur
Example/new
Example/new/1361118753.M257292P70977Q1.hubert.local
Example/tmp
Example
Example/.subfolder
Example/.subfolder/cur
Example/.subfolder/maildirfolder
Example/.subfolder/new
Example/.subfolder/tmp
Example/cur
Example/new
Example/new/1361118753.M257292P70977Q1.hubert.local
Example/tmp
Before: []
##############################
subfolder created: ['subfolder']
subfolder contents: []
##############################
second_level created: ['second_level']
##############################
second_level removed: []
その他のフォーマット¶
MH は幾つかのメールハンドラで使用される複数ファイルの別のメールボックスフォーマットです。Babyl や MMDF は mbox とは違うメッセージセパレータを持つ1ファイルフォーマットです。こういったフォーマットは mbox や Maildir ほど一般的ではないと思います。Babyl や MMDF は mbox と同じ API を、MH は Maildir クラスにあるフォルダ関連のメソッドをサポートします。
See also
- mailbox
- 本モジュールの標準ライブラリドキュメント
- mbox manpage from qmail
- http://www.qmail.org/man/man5/mbox.html
- maildir manpage from qmail
- http://www.qmail.org/man/man5/maildir.html
- email モジュール
- mhlib
- mhlib モジュール