【にわか】SMTPの仕組みを独学したメモ切れ

テクノロジー

メール系の話に本格参入する気はないけど…

でも仕事の流れで、迷惑メール判別の仕組みを色々調べてしまったし、仕事の流れでたぶんこのまま葬られるだけの知識なので、消える前に書き留めておくだけです。

ガチ勢目指すつもりないので、激しいツッコミいやん。


SMTPの話。

SMTP(Simple Mail Transfer Protocol)は、メールの差し出しから、相手方の受信ボックスへ放り込むまでを担うプロトコル。

メール技術最初期から存在(デファクトスタンダードが標準になった形だけど)する、ある意味完成された規格。

メールといえば、「ToとCcとBccを区別しろ」というビジネスマナーがある。

このうちBccは、「ToとCcの人にはアドレスが見えないので、上司をこっそり入れとく用途」みたいな使い方をされる。

確かに受信したBccに誰かいるかなんて、メーラーで見ても書いてない。

ちょっと詳しい人が「メールヘッダー」を見てみても、やはり書いてない。

それどころか実は、Bccで送られた人本人が、「自分がBccに入っている」ことだって分からない。「ToでもCcでもないからBccで来たんだろう」と消去法するしかない。

あれ?内部データであるメールヘッダーにも名前が無い人に、どうやって届けてるんだろう?


メールを配達するとき、メールヘッダーは読んでいない。全く読んでいないわけではないが、基本機能だけならメールヘッダーは無くてもいいぐらい。

SMTPで通信するときは、こんなやり取りをする。

$ telnet smtp.example.com smtp
220 Connected
> HELO cgi.example.com
250 Hello smtp.example.com
> MAIL FROM:webmaster@example.com
250 okay
> RCPT TO:test@hogefuga.com
250 okay
> DATA
354 Start mail input, end with "."
> From: webmaster@example.com
> To: test@hogefuga.com
> Subject: テストメール
> 
> テストメールの本文です。
> 
> .
250 okay
> QUIT
221 bye.

上で出てきた「RCPT TO:」で書いてあるメールアドレスを、「エンベロープTO」、同じく「MAIL FROM:」のメールアドレスを「エンベロープFROM」と言う。

SMTPはエンベロープTOのアドレスへ届くようメールをバケツリレーしていく仕組みである。

対してDATAの後に書いたFrom:とTo:は、メールヘッダーの中なので「ヘッダーFROM/TO」みたいな呼ばれ方をする。

エンベロープ(envelope)=封筒。メールは現実世界の郵便で喩えられることが多いが、ここでも、「郵便屋は封筒の中身の便箋に書いてある人物へ届けるのではなく、封筒に書いてある宛名に届ける」という解釈ができる。実際その通りである。

メールヘッダーにはCcやBccも書けるが(Bccは送信側ではヘッダーに記録しているが、SMTPで発信する前に消される―――そうでないと冒頭のビジネスマナーの意味がなくなる)、「エンベロープCC」とか「エンベロープBCC」なるものは存在しない。すべて等しくTOである。だって手紙の宛先だもん。

上のやり取りを数回繰り返したり、「RCPT TO:」行を複数書いたりして、SMTPサーバーさんはTo・Cc・Bccの皆さんのメールボックスへメールを送信する。

エンベロープFROMとエンベロープTOは、あくまでSMTPのプロトコルでのデータの一つに過ぎないため、目的のメールサーバーに着いたら(=POP3やIMAP4の担当範囲に収まったら)、エンベロープFROM・エンベロープTOは電子の彼方へ消える。

現実に喩えたら、郵便屋はポストに投函する時、わざわざ封筒だけ捨てて中身をポストに入れる感じか。嫌だなそんなの。

ということで、「なぜ受信者から見えるところにメールアドレスが書いてないBccメールが届くのか」の答えは、「SMTPのいち符号であるエンベロープTOへ送り届けてるから」である。


ところで現実の郵便屋が、宛先に行ったら空き家だったとか別人が住んでいたとかで「宛所に尋ねあたりません」となった場合、そういうハンコを捺して、その郵便の送り主に返送する。この「送り主」も、わざわざ封筒を開けるのではなく、封筒のウラとか下とかに書いてある荷主と思しきところを送り主として扱う。

SMTPでも同じで、送信先サーバが死んでるとかで届けられなかった場合、SMTPの範疇であれば「エンベロープFROM」へ送り返す。
ちなみにこの返送されたメール、一般的にはリターンメールとかエラーメールとかで呼んだほうが分かりやすいが、メール技術の世界では「バウンスメール」と呼ぶ。

もし、目的のメールサーバーにたどり着いた後、POP3やIMAP4の担当範囲に収まった後にエラーとなったら?

SMTP処理は終了してしまったので、エンベロープFROMは電子の彼方へ飛んでいった。なので返せない……だと困るので、受信の過程のどこかのタイミングで、メールヘッダーに「Return-Path」を書き加えて、ここにエンベロープFROMを書いておく仕組みになっている。これで、SMTPが終わった後でも返送先が分かるわけだ。


ちなみに冒頭のSMTPのやり取りから察せるかもしれないが、エンベロープFROM/TOと、メールヘッダーのFROM/TOは違ってても構わない。

なぜ?かはプロトコルの歴史の話になるかもしれないが……まあ、ネットの知り合いに手紙を書く時なんかは、封筒に本名を書いておいて、便箋にはハンドルネームを書くというのは普通のことなので、そういうもんだと思って大丈夫かと思う。

メールの世界でいえば、「うちの団体から送ったメール、エラーメールは管理者へ返してほしい」という場合は、エンベロープFROMに管理者のアドレスを書いておくとか。「このメールアドレスは送信専用につき、返信はこっちのアドレスへ」という場合は、ヘッダーに「Reply-To」というのを書き加えておけば、メーラーはヘッダーのFROMではなくそっちに返信してくれるとか。

付け加えると、実はエンベロープFROMも偽ることができる。だってエラー時の返送先にしか使ってないもん。

…言うまでもなく、この仕組みは迷惑メールの原因となっている。

つまり、私が個人のメールアカウントから、エンベロープFROMもヘッダーFROMも「~~@amazon.co.jp」とかしてメールを送れば、どう見てもアマゾンからのメールに見えるでしょ?ということ。名乗るだけ自由ですから。

他にも悪用例として、敵対する誰かをエンベロープFROMにセットして、適当なメールアドレスへメールを大量に送りつけたら、大量のバウンスメール(エラーメール)が敵対する誰かに届いて、メールボックスをパンクさせられる…という手も。

流石にこの「名乗るだけ自由」っていうのはダメだということで、「確かにこの人はうちのドメインを使ってヨシ!」という認証制度が存在する。

DNSレベルでサポートされる、「SPFレコード」というものである。


SPF(Sender Policy Framework)とは、そういうなりすましを防ぐための仕組みである。

設定方法はカンタン、DNSにSPFレコード(と、互換のためTXTレコードでも同様の記述をする必要がある)で、「私のドメイン名を使っていいIPアドレス一覧」を列挙しておく。IPアドレス範囲指定もできるし、別のネームサーバーからインポートして端折ることも可能。

で、いざメールを送ったとして、受信した側がSPFレコードを検証する。
具体的には、SMTPで受信したサーバーがDNSに対して、「このエンベロープFROMのドメインのSPFレコードをおくれやす」と要求する。
そうして手に入れたSPFレコードで許可されているIPアドレスと、SMTPの発信元IPアドレスを比較して、許可されていれば「このメールはシロだ」、許可されていなければ「こいつはなりすましだ」と判断できる。
という仕組み。

尤もこれは「IPアドレスは容易には騙れない」という原則に基づいたものなので、IPアドレスを詐称されたらどうしようもない。(別の対処手段があるんだと思う、たぶん)
あと、類似のドメイン名を阻止するのは守備範囲外なので、「~~@arnazon.co.jp」ってドメインで(AMAZONのMがRNになってますよ)メールを送られることに対して、amazon.co.jpがなにか防御できる仕組みではない。

んで、キャリアメール(DとFとA)の「迷惑メール対策サービス」はもーっと厳しくSPFレコードを使っている。エンベロープFROMだけではなく、HELOで入力したドメインも(実はHELOで打つホスト名もウソつける)、そしてメールヘッダーのFROMも全部SPFレコードを確認して、オールグリーンでないと受信させてくれない。

一体これの何が厄介かというと、AWSのサービス「AWS SES」を使ったとき、ちゃんとSPFレコードを書いておかないと、ケータイに届かないんだわ……


ということで、無事「仕事の流れで迷惑メールについて調べた」ところに帰着しました。ちゃんと調べられたということです。

ちなみに迷惑メール対策といえばもう一つ、「ブラックリスト」があるので、ちょっとメモしておきます。流れで一緒に調べちゃいました。


メールの不着があまりにも多いと(何パーセントだっけ、「あまりにも多い」の敷居はかなり低い)、その発信元IPアドレスがプロバイダレベルからブラックリストに登録される危険がある。

また世界共通のメールのブラックリストサービスというものもあり(最大手はSPAMHAUS)、こちらはハニーポットと呼ばれるメールアドレス(ちょっと前まで誰かが使っていたが今は誰も使っていないメールアドレスなど)を監視しておいて、そこにあまりにも長期間同じ発信元からメールが来た場合、「おっ、この発信元は送信先が居るか居ないか全然メンテしてねえな!」と判断して、ブラックリストに載せるという仕組みをしている。

メールを送る側としてはこのブラックリスト入りをいかに回避するか、という考えが必要で、対応策としては「バウンスメール率を下げる」「メールがすぐ開封されるか確認する」ということになる。

バウンスメール率を下げるために、メール配信サービス(SendgridとかAWS SESとか)には一度不着となったメールアドレスにはもうメールを送らないよう、リストを作ってくれる機能がある(それを無視して送り続けると、「おっ、この管理者は送信先が居るか居ないか全然メンテしてねえな!」と判断して、メール配信サービスの利用停止処分を食らう)。

あとメールがすぐ開封されるか確認するために、「開封確認付きメール」なんてものもある。メールが開封されたら、メーラーからメール送信元へ「開けましたよ!」通知を送る機能。
まあ用途が用途なため(ブラックリスト入りを避けたい人は(会社の取引メールとかではなく)不特定多数にメールを送りたい人のため)、家庭用メーラーはデフォルトで開封確認を無効にしてたりするのだが。
※ほぼすべてのメーラーで、開封確認に応じなくともメールは普通に開封できるし中身も読める

で、AWS SESは「一度不着になったメールアドレスのリストを作る」と書いたが、このリストは同一リージョン内の全ユーザーで共有されるので、例えば「ドメイン指定受信設定」のおかげでキャリアケータイへのメールが弾かれたサービスA社がSESを使っておれば、ドメイン指定受信設定で許可されているサービスB社のSESも巻き添えを食らって送信を阻止される、という厄介仕様がある。
どちらかといえば厄介なのはドメイン指定受信とかいう機能だが…。


ということで、真に仕事で調べたかったのはこのことでした。

あー長かった。でも仕事ではここまで深堀りする必要はないから、ブログにぶちまけて終わりにしておきます。

ガチでメールを調べたい人の足がかりにでもどうぞ。