要約

  • RFC 2180 では、使用中のメールボックスに対する削除を拒否する、既存セッション向けに残す、他の接続を切る、といった複数の挙動が許容された。
  • tagged OK は一つの戦略で一つのコマンドが完了した証拠であり、名前空間、アクセス、メッセージ番号、保存データが同時に収束した証拠ではない。

三つの接続が見た三つの事実

FOO を選択済みのクライアントが二つある。片方が DELETE FOO を送り OK を受け取る。後から来た三つ目のクライアントには FOO が見えず、同じ名前の再作成も拒否される。それでも二つ目のクライアントは、選択済みの内容へ FETCH や STORE を続けられる。

RFC 2180 は、この「ゴースト化」を合理的な戦略として記録した。参照数がゼロになるまで内容を残し、その後に恒久削除して名前を再利用可能にする。別のサーバーは使用中の削除自体を拒否してよいし、削除を受け入れたうえで他のセッションへ BYE を送り切断してもよい。

拒否は継続性を守るが、共有メールボックスを削除不能にし得る。ゴースト化は作業を守るが、機密情報へのアクセスを遅れて残す。切断は削除を強く実行するが、進行中の処理を失わせる。実装の自由とは、費用が消えることではなく、どの費用を選ぶかということだった。

RENAME でも層が分かれる。名前属性だけを変えれば、選択済みセッションは古い名前を使わない FETCH を続けられる。一方、APPEND FOO は失敗し、NEWNAME の手掛かりが返ることがある。名前の世界と、接続が保持する選択状態の世界は同一ではない。

EXPUNGE の通知は、変化より後にしか届かないことがある

RFC 2060 のメッセージシーケンス番号は、選択中メールボックス内の現在位置である。途中のメッセージが expunge されれば後続番号が詰まる。しかし FETCH、STORE、SEARCH の応答中には EXPUNGE を送れない。状態はすでに変わったのに、クライアントはまだ古い番号表でコマンドを完了させなければならない。

RFC 2180 が列挙した応答は一つではない。消えたメッセージを一時保存して FETCH に応じる。残っている分だけ返して tagged NO で終える。残存分には通常値、消失分には NIL 形の値を返し tagged OK で終える。あるいは同時アクセス中の expunge を拒否する。

NIL は「値が空」と「対象が消えた」を同じ形にできる。区別が必要なクライアントは NOOP を送り、保留された EXPUNGE を受け取り、番号表を更新してから再試行を判断する。構文を読めるだけでは相互運用にならない。曖昧さを解消する状態機械が必要だった。

.SILENT 付き STORE の OK も範囲が狭い。まだ存在するすべてのメッセージに変更できたなら、要求範囲の一部がすでに expunge 済みでも成功を返し得る。成功は元の集合の存続証明ではない。

COPY が固定したのは開始時の参照だけ

COPY は開始時のシーケンス番号で対象を特定する。処理中に番号が変わっても、成功したなら開始時に特定したメッセージが宛先へ入っていなければならない。失敗なら宛先を以前の状態へ戻す。

これはメールボックス全体のスナップショットではない。一つのコマンドについて「何を指したか」を固定しただけで、次のコマンドや他の接続まで凍結しない。

1997年の実践記録として読む

RFC Editor の情報ページは RFC 2180 を Informational と位置づける。適合性の定義でも有効挙動の完全一覧でもなく、基準は RFC 2060 にある。したがって、現在の特定サービスがゴースト化を採用している、普及率が高い、ある製品が安全である、といった主張はこの資料から導けない。

歴史的意義は別にある。特定サーバーの癖に合わせたクライアントでは足りず、プロトコルが許す挙動全体を相手にしなければならない、と責任を明記した点である。

RFC 2177 の IDLE は更新を早く受け取る道を作り、RFC 7162 の CONDSTORE/QRESYNC は mod-sequence と VANISHED で再同期を効率化した。だが通知の改善は、OK を全接続の瞬時一致証明には変えない。

コマンド完了、名前の消失、既存セッションの失権、保存バイトの破棄は別々の事実である。RFC 2180 は、その境界を曖昧なまま運用するのではなく、クライアントが耐えられる形で明示した。