21.15. "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_PORT)

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

   The "IMAP4" class supports the "with" statement.  When used like
   this, the IMAP4 "LOGOUT" command is issued automatically when the
   "with" statement exits.  E.g.:

      >>> from imaplib import IMAP4
      >>> with IMAP4("domain.org") as M:
      ...     M.noop()
      ...
      ('OK', [b'Nothing Accomplished. d25if65hy903weo.87'])

   バージョン 3.5 で変更: "with" 構文のサポートが追加されました。

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

exception IMAP4.error

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

exception IMAP4.abort

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

exception IMAP4.readonly

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

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

class imaplib.IMAP4_SSL(host='', port=IMAP4_SSL_PORT, keyfile=None, certfile=None, ssl_context=None)

   This is a subclass derived from "IMAP4" that connects over an SSL
   encrypted socket (to use this class you need a socket module that
   was compiled with SSL support).  If *host* is not specified, "''"
   (the local host) is used. If *port* is omitted, the standard IMAP4
   -over-SSL port (993) is used. *ssl_context* is a "ssl.SSLContext"
   object which allows bundling SSL configuration options,
   certificates and private keys into a single (potentially long-
   lived) structure.  Please read セキュリティで考慮すべき点 for best
   practices.

   *keyfile* and *certfile* are a legacy alternative to *ssl_context*
   - they can point to PEM-formatted private key and certificate chain
   files for the SSL connection.  Note that the *keyfile*/*certfile*
   parameters are mutually exclusive with *ssl_context*, a
   "ValueError" is raised if *keyfile*/*certfile* is provided along
   with *ssl_context*.

   バージョン 3.3 で変更: *ssl_context* parameter added.

   バージョン 3.4 で変更: このクラスは "ssl.SSLContext.check_hostname"
   と *Server Name Indication* でホスト名のチェックをサポートしました
   。("ssl.HAS_SNI" を参照してください)。

   バージョン 3.6 で非推奨: *keyfile* and *certfile* are deprecated in
   favor of *ssl_context*. Please use
   "ssl.SSLContext.load_cert_chain()" instead, or let
   "ssl.create_default_context()" select the system's trusted CA
   certificates for you.

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

class imaplib.IMAP4_stream(command)

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

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

imaplib.Internaldate2tuple(datestr)

   Parse an IMAP4 "INTERNALDATE" string and return corresponding local
   time.  The return value is a "time.struct_time" tuple or "None" if
   the string has wrong format.

imaplib.Int2AP(num)

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

imaplib.ParseFlags(flagstr)

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

imaplib.Time2Internaldate(date_time)

   Convert *date_time* to an IMAP4 "INTERNALDATE" representation. The
   return value is a string in the form: ""DD-Mmm-YYYY HH:MM:SS
   +HHMM"" (including double-quotes).  The *date_time* argument can be
   a number (int or float) representing seconds since epoch (as
   returned by "time.time()"), a 9-tuple representing local time an
   instance of "time.struct_time" (as returned by "time.localtime()"),
   an aware instance of "datetime.datetime", or a double-quoted
   string.  In the last case, it is assumed to already be in the
   correct format.

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

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

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


21.15.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)

   It will be called to process server continuation responses; the
   *response* argument it is passed will be "bytes".  It should return
   "bytes" *data* that will be base64 encoded and sent to the server.
   It should return "None" if the client abort response "*" should be
   sent instead.

   バージョン 3.5 で変更: string usernames and passwords are now
   encoded to "utf-8" instead of being limited to ASCII.

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を削除(権限を削除)します。

IMAP4.enable(capability)

   Enable *capability* (see **RFC 5161**).  Most capabilities do not
   need to be enabled.  Currently only the "UTF8=ACCEPT" capability is
   supported (see **RFC 6855**).

   バージョン 3.5 で追加: The "enable()" method itself, and **RFC
   6855** support.

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" サーバでサポートされています。

IMAP4.getquota(root)

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

IMAP4.getquotaroot(mailbox)

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

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" が含まれ
   る場合のみ有効です。

IMAP4.logout()

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

IMAP4.lsub(directory='""', pattern='*')

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

IMAP4.myrights(mailbox)

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

IMAP4.namespace()

   Returns IMAP namespaces as defined in **RFC 2342**.

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* として認証されたものとします。認証された管理者がユーザの代理
   としてメールボックスにアクセスする際に使用します。

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[, ...])

   Search mailbox for matching messages.  *charset* may be "None", in
   which case no "CHARSET" will be specified in the request to the
   server.  The IMAP protocol requires that at least one criterion be
   specified; an exception will be raised when the server returns an
   error.  *charset* must be "None" if the "UTF8=ACCEPT" capability
   was enabled using the "enable()" command.

   以下はプログラム例です:

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

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

IMAP4.select(mailbox='INBOX', readonly=False)

   メールボックスを選択します。返されるデータは *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" サーバでサポートされています。

IMAP4.setquota(root, limits)

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

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.starttls(ssl_context=None)

   Send a "STARTTLS" command.  The *ssl_context* argument is optional
   and should be a "ssl.SSLContext" object.  This will enable
   encryption on the IMAP connection.  Please read セキュリティで考慮
   すべき点 for best practices.

   バージョン 3.2 で追加.

   バージョン 3.4 で変更: このメソッドは
   "ssl.SSLContext.check_hostname" と *Server Name Indication* でホス
   ト名のチェックをサポートしました。("ssl.HAS_SNI" を参照してください
   )。

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()

   注釈: Creating flags containing ']' (for example: "[test]")
     violates **RFC 3501** (the IMAP protocol).  However, imaplib has
     historically allowed creation of such tags, and popular IMAP
     servers, such as Gmail, accept and produce such flags.  There are
     non-Python programs which also create such tags.  Although it is
     an RFC violation and IMAP clients and servers are supposed to be
     strict, imaplib nonetheless continues to allow such tags to be
     created for backward compatibility reasons, and as of python 3.6,
     handles them if they are sent from the server, since this
     improves real-world compatibility.

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" 拡張命令です。

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

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

IMAP4.unsubscribe(mailbox)

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

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

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

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

IMAP4.PROTOCOL_VERSION

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

IMAP4.debug

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

IMAP4.utf8_enabled

   Boolean value that is normally "False", but is set to "True" if an
   "enable()" command is successfully issued for the "UTF8=ACCEPT"
   capability.

   バージョン 3.5 で追加.


21.15.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()
