IMAPプロトコルの流れを学ぶモバイル環境に優しいメールプロトコルIMAP(4)

» 2002年04月10日 00時00分 公開
[日比野洋克オレンジソフト]

 前回は、Cyrus IMAPを使った実際のIMAPサーバの構築について解説しました。今回は、再びクライアント側の話に戻り、実際のプロトコルのやり取りについて解説していきます。

 IMAP4では、受信したメッセージはIMAP4サーバに保存されます。メーラは接続時にIMAP4サーバから各種情報(フォルダ一覧、メッセージのヘッダ情報、メッセージのボディなど)を取得しますが、毎回これらの情報すべてを取得していては、通信時間=待ち時間が長くなり、使い勝手が悪くなってしまいます。そこで、メーラはローカルのハードディスクに前回の情報をキャッシュしておき、前回の通信から変更のあった部分=差分だけを取得することで通信量を削減します。また、オフライン時に行った削除/移動/コピーなどの処理をサーバ側に反映させる処理も行います。この差分情報の取得とオフライン処理の反映をまとめて同期処理と呼びます。IMAP4プロトコルは多様なコマンド/オプションを持っているので、同期処理の実装はメーラによってさまざまな実現方法が試されています。同期処理をいかにうまく行うかが、プログラマーの腕の見せどころになるわけです。

メーラとサーバ間のIMAPプロトコルの流れ

 それでは、実際に、メーラではどのようにIMAPサーバと通信しているのかをのぞいてみましょう。IMAP4をサポートしたメーラはいくつかありますが、今回は次の4つを取り上げることにします(いずれもWindows用のメーラです)。

メーラ 開発元 最新版(4/5現在)
Becky! Internet Mail V2 リムアーツ 2.00.11
Datula オンシステムズ 1.51.09
Outlook Express V6 ※1 マイクロソフト 6.00.2600.0000
Winbiff V2 オレンジソフト 2.34PL1
※1 Outlook Express V6はInternet Explorer 6に含まれている

 これらのメーラでは、メールサーバとのログを記録することができます。操作方法はそれぞれ以下のとおりです。

Becky! 「ツール」→「プロトコルログを取る」
Datula 「表示」→「Protocol Log...」
Outlook Express 「オプション」→「メンテナンス」→トラブルシューティングの「IMAP」
Winbiff 「ファイル」→「イベントビュアを表示」

 Outlook Express以外は画面で確認することができますが、Outlook Expressだけは「imap4.log」という名前でログファイルが生成されますので、通信終了後にテキストエディタなどを用いてログファイルを参照してください(ログファイルの格納先フォルダは環境によって変わりますので、エクスプローラの検索機能で探してください)。

 なお、以下に示すログでは、分かりやすくするために、レスポンスの多くは省略しています。また、この結果は、あくまでも検証に用いたIMAPサーバにおいての結果であり、別のIMAPサーバでは動作が異なる可能性があることをご了承ください。

IMAPサーバとの接続

Becky! 0009 CAPABILITY
0010 LOGIN ******** ********
0011 NAMESPACE
0011 OK Completed
Datula a001 CAPABILITY
a002 AUTHENTICATE LOGIN
a003 STATUS "INBOX" (RECENT UNSEEN MESSAGES)
a004 NAMESPACE
Outlook Express CAPABILITY
LOGIN command sent
Winbiff A1 CAPABILITY
A2 LOGIN ********
A3 NAMESPACE

 IMAPサーバとの接続は、CAPABILITYコマンドによりサーバの機能確認を行った後、ログインする、というのが基本の動作となります。メーラ間の違いはそれほどなく、2点だけです。

  • Datulaでは、CAPABILITYの“AUTH=LOGIN”を解釈して、サーバへのログインにAUTHENTICATEコマンドを用いています。ほかのクライアントはLOGINコマンドを用いています※2
  • Outlook Express以外の3つのメーラは、NAMESPACE拡張を認識し、NAMESPACEコマンドを発行しています。
※2 検証に用いたIMAPサーバはCRAM-MD5をサポートしていないので、ログでは確認できませんでしたが、Outlook Express以外のメーラはCRAM-MD5をサポートしているそうです。

メールボックス一覧の取得

Becky! 0006 LIST "" *
Datula a019 LIST "" ""
a020 LSUB "" "%"
a021 LSUB "Shared Folders/User/" "%"
a022 LIST "" "%"
a023 LIST "Shared Folders/User/" "%"
Outlook Express 0002 LIST "" "*"
0003 LSUB "" "*"
0004 LIST "" "INBOX*"
0005 LSUB "" "INBOX*"
Winbiff A20 LIST "" "*"
A24 LIST "" "Shared Folders/User/*"

 IMAP4では、おのおののメールボックスに購読(subscribe)/未購読(unsubscribe)設定を行うことができます。LSUBコマンドは、購読メールボックスの一覧を取得するコマンドです。DatulaとOutlook Expressは、このLSUBコマンドを用いて、購読メールボックスの一覧を取得し、表示するようにしています。

 Datulaは、メールボックス一覧表示でツリーをオープンしたときに、その直下の階層のメールボックス一覧を取得しています。取得するメールボックス数を減らすことができるので、通信時間の短縮に効果があると考えられます。

 DatulaとWinbiffは、NAMESPACEによる名前空間を認識していて、共有メールボックス一覧を取得しています。

 メールボックス一覧の取得については、Datulaが一番多くの工夫がなされていると思います。DatulaがNNTP(News)クライアントでもあるのも一因でしょう。

メールボックスの選択〜メール一覧の取得

Becky! 0010 SELECT "INBOX"
0011 UID SEARCH ALL 1.
0012 UID SEARCH UNSEEN
0013 UID SEARCH ANSWERED
0014 UID SEARCH DELETED
0015 FETCH 5069:5099 (UID FLAGS RFC822.SIZE RFC822.HEADER)
Datula a003 SELECT "@IT"
a004 FETCH 1:59 (FLAGS UID) 2.
a005 FETCH 1:59 (RFC822.SIZE BODY.PEEK[HEADER.FIELDS.NOT (Received)])
Outlook Express SELECT "INBOX"
0003 UID FETCH 213555:* (BODY.PEEK[HEADER.FIELDS (References X-Ref X-Priority X-MSMail-Priority X-MSOESRec Newsgroups)] ENVELOPE RFC822.SIZE UID FLAGS INTERNALDATE)
0004 UID FETCH 1:213554 (UID FLAGS)
Winbiff A558 SELECT "inbox"
A559 UID SEARCH UNDELETED
A560 UID SEARCH FLAGGED UNDELETED
A561 UID SEARCH UNSEEN UNDELETED
A562 UID SEARCH RECENT UNDELETED
A563 UID SEARCH ANSWERED UNDELETED
A564 UID FETCH 213819:213822 (UID INTERNALDATE RFC822.SIZE BODY.
PEEK[HEADER.FIELDS.NOT ("Received")])

●メール一覧の取得

 メールの一覧を取得するときには、キャッシュにないメールを探す必要があります。この方法には、大きく分けて2種類あります。1つは、Becky!とWinbiffで使われているSEARCHコマンドを用いた方式(1)。もう1つは、DatulaとOutlook Expressで使われているFETCHコマンドによる方式(2)です。

  • 方式(1)

 Becky!のログで流れを見てみましょう。1.により、メールボックスに含まれるすべてのメールのUIDを検索(取得)しています。UIDとは各メールに割り振られたユニークな番号です。このUIDをキーにして、キャッシュに含まれていないメールを検出することができます。この例では、UID=5069〜5099のヘッダ情報をタグ0015のFETCHコマンドで取得しています。0012から0014までのSEARCHコマンドは、各メールのフラグを取得しています。フラグには未読(UNSEEN)/返信済み(ANSWERED)/削除(DELETED)などがあります。IMAP4では、サーバにメールがあるので、ほかのクライアントによりフラグが書き換えられていることもあります。その同期を取るためにフラグを取得し、キャッシュに反映させるわけです。

  • 方式(2)

 UIDとフラグを取得してキャッシュと同期を取るという方法論自体は、方式(1)と変わりありません。しかし、UIDとFLAGを取得するのにFETCHコマンドを用いているのが、違う部分です。Datulaのログでは、2.がそれに当たります。Outlook Expressでは、この方式に少し工夫を加えていますが、基本的には同一の方式です。

 方式(1)の、SEARCHコマンドを用いる利点は、レスポンスのデータ量が少ないことにあります。SEARCHコマンドのレスポンスは、

A01 UID SEARCH 1:9 ALL
* SEARCH 92285 92286 92287 92295 92296 92297 92298 92301 92302
A01 OK Completed

のように1つのタグなしレスポンスにUIDが羅列されますが、FETCHコマンドでは、

A02 FETCH 1:9 UID
* 1 FETCH (UID 92285)
* 2 FETCH (UID 92286)
* 3 FETCH (UID 92287)
* 4 FETCH (UID 92295)
* 5 FETCH (UID 92296)
* 6 FETCH (UID 92297)
* 7 FETCH (UID 92298)
* 8 FETCH (UID 92301)
* 9 FETCH (UID 92302)
A02 OK Completed

のように複数のタグなしレスポンスとなり、データ量として倍以上の差が出てしまいます。

●ヘッダの取得

 各メーラで、必要とするヘッダを取得しています。独特なのがOutlook Expressで、X-Ref、X-Priority、X-MSMail-Priority、X-MSOESRecといった独自のヘッダも取得しています。

メール本文(添付ファイル付き)の取得

Becky! 0018 UID FETCH 5070 (BODY) 3.
0019 UID FETCH 5070 (RFC822.HEADER) 4.
0020 UID FETCH 5070 (BODY[1]) 5.
Datula a007 FETCH 5070 RFC822
Outlook Express 0006 UID FETCH 5070 (BODY.PEEK[] UID)
Winbiff A1078 UID FETCH 5070 (BODYSTRUCTURE)
A1079 UID FETCH 5070 (BODY.PEEK[HEADER])
A1080 UID FETCH 5070 (BODY.PEEK[1.1])
A1081 UID FETCH 5070 (BODY.PEEK[1.2])

 IMAP4には、メールのMIME構造を解析して、特定のパートだけを取得する機能があります。メール全体ではなく、添付ファイルを除いたテキストの部分だけを取得するようなことができ、通信量を削減することができます。Becky!とWinbiffでは、MIME構造の解析を用いています。Becky!を例に取ると、3.により、メッセージの構造を取得しています。次の4.5.では、それぞれヘッダと第1パートのデータを取得しています。


 今回はPC用のメーラを例に挙げて、プロトコルの実際の流れを見てきました。これを機会にIMAP4に対応したメーラがもっと増えてくることを期待しています。特に、PalmやPocket PCなどのPDAは、ローカルのストレージが少ないこともあり、IMAP4が実現するリモートメール環境を活用するには最適の素材だと思います。すでにいくつか実装が出ていますが、これから楽しみな環境ではないでしょうか。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。