POPとIMAP

ようやく IMAP も普及したようで、POP から IMAP に乗り換える人が増えています。僕の周りのインターネット技術者も、ぼちぼち乗り換え始めました。(gmail が IMAP をサポートしたことが大きな要因でしょうか?)

彼らは優秀なのにも関わらず、こんな間違った表現を使います。

  • POP はメールをメールリーダに取ってくるもので、IMAP はサーバ側のメールを読むものだ
  • POP だとよかったけど、IMAP は常にネットワークにつながっていないと辛い
  • POP だとよかったけど、IMAP はフォルダ内のメールの数が多くなると辛い

その度に、「そうじゃない」と言ってきたのですが、もうそう説明するのにも疲れてきました。そこで、正しいことを書いて、この説明はもう二度としないことにしようと思います。(DRY: Don't Repeat Yourself ですね。)

間違いの根源は、おそらく二つです。

「プロトコル」と、その「使い方」を同一視している
明らかなことですが、両者は異なります
「プロトコル」と「実装」方法を同一視している
間違いやすいことですが、両者は異なります

POP と IMAP の違い

まず第一に、もし、「POP と IMAP は全然違うプロトコルだ」と誤解しているのでしたら、その思い込みを直して下さい。

POP と IMAP は、似たようなプロトコルです。両者の本質的な違いは、サーバ側において、POP のメールボックスが 1 つであるのに対し、IMAP のそれは複数であることです。

つまり、IMAP は POP のスーパーセットであり、POP にできることは、IMAP にもできるのです。ここさえ分っていれば、POP から IMAP に変えても、使い心地が悪くなるはずはないのは明らかです。

もし、使い心地が悪くなったとしたら、それはプロトコルの問題ではなく、実装の問題です。つまり、IMAP が悪いのではなく、あなたのメールリーダの実装がヘボいのです。

使い方

「POP は、メールをメールリーダ側に取ってくるものだ」と思っているのでしたら、失礼ですが、あなたは POP に関して old type です。:) 最近の POP ユーザの多くは、POP サーバからメールを取っても、サーバ側のメールは削除しません。

もちろん、ISP/ASP としては、サーバにメールを残されるとディスクが圧迫されるので、削除してほしいと願っていますよ。でも、そんな他人の願いには無頓着ですから、多くのユーザがメールを残します。一日に数通しかメールを受け取らないユーザであれば、なんの問題も起きません。

一方、IMAP でも、メールを取得した後にサーバから消すという、old type な POP 風の使い方もできます。もちろん、それだと「複数のメールボックス」という特徴は活かせませんけどね。

POPの通信例

POP でメールを取得するには、こんな言葉を喋ります。

% telnet pop.example.com 110
S: +OK POP server ready.
C: USER bob
S: +OK Password required.
C: PASS password
S: +OK bob has 3 message(s) (3557 bytes).
C: LIST # メール一覧
S: 1 3823 # 番号 サイズ
S: 2 2765
S: 3 3010
S: .
C: RETR 1 # メール 1 を取得
S: Subject: test
S: From: [email protected]
S: To: bob@example.com
S:
S: this is a body.
S:
S: --Alice
S: .
C: DELE 1 # メール 1 に削除マークを付ける
S: +OK Message 1 has been deleted.
C: QUIT # 通信終わり。メールが削除される
S: +OK POP server at pop.example.com signing off.

メールのリストを取り、好きなメールをローカルにコピーして、不要ならメールを削除します。UNIX 風に言うなら、ls して、scp して、rm するのです。

最後に削除しなければ、メールはサーバ側に残されます。取得済みのメールをサーバ側に残したとしても、新着メールを判断する方法が提供されています。今日のテーマとは関係がないので、その方法は説明しません。

IMAPの通信例

IMAP でメールを取得するには、こんな言葉を喋ります。

% telnet imap.example.com 143
S: * OK
C: tag1 LOGIN "bob" "password"
S: tag1 OK Logged in.
C: tag2 SELECT "inbox" # inbox を選択
S: * 3 EXISTS # メールが 3 つある
S: tag2 OK Select completed.
C: tag3 FETCH 1 RFC822 # メール 1 を取得
S: * 1 FETCH (RFC822 {3823}
S: Subject: test
S: From: [email protected]
S: To: bob@example.com
S:
S: this is a body.
S:
S: --Alice
S:
S: )
S: tag3 OK Fetch completed.
C: tag4 STORE 1 +FLAGS (\Deleted) # メール 1 に削除マークを付ける
S: tag4 OK Store completed.
C: tag5 EXPUNGE # メールを削除
S: tag5 OK Expunge completed.
C: tag6 LOGOUT # 通信終わり
S: tag6 OK Logout completed.

メールのリストを取り、好きなメールをローカルにコピーして、不要ならメールを削除します。単語は違いますが、内容は POP と同じでしょう?

利用方法の分類

つまり、こういうことです。

  • old type の POP ユーザは、サーバからメールを削除する
  • new type の POP ユーザは、サーバにメールを残す
  • IMAP ユーザは、サーバにメールを残す。おそらくは、IMAP の特性を活かすために、別のメールボックスに移動させる

IMAP のヘボい実装(1)

IMAP の典型的なヘボい実装は、こんな感じです。

  • あるメールボックスにあるメールのヘッダ情報だけを取得し、一覧表示する
  • ユーザが、あるメールを読もうとすると、サーバにつないで、そのメールを取得し表示する

これって、いわゆる AJAX 以前の web アプリみたいですね。ユーザが命令がないと、何もしないのです。

この実装だと、こんな問題が発生します。

  • メールを表示するまでに時間がかかる
  • 一覧を取った後にインターネットのない環境に行く。そこでメールを読もうとすると読めない

というわけで、まともな実装ではこんなことをします。

  • 非同期にメールをキャッシュする

気取った表現を使ってみましたが、非同期でローカルにメールを取ってくる(FETCH)だけのことです。

IMAP のヘボい実装(2)

メールボックスの形式について考えてみましょう。これは、サーバ側にもメールリーダ側にも当てはまる話です。

メールボックスが 1 ファイル、つまり、あるメールボックスのすべてのメールが 1 つのファイルに納められている形式は、10年前に破綻していました。(mbox 形式のことですよ。)

そこで多くの実装では、メールボックスをディレクトリとし、メールを1つのファイルに格納します。(MH 形式や Maildir 形式です。)

この形式だと、あるメールボックス内のメールの数が多くなると、とたんに遅くなります。(環境にもよりますが、一説には3万通ぐらいが閾値だとのことです。)

これも、IMAP が悪いのではなく、実装がヘボいのです。

たとえば、IMAP 上で 6 や 43218 で特定されるメールを、そのまま 6 や 43218 というファイルに保存する必要はありません。スケールさせるなら、たとえば 1000 ぐらいを目安にして、0/6 や 43/218 というサブディテクトリを活用した形にすればいいのです。

お願い

「IMAP はヘボい」というのではなく「○○○というメールリーダの IMAP の実装はヘボい」という誤解を生まない表現を使って下さい。(_ _)