20.10. "imaplib" --- IMAP4 プロトコルクライアント
*************************************************

**ソースコード:** Lib/imaplib.py

======================================================================

このモジュールでは三つのクラス、 "IMAP4", "IMAP4_SSL" と
"IMAP4_stream" を定義します。これらのクラスは IMAP4 サーバへの接続をカ
プセル化し、 **RFC 2060** に定義されている IMAP4rev1 クライアントプロ
トコルの大規模なサブセットを実装しています。このクラスは IMAP4 (**RFC
1730**) 準拠のサーバと後方互換性がありますが、 "STATUS" コマンドは
IMAP4 ではサポートされていないので注意してください。

"imaplib" モジュール内では三つのクラスを提供しており、 "IMAP4" は基底
クラスとなります:

class imaplib.IMAP4([host[, port]])

   このクラスは実際の IMAP4 プロトコルを実装しています。インスタンスが
   初期化された際に接続が生成され、プロトコルバージョン (IMAP4 または
   IMAP4rev1) が決定されます。*host* が指定されていない場合、"''" (ロ
   ーカルホスト) が用いられます。*port* が省略された場合、標準の IMAP4
   ポート番号 (143)  が用いられます。

例外は "IMAP4" クラスの属性として定義されています:

exception IMAP4.error

   何らかのエラー発生の際に送出される例外です。例外の理由は文字列とし
   てコンストラクタに渡されます。

exception IMAP4.abort

   IMAP4 サーバのエラーが生じると、この例外が送出されます。この例外は
   "IMAP4.error" のサブクラスです。通常、インスタンスを閉じ、新たなイ
   ンスタンスを再び生成することで、この例外から復旧できます。

exception IMAP4.readonly

   この例外は書き込み可能なメールボックスの状態がサーバによって変更さ
   れた際に送出されます。この例外は "IMAP4.error" のサブクラスです。他
   の何らかのクライアントが現在書き込み権限を獲得しており、メールボッ
   クスを開きなおして書き込み権限を再獲得する必要があります。

このモジュールではもう一つ、安全 (secure) な接続を使ったサブクラスがあ
ります:

class imaplib.IMAP4_SSL([host[, port[, keyfile[, certfile]]]])

   "IMAP4" から派生したサブクラスで、SSL 暗号化ソケットを介して接続を
   行います (このクラスを利用するためには SSL サポート付きでコンパイル
   された socket モジュールが必要です) 。 *host* が指定されていない場
   合、 "''" (ローカルホスト) が用いられます。 *port* が省略された場合
   、標準の IMAP4-over-SSL ポート番号 (993) が用いられます。 *keyfile*
   および *certfile* もオプションです - これらは SSL 接続のための PEM
   形式の秘密鍵 (private key) と認証チェイン (certificate chain) ファ
   イルです。

さらにもう一つのサブクラスは、子プロセスで確立した接続を使用する場合に
使用します:

class imaplib.IMAP4_stream(command)

   "IMAP4" から派生したサブクラスで、 *command* を "os.popen2()" に渡
   して作成される "stdin/stdout" デスクリプタと接続します。

   バージョン 2.3 で追加.

以下のユーティリティ関数が定義されています:

imaplib.Internaldate2tuple(datestr)

   IMAP4 の "INTERNALDATE" 文字列を解析してそれに相当するローカルタイ
   ムを返します。戻り値は "time.struct_time" のインスタンスか、文字列
   のフォーマットが不正な場合は "None" です。

imaplib.Int2AP(num)

   整数を ["A" .. "P"] からなる文字集合を用いて表現した文字列に変換し
   ます。

imaplib.ParseFlags(flagstr)

   IMAP4 "FLAGS" 応答を個々のフラグからなるタプルに変換します。

imaplib.Time2Internaldate(date_time)

   *date_time* を IMAP4 の "INTERNALDATE" 表現形式に変換します。戻り値
   は ""DD-Mmm-YYYY HH:MM:SS +HHMM"" (ダブルクォートを含む) の形をした
   文字列です。 *date_time* 引数は ("time.time()" が返す) epoch からの
   経過秒数を表す数値 (int か float) か、("time.localtime()" が返す)
   ローカルタイムを表現する 9要素タプルか、ダブルクォートされた文字列
   です。文字列だった場合、それがすでに正しいフォーマットになっている
   と仮定されます。

IMAP4 メッセージ番号は、メールボックスに対する変更が行われた後には変化
します; 特に、"EXPUNGE" 命令はメッセージの削除を行いますが、残ったメッ
セージには再度番号を振りなおします。従って、メッセージ番号ではなく、
UID 命令を使い、その UID を利用するよう強く勧めます。

モジュールの末尾に、より拡張的な使用例が収められたテストセクションがあ
ります。

参考: プロトコルに関する記述、およびプロトコルを実装したサーバのソー
  スとバ イナリは、全てワシントン大学の *IMAP Information Center*
  (https://www.washington.edu/imap/) にあります。


20.10.1. IMAP4 オブジェクト
===========================

全ての IMAP4rev1 命令は、同じ名前のメソッドで表されており、大文字のも
のも小文字のものもあります。

命令に対する引数は全て文字列に変換されます。例外は "AUTHENTICATE" の引
数と "APPEND" の最後の引数で、これは IMAP4 リテラルとして渡されます。
必要に応じて (IMAP4 プロトコルが感知対象としている文字が文字列に入って
おり、かつ丸括弧か二重引用符で囲われていなかった場合) 文字列はクオート
されます。しかし、"LOGIN" 命令の  *password* 引数は常にクオートされま
す。文字列がクオートされないようにしたい (例えば "STORE" 命令の
*flags* 引数) 場合、文字列を丸括弧で囲んでください (例:
"r'(\Deleted)'")。

各命令はタプル: "(type, [data, ...])" を返し、*type* は通常 "'OK'" ま
たは "'NO'" です。*data* は命令に対する応答をテキストにしたものか、命
令に対する実行結果です。各 *data* は文字列かタプルとなります。タプルの
場合、最初の要素はレスポンスのヘッダで、次の要素にはデータが格納されま
す (ie: 'literal' value)。

以下のコマンドにおける *message_set* オプションは、操作の対象となるひ
とつあるいは複数のメッセージを指す文字列です。単一のメッセージ番号
("'1'") かメッセージ番号の範囲 ("'2:4'")、あるいは連続していないメッセ
ージをカンマでつなげたもの ("'1:3,6:9'") となります。範囲指定でアスタ
リスクを使用すると、上限を無限とすることができます ("'3:*'")。

"IMAP4" のインスタンスは以下のメソッドを持っています:

IMAP4.append(mailbox, flags, date_time, message)

   指定された名前のメールボックスに *message* を追加します。

IMAP4.authenticate(mechanism, authobject)

   認証命令です --- 応答の処理が必要です。

   *mechanism* は利用する認証メカニズムを与えます。認証メカニズムはイ
   ンスタンス変数 "capabilities" の中に "AUTH=mechanism" という形式で
   現れる必要があります。

   *authobject* は呼び出し可能なオブジェクトである必要があります:

      data = authobject(response)

   これはサーバで継続応答を処理するためによばれます。これは(おそらく)
   暗号化されて、サーバへ送られた "data" を返します。もしクライアント
   が中断応答 "*" を送信した場合にはこれは "None" を返します。

IMAP4.check()

   サーバ上のメールボックスにチェックポイントを設定します。

IMAP4.close()

   現在選択されているメールボックスを閉じます。削除されたメッセージは
   書き込み可能メールボックスから除去されます。"LOGOUT" 前に実行するこ
   とを勧めます。

IMAP4.copy(message_set, new_mailbox)

   *message_set* で指定したメッセージ群を *new_mailbox* の末尾にコピー
   します。

IMAP4.create(mailbox)

   *mailbox* と名づけられた新たなメールボックスを生成します。

IMAP4.delete(mailbox)

   *mailbox* と名づけられた古いメールボックスを削除します。

IMAP4.deleteacl(mailbox, who)

   mailbox における who についてのACLを削除(権限を削除)します。

   バージョン 2.4 で追加.

IMAP4.expunge()

   選択されたメールボックスから削除された要素を永久に除去します。各々
   の削除されたメッセージに対して、"EXPUNGE" 応答を生成します。返され
   るデータには "EXPUNGE" メッセージ番号を受信した順番に並べたリストが
   入っています。

IMAP4.fetch(message_set, message_parts)

   メッセージ (の一部) を取りよせます。*message_parts* はメッセージパ
   ートの名前を表す文字列を丸括弧で囲ったもので、例えば: ""(UID
   BODY[TEXT])"" のようになります。返されるデータはメッセージパートの
   エンベロープ情報とデータからなるタプルです。

IMAP4.getacl(mailbox)

   *mailbox* に対する "ACL" を取得します。このメソッドは非標準ですが、
   "Cyrus" サーバでサポートされています。

IMAP4.getannotation(mailbox, entry, attribute)

   *mailbox* に対する "ANNOTATION" を取得します。このメソッドは非標準
   ですが、"Cyrus" サーバでサポートされています。

   バージョン 2.5 で追加.

IMAP4.getquota(root)

   "quota" *root* により、リソース使用状況と制限値を取得します。このメ
   ソッドは **RFC 2087** で定義されている IMAP4 QUOTA 拡張の一部です。

   バージョン 2.3 で追加.

IMAP4.getquotaroot(mailbox)

   *mailbox* に対して "quota" *root* を実行した結果のリストを取得しま
   す。このメソッドは **RFC 2087** で定義されている IMAP4 QUOTA 拡張の
   一部です。

   バージョン 2.3 で追加.

IMAP4.list([directory[, pattern]])

   *pattern* にマッチする *directory* メールボックス名を列挙します。
   *directory* の標準の設定値は最上レベルのメールフォルダで、*pattern*
   は標準の設定では全てにマッチします。返されるデータには "LIST" 応答
   のリストが入っています。

IMAP4.login(user, password)

   平文パスワードを使ってクライアントを照合します。*password* はクオー
   トされます。

IMAP4.login_cram_md5(user, password)

   パスワードの保護のため、クライアント認証時に "CRAM-MD5" だけを使用
   します。これは、"CAPABILITY" レスポンスに "AUTH=CRAM-MD5" が含まれ
   る場合のみ有効です。

   バージョン 2.3 で追加.

IMAP4.logout()

   サーバへの接続を遮断します。サーバからの "BYE" 応答を返します。

IMAP4.lsub([directory[, pattern]])

   購読しているメールボックス名のうち、ディレクトリ内でパターンにマッ
   チするものを列挙します。*directory* の標準の設定値は最上レベルのメ
   ールフォルダで、*pattern* は標準の設定では全てにマッチします。返さ
   れるデータには返されるデータはメッセージパートエンベロープ情報とデ
   ータからなるタプルです。

IMAP4.myrights(mailbox)

   mailboxにおける自分のACLを返します (すなわち自分がmailboxで持ってい
   る権限を返します)。

   バージョン 2.4 で追加.

IMAP4.namespace()

   RFC2342で定義されるIMAP名前空間を返します。

   バージョン 2.3 で追加.

IMAP4.noop()

   サーバに "NOOP" を送信します。

IMAP4.open(host, port)

   *host* 上の *port* に対するソケットを開きます。このメソッドは
   "IMAP4" のコンストラクタから暗黙的に呼び出されます。このメソッドで
   確立された接続オブジェクトは "IMAP4.read()", "IMAP4.readline()",
   "IMAP4.send()", "IMAP4.shutdown()"  メソッドで使われます。このメソ
   ッドはオーバライドすることができます。

IMAP4.partial(message_num, message_part, start, length)

   メッセージの後略された部分を取り寄せます。返されるデータはメッセー
   ジパートエンベロープ情報とデータからなるタプルです。

IMAP4.proxyauth(user)

   *user* として認証されたものとします。認証された管理者がユーザの代理
   としてメールボックスにアクセスする際に使用します。

   バージョン 2.3 で追加.

IMAP4.read(size)

   遠隔のサーバから *size* バイト読み出します。このメソッドはオーバラ
   イドすることができます。

IMAP4.readline()

   遠隔のサーバから一行読み出します。このメソッドはオーバライドするこ
   とができます。

IMAP4.recent()

   サーバに更新を促します。新たなメッセージがない場合応答は "None" に
   なり、そうでない場合 "RECENT" 応答の値になります。

IMAP4.rename(oldmailbox, newmailbox)

   *oldmailbox* という名前のメールボックスを *newmailbox* に名称変更し
   ます。

IMAP4.response(code)

   応答 *code* を受信していれば、そのデータを返し、そうでなければ
   "None" を返します。通常の形式 (usual type) ではなく指定したコードを
   返します。

IMAP4.search(charset, criterion[, ...])

   条件に合致するメッセージをメールボックスから検索します。*charset*
   は "None" でもよく、この場合にはサーバへの要求内に "CHARSET" は指定
   されません。IMAP プロトコルは少なくとも一つの条件 (criterion) が指
   定されるよう要求しています; サーバがエラーを返した場合、例外が送出
   されます。

   例:

      # M is a connected IMAP4 instance...
      typ, msgnums = M.search(None, 'FROM', '"LDJ"')

      # or:
      typ, msgnums = M.search(None, '(FROM "LDJ")')

IMAP4.select([mailbox[, readonly]])

   メールボックスを選択します。返されるデータは *mailbox* 内のメッセー
   ジ数 ("EXISTS" 応答) です。標準の設定では *mailbox* は "'INBOX'" で
   す。*readonly* が設定された場合、メールボックスに対する変更はできま
   せん。

IMAP4.send(data)

   遠隔のサーバに "data" を送信します。このメソッドはオーバライドする
   ことができます。

IMAP4.setacl(mailbox, who, what)

   "ACL" を *mailbox* に設定します。このメソッドは非標準ですが、
   "Cyrus" サーバでサポートされています。

IMAP4.setannotation(mailbox, entry, attribute[, ...])

   "ANNOTATION" を *mailbox* に設定します。このメソッドは非標準ですが
   、"Cyrus" サーバでサポートされています。

   バージョン 2.5 で追加.

IMAP4.setquota(root, limits)

   "quota" *root* のリソースを *limits* に設定します。このメソッドは
   **RFC 2087** で定義されている IMAP4 QUOTA 拡張の一部です。

   バージョン 2.3 で追加.

IMAP4.shutdown()

   "open" で確立された接続を閉じます。 "IMAP4.logout()" は暗黙的にこの
   メソッドを呼び出します。このメソッドはオーバライドすることができま
   す。

IMAP4.socket()

   サーバへの接続に使われているソケットインスタンスを返します。

IMAP4.sort(sort_criteria, charset, search_criterion[, ...])

   "sort" 命令は "search" に結果の並べ替え (sort) 機能をつけた変種です
   。返されるデータには、条件に合致するメッセージ番号をスペースで分割
   したリストが入っています。

   sort 命令は *search_criterion* の前に二つの引数を持ちます;
   *sort_criteria* のリストを丸括弧で囲ったものと、検索時の *charset*
   です。"search" と違って、検索時の *charset* は必須です。"uid sort"
   命令もあり、"search" に対する "uid search" と同じように "sort" 命令
   に対応します。"sort" 命令はまず、charset 引数の指定に従って
   searching criteria の文字列を解釈し、メールボックスから与えられた検
   索条件に合致するメッセージを探します。次に、合致したメッセージの数
   を返します。

   "IMAP4rev1" 拡張命令です。

IMAP4.status(mailbox, names)

   *mailbox* の指定ステータス名の状態情報を要求します。

IMAP4.store(message_set, command, flag_list)

   メールボックス内のメッセージ群のフラグ設定を変更します。 *command*
   は **RFC 2060** のセクション 6.4.6 で指定されているもので、
   "FLAGS", "+FLAGS", あるいは "-FLAGS" のいずれかとなります。オプショ
   ンで末尾に ".SILENT" がつくこともあります。

   たとえば、すべてのメッセージに削除フラグを設定するには次のようにし
   ます:

      typ, data = M.search(None, 'ALL')
      for num in data[0].split():
         M.store(num, '+FLAGS', '\\Deleted')
      M.expunge()

IMAP4.subscribe(mailbox)

   新たなメールボックスを購読 (subscribe) します。

IMAP4.thread(threading_algorithm, charset, search_criterion[, ...])

   "thread" コマンドは "search" にスレッドの概念を加えた変形版です。返
   されるデータは空白で区切られたスレッドメンバのリストを含んでいます
   。

   各スレッドメンバは0以上のメッセージ番号からなり、空白で区切られてお
   り、親子関係を示しています。

   "thread" コマンドは *search_criterion* 引数の前に2つの引数を持って
   います。*threading_algorithm* と *charset* です。"search" コマンド
   とは違い、*charset* は必須です。"search" に対する "uid search" と同
   様に、"thread" にも "uid thread" があります。"thread" コマンドはま
   ずメールボックス中のメッセージを、charsetを用いた検索条件で検索しま
   す。その後マッチしたメッセージを指定されたスレッドアルゴリズムでス
   レッド化して返します.

   "IMAP4rev1" 拡張命令です。

   バージョン 2.4 で追加.

IMAP4.uid(command, arg[, ...])

   command args を、メッセージ番号ではなく UID で指定されたメッセージ
   群に対して実行します。命令内容に応じた応答を返します。少なくとも一
   つの引数を与えなくてはなりません; 何も与えない場合、サーバはエラー
   を返し、例外が送出されます。

IMAP4.unsubscribe(mailbox)

   古いメールボックスの購読を解除 (unsubscribe) します。

IMAP4.xatom(name[, arg[, ...]])

   サーバから "CAPABILITY" 応答で通知された単純な拡張命令を許容
   (allow) します。

"IMAP4_SSL" のインスタンスは追加のメソッドを一つだけ持ちます:

IMAP4_SSL.ssl()

   サーバへの安全な接続に使われる SSLObject インスタンスを返します。

以下の属性が "IMAP4" のインスタンス上で定義されています:

IMAP4.PROTOCOL_VERSION

   サーバから返された "CAPABILITY" 応答にある、サポートされている最新
   のプロトコルです。

IMAP4.debug

   デバッグ出力を制御するための整数値です。初期値はモジュール変数
   "Debug" から取られます。3 以上の値にすると各命令をトレースします。


20.10.2. IMAP4 の使用例
=======================

以下にメールボックスを開き、全てのメッセージを取得して印刷する最小の (
エラーチェックをしない) 使用例を示します:

   import getpass, imaplib

   M = imaplib.IMAP4()
   M.login(getpass.getuser(), getpass.getpass())
   M.select()
   typ, data = M.search(None, 'ALL')
   for num in data[0].split():
       typ, data = M.fetch(num, '(RFC822)')
       print 'Message %s\n%s\n' % (num, data[0][1])
   M.close()
   M.logout()
