RFC 3030 – SMTP BINARYMIME およびチャンキング
このRFCが存在する理由
従来のSMTPはDATAコマンドを使用してメッセージコンテンツを転送します。メッセージ本文はテキストのストリームとして送信され、ピリオドのみを含む行(.\r\n)で終了します。この設計には2つの問題があります:
- ドット詰め込みのオーバーヘッド:ピリオドで始まるメッセージ内の任意の行は、追加のピリオドを追加してエスケープする必要があります。サーバーはすべての行をスキャンしてエスケープを削除する必要があります。これは処理のオーバーヘッドを追加し、バグを引き起こす可能性があります。
-
バイナリサポートなし:
DATAコマンドは、CRLF行末を持つ7ビットASCIIテキストを想定しています。バイナリコンテンツ(添付ファイルなど)はBase64でエンコードする必要があり、データサイズが約33%増加します。
RFC 3030は、これらの問題を解決する2つの関連する拡張機能を定義しています。CHUNKINGはBDATコマンドを導入し、明示的なサイズのチャンクでデータを転送します。ドット詰め込みは必要ありません。BINARYMIMEはCHUNKINGを基に構築され、エンコードなしで生のバイナリコンテンツを許可します。
動作原理
CHUNKING(BDATコマンド)
- サーバーはEHLO応答で
CHUNKINGをアドバタイズします。 DATAの代わりに、クライアントはBDAT <size>を使用して、正確に<size>オクテットのチャンクを送信します。- サーバーはその正確なバイト数を読み取り、応答を送信します。
- クライアントは複数の
BDATチャンクを送信できます。最後のチャンクにはLASTキーワードが含まれます:BDAT <size> LAST。 - サイズが明示的であるため、ドット詰め込みは必要ありません。
BINARYMIME
- サーバーはEHLO応答で
CHUNKINGとBINARYMIMEの両方をアドバタイズします。 - クライアントは
MAIL FROMコマンドでBODY=BINARYMIMEを宣言します。 - メッセージデータは
BDATで送信され、生のバイナリコンテンツを含む場合があります。Base64エンコーディングやCRLF行末の要件はありません。
SMTP例
DATAの代わりにBDATを使用してメッセージを送信する:
生のバイナリコンテンツ用のBINARYMIME:
主要な技術詳細
BDATとDATA
| 側面 | DATA | BDAT(CHUNKING) |
|---|---|---|
| 終了 |
.\r\n(独自の行のピリオド) |
明示的なバイト数+LASTキーワード |
| ドット詰め込み | 必須 | 不要 |
| バイナリコンテンツ | Base64でエンコードする必要があります | BINARYMIMEで生のバイナリ |
| ストリーミング | サーバーは終了記号をスキャンします | サーバーは正確なバイト数を読み取ります |
| 複数のチャンク | 適用されません | はい、各チャンク後に中間ステータス |
チャンクサイズ
義務付けられたチャンクサイズはありません。クライアントは通常、利用可能なメモリとネットワーク条件に基づいてチャンクサイズを選択します。一般的な戦略には、メッセージ全体を単一のBDAT ... LASTとして送信すること、または数百キロバイトのチャンクに分割することが含まれます。小さいチャンクは中間エラー検出を可能にします。大きいチャンクはプロトコルのオーバーヘッドを削減します。
エラー回復
サーバーがBDATチャンクを拒否する場合(例えば、メッセージが大きすぎる場合)、クライアントはBDAT 0 LASTを発行してトランザクションをきれいに中止できます。これは、クライアントがメッセージ全体とドット終了記号を送信する必要があるDATAモデルよりもクリーンです。
BINARYMIMEフォワーディング
BINARYMIMEメッセージを受信するサーバーは、BINARYMIMEをサポートしていないサーバーにそれを転送してはいけません。次のホップがBINARYMIMEをアドバタイズしない場合、転送サーバーは中継する前にバイナリコンテンツパーツをBase64エンコーディングに変換する必要があります。これは重要な相互運用性要件です。
一般的な間違い
-
CHUNKINGをチェックしないでBDATを使用する。すべてのサーバーがCHUNKINGをサポートしているわけではありません。
BDATを使用する前に、必ずEHLO応答を確認してください。CHUNKINGがアドバタイズされていない場合は、DATAにフォールバックします。 - 次のホップがBINARYMIMEをサポートしていない場合にBODY=BINARYMIMEを送信する。リレーサーバーで、下流のMTAがBINARYMIMEをアドバタイズしない場合、中継する前にバイナリパーツをBase64に再エンコードする必要があります。生のバイナリを理解していないサーバーに送信するとメッセージが破損します。
-
バイト数を間違える。
BDATのサイズは、その後に続くオクテット数と正確に一致する必要があります。バイトが少なすぎるか多すぎるか送信するとプロトコルが非同期になり、セッションが破損します。 -
LASTキーワードを忘れる。最終的な
BDATチャンクにはLASTを含める必要があります。それがない場合、サーバーはより多くのチャンクを待機し、セッションがハングします。 -
BDATとDATAを混在させる。クライアントは、特定のメッセージに対して
DATAまたはBDATのいずれかを使用する必要があり、決して両方ではありません。トランザクション中に切り替えるとプロトコルエラーになります。 -
中間チャンクエラーを処理しない。最終的ではない
BDATチャンクがエラーを返す場合、クライアントはデータを送信し続けるのではなく、BDAT 0 LASTを送信してトランザクションをリセットする必要があります。
配信可能性への影響
- バイナリ添付ファイルの帯域幅削減。BINARYMIMEはBase64エンコーディングの33%のオーバーヘッドを排除します。10 MB添付ファイルの場合、約3.3 MBの転送データを節約できます。これは規模が大きいと重要です。
- 大きなメッセージの処理速度が向上します。明示的なサイズのBDATにより、サーバーは事前にメモリを割り当て、行単位のスキャンをスキップできます。これにより、両側のCPUオーバーヘッドが削減されます。
- よりクリーンなエラー処理。中間チャンク応答により、クライアントはメッセージ全体を送信せずに早期に障害を検出できます。メッセージが拒否される場合、これは帯域幅と接続時間を節約します。
- 大手プロバイダー間での広範なサポート。Google、Microsoft、およびほとんどの大規模メールプラットフォームはCHUNKINGをサポートしています。利用可能な場合はそれを使用することは、効率的な配信のためのベストプラクティスです。
- ドット詰め込みバグを排除します。BDATは、ドット詰め込みと行末処理に関連する潜在的なバグのカテゴリ全体を削除します。メッセージは送信されたとおり、バイト単位で到着します。