SMTPによるメール送信のしくみ

メールを送信するために使用するプロトコル(SMTP)について説明します。 SMTPはRFC 821で定義され、何回か改定して現在はRFC 5321になっています。 改定により細かなところは変わっていますが基本は同じです。 互換性を保持していてRFC 821の仕様で送信しても現在のメールサーバは受け付けることになっています。

メールサーバに接続する

メール送信するときに、まず初めに行うことはメールサーバに接続することです。
はい、そこズッコケない!!
メール送信するクライアント(メーラー)の送信設定には、SMTPサーバのホスト名、ポート番号、認証、暗号化などの項目があります。 各SMTPサーバもこれらの情報を公開しており、メーラーはその設定を行えば送信できます。 さて、受け付けたメールサーバはそのメールをどうするのでしょうか?
メーラーは世界中のどのメールアドレスに送信する場合でも、設定した一つのメールサーバに送信します。 受け付けたメールサーバは、世界中のどのメールサーバに送信するか確認して、そこにメールを転送します。 その転送にもSMTPを使用します。

メールサーバ間の接続

つまり、メーラー⇒メールサーバの送信にも、メールサーバ⇒メールサーバの送信にも同じSMTPを使うのです。

f:id:vamoscavy:20170817185531p:plain

メールサーバ⇒メールサーバの送信では、メーラーで設定したような項目を自動的に決めなくてはなりません。 メーラーが設定項目を書いてあるWebページを読むことはありません。 それでは、どうするのでしょうか?
メールアドレスを思い浮かべてください。 メールアドレスは、anybody@example.comのような形式になっています。 この @ から後ろ@example.comの部分を用いてDNSを参照することにより接続先のSMTPサーバを決定します。
ポート番号は25です。 メールサーバ⇒メールサーバ間の送信では25に固定されています。
認証は行いません。 メールサーバ⇒メールサーバ間では、受信側は世界中からメールを受け付けるので認証しません。 しかし、宛先のメールアドレスがメールサーバの管轄外だった場合には受信を拒否します。
暗号化は基本的にはありません。 ただし、SMTPの拡張機能により暗号化することがあります。 Gmail では暗号化されずに受信した場合には赤い南京錠のアイコンで警告表示するので、拡張機能と言えども必須になってきています。

f:id:vamoscavy:20170817172632p:plain

Customers Mail Could は標準で暗号化通信に対応しているので、Gmail 宛てでも赤い南京錠のアイコンが表示されることはありません。

接続したら挨拶を交わす

メールサーバに接続すると、まずはメールサーバがSMTPを受け入れることを表すメッセージを送信します。

220 smtp.example.com ESMTP

この最初のメッセージをグリーティングといいます。 このように、メールサーバが送るメッセージは「3桁の数値+空白+メッセージ文」の形式になっています。 この3桁の数値は応答コードといい、これによりクライアントはメールサーバがどのような状態か分かるようになっています。 特に最上位桁(百の位)が重要です。

百の位 意味
2 成功
3 続きの送信待ち
4 一時エラー
5 恒久エラー

残りの二桁で応答の内容を表します。 グリーティングは通常はこのように 220 を返します。

クライアントは、メールサーバのグリーティングに対して挨拶を返します。 挨拶は EHLO (Extended HELLO) コマンドです。 昔(RFC 821)は、HELO (HELLO) コマンドでした。

EHLO client.example.com

EHLO (HELO) では、クライアントのホスト名を名乗ることになっています。 このホスト名は何を名乗ってもいいのですが、チェックが厳しいメールサーバではDNSに載っているかとか、 SPFをパスするかとか確認して、名乗りがなっていない場合は拒否されることもあります。
受け入れられた場合は、メールサーバは成功の応答を返します。 成功の応答コードは、通常は 250 になります。
ここで、いきなり例外です。 SMTP の応答は通常は1行なのですが、EHLO の応答は複数行になります。 複数行の応答では、続きがある場合に応答コードとメッセージ分を区切る空白を-にします。 1行目は、メールサーバのホスト名などを返し、2行目以降は拡張 SMTP で使用できる機能などを表します。

250-smtp.example.com
250-SIZE 2097152
250-STARTTLS
250 8BITMIME

ここでは、個々の拡張機能の説明はしませんが、一つだけ取り上げます。
応答例の中に STARTTLS があります。 この場合、メールサーバは STARTTLS による暗号化通信をサポートしています。 先に拡張機能による暗号化が必須になってきていますと述べましたが、それがこの機能です。 STARTTLS を使う場合は、クライアントが EHLO の応答に STARTTLS があること確認した後に STARTTLS コマンドを送信します。

STARTTLS

メールサーバが STARTTLS コマンドを受け入れると、その旨の応答を返して暗号化通信に入ります。

220 2.0.0 Ready to start TLS
(この後は、暗号化通信。)

クライアントは、この応答を確認してから TLS のハンドシェイクをして暗号化通信に入ります。 暗号化通信に入ったら、クライアントは再度 EHLO コマンドを送信します。 これは、最初の EHLO と STARTTLS 後では使える拡張機能が異なることがあるからです。

250-smtp.example.com
250-SIZE 2097152
250-AUTH CRAM-MD5 LOGIN PLAIN
250 8BITMIME

この例では、EHLO の応答から STARTTLS が除かれて、代わりに AUTH が追加されています。

挨拶(と暗号化)が終了したら実際のメール送信を行います。 メール送信は MAIL FROM、RCPT TO、DATA の3コマンドを使用します。 これらのコマンドを使用している期間をメールトランザクションと言います。

メールトランザクション

メールトランザクションは、まず MAIL FROM コマンドから始まります。 MAIL FROM コマンドは、差出人のメールアドレスです。 差出人は一人なので、このコマンドは1回しか使用できません。

MAIL FROM:<from@example.com>

メールサーバは、その差出人のメールを受け付ける場合に成功を返します。

250 OK

次に、RCPT TO コマンドで宛先のメールアドレスを指定します。 宛先は複数指定することができるので、このコマンドは複数回使用できます。(上限はあります。)

RCPT TO:<to@example.com>

メールサーバは、その宛先のメールを受け付ける場合に成功を返します。

250 OK

メールトランザクションの最後はメール本文です。 メール本文を送るには DATA コマンドを使用します。

DATA

DATA コマンドを送ると、メールサーバは本文が送られるのを待ちます。 待っていることを表すために DATA コマンドの応答として 3xx の応答コードを返します。

354 ok send data ending with <crlf>.<crlf>

この応答をもってメール本文を送ります。 ここで言うメール本文とは、いわゆる本文の他に、メールヘッダや添付ファイルなども含みます。 全て送信したら、最後に.だけの行を送信します。

.

メールサーバは.だけの行でメール本文終了と認識して、メール受信処理を終えます。 メールを受信できたら成功の応答を返します。

250 OK

MAIl FROM から、ここまでがメールトランザクションです。

他のメールを送りしたい場合は、再度 MAIL FROM からメールトランザクションを開始することができます。 これにより、多くのメールを送る場合に、接続や暗号化のハンドシェイクなどの負荷を軽減して送ることができます。

Customers Mail Cloud では、メールトランザクションを終了しても一定期間は接続を保持する コネクションプールと呼ばれる機能を装備しています。 これにより、携帯電話キャリアや Gmail などの多くのメールアドレスを抱える宛先に大量のメールを送信する場合でも 効率よく送信先の負荷も上げずに行うことができます。

終了の挨拶を交わす

メール送信が終了しても、いきなり切断はしません。 SMTP は最初に挨拶するプロトコルですが、終了にも挨拶をします。 終了の挨拶は QUIT コマンドです。

QUIT

メールサーバが応答して終了です。

221 good bye

ここで、互いに切断します。

以上が、SMTP を用いてメール送信です。

復習

これらは、(STARTTLS を除いて)telnet コマンドで確認することができます。

$ telnet smtp.example.com 25
Trying 203.0.113.23...
Connected to smtp.example.com
Escape character is '^]'.
220 smtp.example.com ESMTP
EHLO client.example.com
250-smtp.example.com
250-SIZE 2097152
250 8BITMIME
MAIL FROM:<from@example.com>
250 OK
RCPT TO:<to@example.com>
250 OK
DATA
354 ok send data ending with <crlf>.<crlf>
メール本文
.
250 OK
QUIT
221 good bye
Connection closed by foreign host.

さて、ここまでの説明で1つ気になることがあったのではないでしょうか? メール本文として.だけの行は送れないのしょうか?
そんなことはありません。送れます。 その場合には、...を2つにします。 そうすると、..と送りたい場合には…
ということで、行の先頭が.の場合は、もう1つ.を重ねることになっています。 メールを受け取った方は行頭の...として扱うことになっています。

この SMTP は、7ビットのプロトコルです。 (EHLO の応答として 8BITMIME があれば8ビットに対応しています。) そのために、普段使っている UTF-8 やシフトJIS で日本語を送ることができません。 この辺りについては、SMTP というよりメール本文(DATA コマンドで送る内容)のフォーマットの話になるので、別の機会にお話しします。