電子メール送信に関する技術


ふと気になって調べたことの備忘メモです ✍

(2022/4/2追記)Twitterやはてブで色々とご指摘やコメントを頂いたので、それに基づいて加筆と修正をおこないました
特に、幾つかの技術については完全に誤った説明をしてしまっており、大変助かりました…ありがとうございました🙏

なぜ調べたか

メール送信機能のあるWebアプリケーションを開発・運用していると、 特定のアドレスに対してメールが届かないんだが とか MAILER-DAEMONなるアドレスからメールが来たんだけど といった問い合わせを受けて原因を探ることになります
実務においては、Amazon SESSendGrid といったメール送信処理を抽象的に扱えるサービスを使うことが多いと思いますが、
ことトラブルシューティングにおいては、その裏にある各種技術についての概要を知っていると、状況把握や原因特定をしやすくなります

ありがたいことに、電子メールは枯れた技術のようで公開日が古い記事でも参考になるものがたくさんありますが、
現代に全体感を理解しようとして調べていくと、歴史的経緯からアドホックに定義された(ように見える)仕様が色々とあってなんども調べ直すことがあって無駄を感じたので、まとめることにしました

なお、掲題の通りではありますがこの記事はメール送信に関するもののため、メール受信やメール内容に関連する各種技術については触れていません
加えて私は一介のWebアプリケーション開発者で雰囲気で電子メールを使っている身なので、誤りが多分に含まれる可能性があります

あしからず 🦵

調べたこと

全体感を捉えるために、調べるとよく出てくる各要素技術についてどこら辺に存在するものかわかるよう図に起こしてみました 🌏

以下、メールの送り元からメールの送り先に至るまで順に見ていきます

MUA / MSA / MTA

電子メールの送信をざっくり理解するにあたっては、大きく3つの登場人物を意識するとよい
記事によってMSAとMTAが同質化していたりなど差異がある場合もあるが、雰囲気で理解しておけば充分の模様

  • MUA (Message User Agent)
    • メールを送信(ないし受信)するソフトウェア
    • 元々はクライアントPCで動作するメールソフト(Outlookなど)のような、SMTP / IMAPによる通信をおこなうソフト群を指していたものと思う
      • Amazon SESのようなAPIによるメール送信が可能な仕組みを利用する場合は、クライアントのプログラムも広義のMUAと言えるかも?
  • MSA (Message Submission Agent)
    • MUAからのメール送信を受け付けるソフトウェア
      • 受け付けたメールをMTAへリレーしていく
    • メールの送信元にあたり、AWSアカウント上に設定したAmazon SESやEC2上で動作する Postfix などがこれに該当する
      • 不正なユーザーによるメール送信をさせないよう、 MUA に対して何かしらの認証の仕組みが必要 になる
  • MTA (Message Transfer Agent)
    • メールを目的のサーバまで転送していくソフトウェア
    • MSAやMTAから送られてきたメールを宛先のMTAまで転送していく
    • MSAがMTAの役割も兼用することも多い
      • 基本的に MUA -> MSA -> (状況によって宛先に至るまで別のMTAを経由する) -> 宛先のMTA という経路でメールが渡されていく
    • 電子メールはパブリックかつ性善説的な仕組み なので、あるMTA(ないしMSA)から別のMTAに対して自由にメールを転送することができる
      • メールアドレスを知っていれば、その人に対していつでもメールを送れますよね
      • このため、 メール転送元が妥当なサーバーであるか検証するための仕組みが必要 になる

https://titechcomp.github.io/y18-il1j/32-delivery.html

SMTP

メール送信には SMTP (Simple Mail Transfer Protocol) というプロトコルが使われる
今回は詳しく触れないが、メール受信には IMAP (Internet Message Access Protocol) などの別のプロトコルが使われるので、これらを混同しないように注意する

https://atmarkit.itmedia.co.jp/ait/articles/0105/02/news001.html

SMTPではHTTPと同じくASCII文字によりコマンドを組み立ててTCP通信でやり取りをおこなう
このため、サーバへのアクセスが可能であればtelnetコマンド等を使ってメール送信をおこなうことができる

https://qiita.com/sheepland/items/973198fa80f0213fe5a1

サブミッションポート

前述の記事でも触れられているが、宛先サーバに対して接続する際に利用するポート番号として 587 または 465 が一般的であり、サブミッションポートと呼ばれる
SMTPで利用されるポート番号と言えば 25 が有名だと思うが、こちらはMTAがメール転送をおこなうために使われている
(なお、25番ポートについてサブミッションポートのような一般的な呼称はないようだが、 スタンダードポート と表現しているケースがあった)

https://www.sparkpost.com/blog/what-smtp-port/

理由としては、元々 SMTPが認証を必要とせず誰に対しても自由にメールが送れたことから、スパマー(スパムメール を送ってくる人のこと)が跋扈するようになり、
これに対処するために、MSAとMTAで利用するポートを分けた上で、サブミッションポートでは SMTP AUTH 等によってMSA利用時に認証をおこなった上で、25番ポートにアクセスしてくる送信元MTAの信頼性(スパマーでないか)を検証することで安全なメール送信を実現している

https://www.infraexpert.com/study/tcpip18.html

SMTPS

現在ではメールを送信するクライアントとしてはGmailなどのWebアプリケーションやAWS SDKといったものが増えてきているが、元々MUAはOutlookThubderbirdといった、SMTPによるやり取りが可能なソフトウェアをクライアントにインストールして利用していた
こちらについては 465 を用いてコネクション接続の段階から暗号化通信をおこなう SMTPS(SMTP over SSL/TLS) という規格が存在する

https://ja.wikipedia.org/wiki/SMTPS

本ポートについては、歴史的経緯から一時的に非推奨になっていたことがあった経緯から利用を推奨しないとする情報も存在するが、RFC8314において(別プロトコルとの重複利用になっているようだが)有効なポートとされている
また、実体として現在も一般的に利用されており、例えばBIGLOBEのメールサーバー接続設定では465ポートを利用してMUAからMSAに接続するようユーザに要求していた

https://support.biglobe.ne.jp/settei/mailer/overssl.html

STARTTLS

前述したSMTPSでは、そのポートを利用開始した段階で暗号化通信が強制される(これをImplicit TLSと呼ぶ)ため通信経路の安全性が高くなるが、
SMTPは元々平文で送受信をおこなう仕様であったことから、宛先MTAが古いものであった場合に暗号化通信に対応していない可能性があり、そうするとメールを正しく送ることができないリスクが発生する
この問題に対処するために、SMTPにおいては同一ポートを利用する代わりに、まず平文でやり取りを開始し、相互がTLSに対応していることを確認してから途中で暗号化通信に切り替える…という動作をさせることができる

https://sendgrid.kke.co.jp/blog/?p=12756

これは、SMTP通信中にSTARTTLSコマンドを発行することで実施することができ、
サブミッションポートとして 587 を利用する場合と、 25 ポートにおいて暗号化通信を利用する場合に用いられる

https://blog.smtps.jp/entry/2017/09/07/114820

なお、STARTTLSのような接続の過程で接続対象に応じて暗号化方式を変更する仕様のものを日和見暗号化方式と呼び、メッセージ送信の過程で様々なMTAを経由する可能性があるSMTPにおいては実利上の優位性がある

https://ja.wikipedia.org/wiki/日和見暗号化

特にSSLやTLSに関する文脈では、特に Implicit TLS / Explicit TLS という語で説明される場合もある
SMTPSはImplicit TLS 、STARTTLSはExplicit TLSにあたる

https://qiita.com/n-i-e/items/e7fdb3ac64a6f172003f

なお、Googleが送受信しているメールについては、全体のトラフィックに対してどの程度の割合が暗号化された経路でやり取りされているか確認できる

https://transparencyreport.google.com/safer-email/overview?hl=ja

2022年時点では、おおよそ90%程度のメールが暗号化された経路で送信されているらしい


https://transparencyreport.google.com/safer-email/overview より引用

OP25B

先ほど、 電子メールは性善説的な仕組み と説明したが、当初スパマーは本人認証をおこなう必要があるMSA経由でのメール送信をおこなわず、自身で野良MTAを建てて25番ポートに対してボット等によりスパムメールやウィルスメールを送りつける…という手法を取っていた
これに対して対抗する手段として、ISP(Internet Service Provider) 各社によって 契約ユーザーから 25 番ポートを利用しての外部接続を遮断する という措置を取ることで、25番ポートへのアクセスをISPが運用するメールサーバやメール送信事業者に限定することで不審な送信元を遮断している

https://www.dekyo.or.jp/soudan/contents/taisaku/4-1.html

参考:AWS を使った場合のメール送信

Amazon SESを例に取ると、APIまたはSMTPによるメール送信を選択できるが、いずれのケースにおいてもマネージドのMSA(以下図中の ②)が利用される
これによって、AWS外部のMTA(図中の ③)から見た時に、メールの送信元(②)は充分に信頼のおける相手であり、かつメール送信者(図中の ①)は送信元により認証がおこなわれているため、スパムやウィルスメールを送ると送信元にばれてしまうこととなる


https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-concepts-process.html より引用

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-concepts-process.html

また、EC2等を用いて自身でPostfixを運用すれば制限を迂回できるかというとそのようにはなっておらず、
AWSアカウントから25番ポートでのアウトバウンド通信はデフォルトで許可されておらず、利用したい場合はAWSに対して制限解除申請をおこなう必要がある

https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-port-25-throttle/

SMTP リレー

以上に説明したような背景から、MTAは自身で運用するよりもメール送信を専門にしている事業者のものを使った方が受信者側から見た時に信頼度が高く、メリットが大きい

https://www.proofpoint.com/jp/threat-reference/smtp-relay

前述のAmazon SESやSendgGridは、メール送信元として自社の運用しているサーバを透過的に使わせるSMTPリレーに対応しており、社内ネットワーク等で独自構築したMSAからメール送信の部分のみを委譲するユースケースを想定している
こうしたSMTPリレーサービスを専門とする業者も調べると多数出てくる

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-smtp-existing-server.html

https://sendgrid.kke.co.jp/blog/?p=636

MTAサーバー間におけるSMTPリレーは25番ポート & STARTTLSを使った暗号化通信によっておこなわれる

DNS

MTA間でのメール送信の際には メール送信元/転送元の妥当性検証 が重要であることを説明したが、これには DNS(Domain Name System) が重要な役割を占めている
メールアドレスは [email protected] のような形式で表記されるが、この内アットマークより後ろのドメイン部 example.com に対応するIPアドレスをDNSにより解決することでメール送信先を特定する

https://ascii.jp/elem/000/000/432/432823/

CLIからDNSへアクセスする場合はdigコマンドを利用する

https://hana-shin.hatenablog.com/entry/2021/12/22/201022

以下、特にメール送信に関連するレコードについて詳細を見ていく

MX レコード

MSAから宛先のMTAに対してメールを転送していく過程では、宛先ドメインのMX(Mail Exchange)レコード が参照される
送信元ドメインのMXレコードは、メール送信においては不要(関係がない)ことに留意する

https://jprs.jp/glossary/index.php?ID=0163

例えば、 gmail.com ドメインのMXレコードを調査すると以下が返却され、gmail-smtp-in.l.google.com にアクセスすれば宛先のMTAと通信できることがわかる(実際にはOP25Bにより試せないため推測ですが…)

$ dig MX gmail.com

略

;; ANSWER SECTION:
gmail.com.		2159	IN	MX	10 alt1.gmail-smtp-in.l.google.com.
gmail.com.		2159	IN	MX	40 alt4.gmail-smtp-in.l.google.com.
gmail.com.		2159	IN	MX	20 alt2.gmail-smtp-in.l.google.com.
gmail.com.		2159	IN	MX	5 gmail-smtp-in.l.google.com.
gmail.com.		2159	IN	MX	30 alt3.gmail-smtp-in.l.google.com.

略

MXレコードが存在しない場合は、フォールバックとして AレコードまたはAAAAレコード が示すアドレスに対して接続を試みるらしい
したがって、トラブルシューティング等にあたってMXレコードが無いからといって即座にメールを受信できないドメインと断定することはできない

https://heartbeats.jp/hbblog/2016/12/null-mx.html

MTA-STS

前項で触れたように、STARTTLSは接続対象とのネゴシエーションの過程で暗号化レベルが変化することからダウングレード攻撃のような、不正な第三者が平文での通信を強制させる操作に対して脆弱性がある

https://powerdmarc.com/ja/what-is-tls-downgrade-attack/

こうした状況に対処するため、2018年にRFC8461 MTA-STS (SMTP MTA Strict Transport Security) という新しい仕様が登場している
MTA-STSは、受信MTA側がメールの送信元に対して暗号化接続を強制させるといったポリシーを明示するもので、送信元が暗号化に対応できない場合メールが送信されなくなる

https://qiita.com/kikutaro/items/e79dc4a6dcbd3e5a2ac5

例えばGmailはMTA-STSに対応しており、自身で利用しているドメインで使いたい場合は以下手順で設定ができる

https://support.google.com/a/answer/9261504?hl=ja

既存技術も踏まえたMTA-STSに対する説明としては、以下の記事で丁寧に解説されている

https://logmi.jp/tech/articles/324439

SPF / DKIM / DMARC

今までは、 MUA -> MSA -> MTA とメールが転送されていく過程で利用される技術について説明してきたが、
ここからは宛先MTAが送信されてきたメールを受け付ける過程でおこなわれる妥当性検証について説明していく
検証はいずれもDNSに登録された幾つかのレコードと、SMTP通信中に宛先MTAに提示された情報を比較することでおこなわれる

簡単なまとめは以下の通り

  • SPF
    • メール送信元ドメインの妥当性検証
  • DKIM
    • メール内容の改竄検知
  • DMARC
    • メール送信元ドメインの詐称の抑止
    • 不審なメールを検知した際の扱い方の定義

https://sendgrid.kke.co.jp/blog/?p=7006

ちなみに、それぞれの設定はいずれもオプションのため、設定をしなくてもメール送信は可能である

SPF

送信元ドメインの妥当性検証は、元々の送信元IPアドレスがメールの送信元ドメインに紐づくものか確認する
例えば、 [email protected] がFromアドレスとして記録されたメールがIPアドレス xxx.xxx.xxx.xxx から送信されてきた場合、 example.com からのメール送信元として xxx.xxx.xxx.xxx が妥当なものであることが導出できればよい
この一連の仕組みを SPF(Sender Policy Framework) と呼び、DNSに所定の形式のTXTレコードを登録することで実現する

https://sendgrid.kke.co.jp/blog/?p=3509

Amazon SESにおいては、以下のように amazonses.com を送信元として許可する設定にすればSPFの設定が完了していることになる

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-authentication-spf.html

example.com ドメインにSESを有効な送信元として紐付けている場合、digコマンドで問い合わせると以下のような値が返却される
DNSにレコードを登録できるのはそのドメインを所有している人物に限られるため、これによって example.com のメール送信元として amazonses.com を認めている ということが確認できる
これに加えて、 amazonses.com に対してAレコードの問い合わせをおこなった際に前述のIPアドレス xxx.xxx.xxx.xxx が返却されれば、 example.com のメール送信元として IP アドレス xxx.xxx.xxx.xxx が適切である ことがわかる

詳細な仕様は以下が詳しい

https://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/

$ dig example.com TXT

略

;; ANSWER SECTION:
example.com.		86400	IN	TXT	"v=spf1 include:amazonses.com ~all"

略

DKIM

SPFによるチェックによりメールアドレスの送信元ドメインの妥当性がわかるが、この情報はメールヘッダに設定された値を参照するため、メールが転送中にMTA等により改竄されていないことを前提としている
以下図のヘッダFromが不正に書き換えられた際に検知できる必要がある


https://sendgrid.kke.co.jp/blog/?p=10121 より引用

これについては、 DKIM(DomainKeys Identified Mail) という技術を使って実現する
DKIMはメールに対して公開鍵暗号方式にて電子署名を付与し、その公開鍵をDNSに selector._domainkey.example.com の形式で登録することで、宛先MTA側にて改竄検知を可能にする

https://sendgrid.kke.co.jp/blog/?p=2044

Amazon SESにおいては、以下手順によりDKIMレコードを設定できる
コンソール等から操作するだけで電子署名の作成および管理をマネージドに実施してくれるので簡単に利用できる

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-authentication-dkim-easy.html

宛先MTA側からDKIMレコードを検証するフローとしては以下のようになる

https://powerdmarc.com/ja/how-to-find-dkim-selector/

Gmail等で受信したメールのヘッダ情報を確認し、 DKIM-Signature ヘッダの s=hogehoge; と書かれている箇所を参照する

DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=hogehoge; d=example.com; 後略

digコマンドによりTXTレコードを引いた時に、 p=xxxxxx/yyyyyy/zzzzzz として値が返却される値が公開鍵として利用される

$ dig hogehoge._domainkey.example.com TXT

略

;; ANSWER SECTION:
hogehoge._domainkey.example.com. 7192 IN CNAME	hogehoge.dkim.amazonses.com.
hogehoge.dkim.amazonses.com. 3570 IN TXT "p=xxxxxx/yyyyyy/zzzzzz"

略

詳細な仕様は以下が詳しい

https://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/dkim/

DMARC

SPFやDKIMによって送信元ドメインとメール内容の検証ができたが、これらの検証で不適格となったメールの取扱については規定されておらず受信者側に任されている
これについて、悪意のある第三者によって不正に送信されたメールの取扱方法を正当な送信元から表明するための仕組みが考案され、 DMARC(Domain-based Message Authentication, Reporting and Conformance) として運用されている

https://mailmarketinglab.jp/about-dmarc/

内容は、送信元ドメインに対して _dmarc をつけたものでDNSにTXTレコードを問い合わせることで確認できる

$ dig _dmarc.example.com TXT

略

;; ANSWER SECTION:
_dmarc.example.com.	86400	IN	TXT	"v=DMARC1; p=quarantine; rua=mailto:[email protected]; ruf=mailto:[email protected]; rf=afrf; pct=100"

略

各値の詳細は以下を参照するとよい
上記サンプルであれば、 認証に失敗した全てのメールについて、迷惑メールに振り分けた上で認証が失敗したことを [email protected] 宛に報告する というような意味合いになる

https://sendgrid.kke.co.jp/blog/?p=3137

Amazon SESにおける設定方法は以下

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-authentication-dmarc.html

参考: Amazon SES + Terraform を利用している場合の SPF / DKIM / DMARC 設定例

Terraformで設定する例を以下記事でまとめているのでよければどうぞ 🍢

https://zenn.dev/yktakaha4/articles/gmail_and_ses_by_tf

Bounce / Complaint

メールが認証上の諸問題をクリアできる状態で送信された場合でも、受信側の事情によりメールが配送されない場合があり、以下のような分類がある
特にハードバウンスや苦情のケースにおいては、送信者側としてはこれ以上宛先に対してメールを送るべきでない状態であるため、何かしらの方法を使って対象のメールアドレスに対するメール送信を抑止する必要がある

  • バウンス(Bounce)
    • ソフトバウンス
      • 宛先のメールサーバ上のメールボックスが一時的に容量超過でメールを受け取れなかった、サーバがダウンしている…など、 一時的な理由 によりバウンスされた場合
    • ハードバウンス
      • 宛先のメールアドレスが存在しなかった、サーバとして受信拒否されている…など、 恒久的な理由 によりバウンスされた場合
  • 苦情(Complaint)
    • メールが受信された後、ユーザによって迷惑メールとしてマークされた場合

https://ja.wikipedia.org/wiki/バウンスメール

上述したようなメールアドレス等に対する送達性に起因するバウンス以外にも、SpamAssassin などのスパムメールフィルタによってバウンスが発生する場合もある

https://www.itmedia.co.jp/enterprise/articles/0603/30/news020.html

Envelope-From / Return-Path

前述した様々な理由によって受信者側にてバウンスや苦情が発生した際にメールの送信元へ通知する必要がある
この時に用いられるメールアドレスとして、メールの送信元サーバーを示す Envelope-From が利用される
これは、MUAがメールの送信依頼をおこなったアドレスと、MSAによって配送される際のアドレスが変わりうるため区別されている
Envelope-Fromに対して、メールの送信依頼元のアドレスは Header-From と言われる

https://baremail.jp/blog/2021/05/25/1377/

Amazon SESにおいては、 [email protected] のような、メール毎に採番された一意のIDを含むアドレスが Envelope-From に指定される仕様となっており、自動的に指定された上で受信内容をAWS側で解釈してくれる
詳細な仕様としては以下のような形式でEメールがやり取りされる

https://docs.aws.amazon.com/ja_jp/ses/latest/dg/send-email-concepts-email-format.html

バウンスが発生すると、受信MTAは Envelope-From に記録されていたアドレスを Return-path ヘッダとしてメールに追記するため、
送信元にてバウンスしたメールの Return-Path を確認することで、受信MTAからどのアドレスを経由してバウンスメールが届いたか確認できる
一連の動作から Return-Path には Envelope-From と同じアドレスが設定されることになるが、 それぞれの情報を送信側 / 受信側のどちらが書くかは留意したい

https://blog.smtps.jp/entry/2018/04/18/112026

レピュテーション

あるドメインについてバウンスや苦情がどの程度発生しているかは、与信管理のような仕組みが各メール配信事業者によって運用されており、レピュテーションと呼ばれる
メール送信者にはこれらの発生率を低く保つことが要求される

https://baremail.jp/blog/2019/05/24/125/

自身が利用しているドメインのレピュテーションは、以下の記事で挙げられたようなサイトで確認できる

https://sendgrid.kke.co.jp/blog/?p=11000

Amazon SESにおいては、メールに対してバウンスや苦情が発生した際にSNSにて通知を受けることができる
また、バウンス率や苦情率といった統計情報もドメインごとに計算されており、ユーザにて確認ができる

https://dev.classmethod.jp/articles/ses-bounce-check/

バウンス率・苦情率が一定値を超過した場合、SESの利用制限を課せられる場合がある

https://blog.serverworks.co.jp/tech/2017/05/17/post-56961/

サプレッションリスト

バウンスメールが発生した場合の対処としては、対象のアドレスをメール送信者側に構築されたサプレッションリストに対して登録するのが一般的である

https://ja.wikipedia.org/wiki/サプレッションリスト

Amazon SESにおけるサプレッションリストはアカウントレベルのものとAWS全体のものがあり、詳細は以下

https://blog.denet.co.jp/amazon-ses-suppression/

MAILER-DAEMON / Mail Delivery Subsystem

バウンスメールがReturn-Pathに対して返送される過程で、送信元のメールアドレスに対して MAILER-DAEMONMail Delivery Subsystem といった送信者からメールが送られて来る場合がある
これらはバウンスが発生したことをメール送信者に対して通知するためのもので、内容を確認するとバウンスが発生した詳細な理由が確認できる

https://libsisimai.org/ja/docs/what-is-bounced-email.html

バウンスの詳細な理由は、SMTP ステータスコードに加えて各MTAにて独自拡張された形式で説明されるため、理解するのが難しい場合がある
以下のサイトがとても詳しいので参考になる

https://libsisimai.org/ja/reason/

おわりに

かなり疲れましたが、勉強になったのでよかったです🍨
誤りや、他に紹介したほうがよさそうな内容があればぜひ教えてください!