HN 日本語サマリー

← 一覧へ戻る
プログラミング

メールについて少し

A Bit about Email (maurycyz.com)

10 pointsby vinhnx1 コメント

要約

この記事では、電子メールの基本的な仕組みと、その歴史的背景について解説しています。メールが送信者から受信者までどのように複数のコンポーネント(MUA、MTA、LDAなど)を経由して配信されるか、SMTPプロトコル、そして認証(SPF、DKIM)の重要性について説明しています。また、メールのプライバシーに関する懸念や、現代のメールシステムが抱える課題についても触れています。

全文翻訳

メールについて少し

2026-11-06 — 2026-11-08 燃やして捨てられる前に言っておくが、インターネットはエッジケースで成り立っているにもかかわらず、ほとんどが単純化されており、エッジケースには触れていないことを承知している。そうでなければ、本を一冊書くだろう。

まず、用語の定義から始めよう。典型的なメールは、受信者に届くまでに多くの異なるコンポーネントを通過する。

1. 送信者のMUA
[SMTP経由、ポート465]
2. 送信MSA
3. 送信MTA
[SMTP経由、ポート25]
4. 受信MTA
5. 受信LDAとメッセージストア
[IMAP経由]
7. 受信者のMUA

(これらすべてが必ずしも異なるマシンやプログラムである必要はないが、各ステップに名前を付けるのは役立つ。)

メールユーザーエージェント(MUA)はユーザーのコンピュータ上で動作し、メッセージの送受信に使用される。例えば、メッセージを送信した場合、そのメッセージはサブミッションエージェント(MSA)にアップロードされ、パスワードがチェックされた後、メール転送エージェント(MTA)に引き渡される。

転送エージェントの仕事は、他のメールサーバーと通信してメッセージを受信側にいるMTAに届けることだ。受信後、それはローカル配信エージェント(LDA)に渡され、受信者がメールをチェックするまで保存される。「LDA」という名前は標準的ではないが、4つの異なる頭字語を避けるために使用している。

この構造の理由は、システムが設計された(1980年頃)当時、ほとんどの組織は単一のサーバーしか所有できなかったことだ。メンテナンスはフルタイムの仕事であり、アップデートにはしばしば数日間のダウンタイムが必要だった。よく接続されたコンピュータでも、週の半分しか機能しない数メガビット/秒の専用リンクしか持てなかった。

これにより、MTAとMUAの区別が強制された。メール送信時に受信者側のサーバーが稼働していなくても、送信MTAはメッセージを保存し、後で再試行する。これにより、短時間の障害でメールがバウンスしなくなる。メールクライアントはユーザーが実行する対話型プログラムであるため、メールが読めるまで保存しておくための別個のメッセージストアが必要になる。

ほとんどのMTAは、通常指数バックオフを用いて、5日間メッセージの再試行を続けるように設定されている。私の設定では、最初の失敗から5分後に待機し、長時間の障害の場合は間隔を1時間に増やす。

MSAとLDAは常に何らかの形で存在してきたが、人々が自分のコンピュータからメールにアクセスするようになったり、サーバーにリモートログインするようになったりすると、はるかに複雑になった。

SMTP

MTA間の配信を含むほとんどの通信は、Simple Mail Transfer Protocolを介して行われる。少し絞り込むために、blog@maurycyz.comにメールを送信するMTAを想定してみよう。

最初のステップは、そのドメインの受信MTAを検索することだ。

# dig MX maurycyz.com
[snip]
maurycyz.com.           300     IN      MX      1 smallcrow.com.
[snip]
# dig A smallcrow.com
[snip]
smallcrow.com.          300     IN      A       65.109.172.162
[snip]

メールは、サブドメインハックやTXTレコードの乱用を使用せずに、独自のDNSレコードを持つほど古い。数字は優先度(小さいほど高い)であり、複数のホストが指定されている場合に使用される。大規模なメールプロバイダーは、タイムリーな配信を保証するために複数のサーバーを持っている。

SMTPは比較的単純なテキストベースのプロトコルだ。唯一の注意点は、ほとんどのメールサーバーがデータ終端としてCRLFを要求することだ。これはしばしばCtrl-Mで送信できるが、キャリッジリターンバイトを自動的に挿入するツールを使用する方が簡単だ。

# telnet
telnet> set crlf
Will send carriage returns as telnet <CR><LF>.
telnet> open smallcrow.com 25
Trying 65.109.172.162...
Connected to smallcrow.com.
Escape character is '^]'.
220 smallcrow.com ESMTP Postfix
HELO nowhere
250 smallcrow.com
MAIL FROM:<me@nowhere>
250 2.1.0 Ok
RCPT TO:<blog@maurycyz.com>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: <me@nowhere>
To: <blog@maurycyz.com>

Hello, world.

.
250 2.0.0 Ok: queued as C870D7CD93
QUIT
221 2.0.0 Bye

送信された各行はコマンドであり、リモートサーバーは3桁の数字と人間が読める説明で応答する。200の応答は成功、300は「続行...」、400は一時的なエラーで送信者に再試行を指示、500のエラーはメールが配信不能であることを示す。

(これがHTTPに似ているように見えるなら、それは偶然ではない。Webの多く、ヘッダー構文を含め、SMTPから借用されている。)

最初のコマンドは常にHELO(またはEHLO)で、送信MTAのホスト名が続く。これは通常、メールアドレスのホスト名とは異なるが、多くのプロバイダーは送信者のIPアドレスと一致することを要求する。次に、MAIL FROMとRCPT TOの2つのコマンドで、配信先アドレスと、失敗通知のアドレスを指定する。バウンスメッセージは通常、エラーが発生した場所の1つ上のステップで生成される。ほとんどの場合、受信MTAに問題があり、送信MTAにエラーコードを送信するが、その時点ではMSAはすでに切断されており、メールによる通知が強制される。これらの通知自体は、無限ループを避けるために空のMAIL FROMを使用する。

アドレスが指定され、受け入れられると、DATAコマンドが送信され、実際のメッセージが続く。これは、最低限、「From」と「To」のヘッダーといくつかのテキストを含む。メッセージは単一のピリオドで終了し、サーバーは成功した引き渡しを示して応答する。

最終ホップのMTAは、ステータスコードを返す前にメールを受信LDAに転送する必要がある。これにより、配信できないメッセージを決して受け入れず、エラー通知が発生するのを防ぐ。「バックキャスト」メッセージは、MAIL FROMを偽装するスパマーと悪く相互作用する。明らかに偽のメッセージを、配信されやすく迷惑を引き起こすものに変えてしまう。

メール内のアドレスが、MAIL FROMおよびRCPT TO(エンベロープとも呼ばれる)のアドレスと一致する必要はない。最も一般的な原因は、転送されたメールだ。例えば、メーリングリストはエンベロープの宛先を各メンバーのメールアドレスに一致させるが、元の「From」と「To」のヘッダーはそのままにして、返信が正しく機能するようにする。エンベロープの送信元は通常、リスト管理者がエラー通知をチェックする場所を指すように変更される。

中間システムがヘッダーを変更しないわけではない。ほとんどの段階で、メッセージを受け取った場所を記録するために「Received」ヘッダーが追加される。

MTAからMTAへの通信には必須だが、SMTPはシステム全体で使用される。メールクライアントは異なるポートを使用してメールを送信するが、同じプロトコルを使用する。内部コンポーネント間(つまり、MTAからLDAへ)の通信は、密接に関連するLocal Mail Transfer Protocolを介して行われることが多い。主な違いは、受信者がメッセージキューを持たず、メールをすぐに配信するかエラーを返すかのどちらかであるという仮定だ。

サブミッションは通常、TLSを使用してポート465に接続し、パスワード(base64エンコード)を追加する。

AUTH PLAIN
334
AGh1bnRlcgBodW50ZXIy
235 2.7.0 Authentication successful

著しく異なる点は、MUAのフェッチであり、「プル」ベースで動作する。ここでは構文には触れないが、それほど複雑ではない。

...しかし、もしあなたが実際にGmailなどにメールを送信しようとして、これまでに書いた内容に基づいて送信しても、うまくいかないだろう。その一部は、Message-Idヘッダーのようなものを強制しているためだ。これは、受信MTAがメールを受け入れたが接続が切断された場合に、メッセージを重複排除するために使用される一意の識別子だ。これにより、送信者は後で再試行することになり、メッセージが重複する。

しかし、大きな部分は...

認証

基本的なSMTPは、すべての送信者が行儀が良いと信頼している。誰でも誰としてでもメールを送信できる。実際、多くのホストは、誰からのメールでもリレーして受け入れるように設定されており、誰かの通常のサーバーがダウンした場合の伝達手段として機能していた。

不正行為に対する最初の解決策は、犯人をインターネットから追放することだった...しかし、ネットワークが成長し、企業が関与し始めると、それはすぐに崩壊した。最初の記録されたスパムメールは1978年に送信され、1300万ドルのコンピュータを販売した。認証はスパムを防ぐことはできないが、不要な送信者をフィルタリングすることを可能にする。

送信者アドレスの検証は、同じホストがメールの送受信に使用される保証がないため、MXレコードを使用して行うことはできない。最も簡単な解決策は、送信者アドレスを別のDNSレコードに公開することだ。

@ TXT v=spf1 ip4:65.109.172.162 ip6:2a01:4f9:c011:841a:b01d::1 -all
; Roughly:
;   allow from 65.109.172.162
;   allow from 2a01:4f9:c011:841a:b01d::1
;   deny otherwise

しかし、それはメール帝国にとっては十分ではない。ビッグテックは、DNSレコード経由で公開される暗号鍵でメール本文に署名することも求めている。これには、メール送信にステップを追加する必要がある。通常はMTAのプラグインとしてだ。

ビッグテックをからかっているが、これは実際には賢明なポリシーだ。SPFはMAIL FROMしか検証できない。なぜなら、メールを転送すると送信元IPアドレスが変わるからだ。DKIM署名はメッセージに添付され、メッセージの元の送信者(ほとんどの場合ユーザーに表示される「From」アドレス)を検証するために使用できる。

しかし、これらはいずれもスパムを防ぐことはできない。なぜなら、スパマーは単にいくつかのTXTレコードを設定できるからだ。ビッグテックはまた、送信者のHELOホスト名が、フォワードおよびリバースDNSの両方を通じて、IPアドレスと一致することを要求する。これは、侵害されたデバイスがジャンクをばらまくのを防ぐのに役立つ。スマートテレビが意味のあるPTRレコードを持つ可能性は低く、もし持っていたとしても、そのホスト名はIPアドレスに戻らないだろう。

...残念ながら、このポリシーは、住宅用インターネット接続から直接メールを送信することを不可能にする。ただし、アドレスブロックを所有している場合を除く。もちろん、解決策は、メールをリレーするためにビッグテック企業にお金を払うことだ。これが気に入らない場合は、より寛容なルールを持つメールプロバイダーを見つけることだ。ビッグテックがその詐欺を継続できる唯一の理由は、5社程度がメールの99%を支配していることだ。

メッセージ

ここでSMTPは単純ではなくなる。配信された最も単純なメールを見てみよう。

Return-Path: <alex@there>
Delivered-To: bob@here
Received: from here
        by here with LMTP
        id bs05E10S7Go4VQMAHrglgg
        (envelope-from <alex@there>)
        for <bob@here>; Thu, 05 Nov 2026 05:21:33 +0000
DKIM-Filter: OpenDKIM Filter v2.11.0 here B05E67CD18
Received-SPF: None (mailfrom) identity=mailfrom; client-ip=313.33.33.337;
        helo=there; envelope-from=alex@there; receiver=here
Received: from there (unknown [313.33.333.337])
        by here (Postfix) with SMTP id B05E67CD18
        for <bob@here>; Thu, 05 Nov 2026 05:20:42 +0000 (UTC)
From: alex@there
To: bob@here

Hello, World!

ヘッダーの形式はHTTPヘッダーに表面上似ているが、行は78バイトを超えてはならない(CRLF行終端子を除く)。長すぎるヘッダーは分割され、新しく作成された行は前のヘッダーの継続であることを示すために空白でプレフィックスが付く。

メールソフトウェアは一般的にメッセージの先頭にヘッダーを付加するため、逆順に読むと役立つ。「From」と「To」は自己説明的だ。次に、「Received」ヘッダーには受信MTAからのメモが含まれる。送信者のHELO名、IPアドレス、RCPT TO、およびタイムスタンプが含まれる。

MTAはSPFとDKIMのチェックを実行したが、結果は空だった。署名はなく、MAIL FROMのホスト名は公開で解決できない。

LDAは別の「Received」ヘッダーを追加したが、あまり役立たない。より重要なのは、「Return-Path」に元のMAIL FROMアドレスを付加し、メッセージが配信されたメールボックスを記録したことだ。

しかし、本文は常にプレーンテキストではない。これはフォーマットを含むメールだ。

[...] 
MIME-Version: 1.0
Content-Type: multipart/alternative;
 boundary=----IX71FHL6PHA0538LS1WKT2W9SF7S8X
Content-Transfer-Encoding: 7bit

------IX71FHL6PHA0538LS1WKT2W9SF7S8X
Content-Type: text/plain;
 charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hello, World! I can do bold text!

------IX71FHL6PHA0538LS1WKT2W9SF7S8X
Content-Type: text/html;
 charset=utf-8
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html><html><body><div dir=3D"auto">Hello, world! I can do <b>bold<
/b> text</div></body></html>

------IX71FHL6PHA0538LS1WKT2W9SF7S8X--

そう、これはWebページだ!

しかし、すべてのメールクライアントがHTMLを理解できるわけではないため、メッセージにはプレーンテキストバージョンも含まれている。これはMIMEの「multipart」エンコーディング、この場合はmultipart/alternativeを使用して行われる。これは、すべてのバージョンが機能的に同等であることを示している。

MIMEのバージョン番号は1996年から1.0で固定されている。

区切り文字はランダムに選択された文字列であり、複数のマルチパートをエスケープなしでネストできる。メッセージの各セクションには独自のヘッダーがあり、この場合はquoted-printableエンコーディングで送信されていることを示している。これにより、MTAを怖いもの(7ビットASCII以外)にさらすことなく、メールメッセージに任意のバイトを含めることができる。SMTPは45年前のものであることを思い出してほしい。

quoted-printableでは、等号がエスケープ文字として使用される。それに続く2桁の16進数でそのバイトにデコードされる。改行に続く場合、両方の文字が削除される。これは、問題を引き起こす可能性のある長い行を分割するために使用される。

このメールでは、「=3D」はリテラルの等号になり、両方の行が結合される。メールで、約80バイトごとに余分な等号や1つか2つの文字が欠けているのを見たことがあるなら、壊れたquoted-printableデコードが原因であることが多い。

2番目の「content-transfer-encoding」はbase64で、添付画像のようなバイナリファイルに使用される。

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="5ZTNvId/H+rlk7Fr"
Content-Disposition: inline

--5ZTNvId/H+rlk7Fr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Check out this file:

--5ZTNvId/H+rlk7Fr
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="file.bin"
Content-Transfer-Encoding: base64

J7mtSdbQItOAi345nwaNkkTXrnDIRPA0DSwhbSAOwm2C/KoHjQIotY9lnJRMBRk9InQaHOxL
bb7DGd9EN6uRpjvCbox9xblAh3CxH7sl+YAkYcKw1V100RpBwMhgaXfUJBB3oRkLffgRwEyK
v9qFBLp9zZ+SiRJoRWbA4aZLexPhHZ35vFROVKYtiAeMlD1s15v3kPZvEADam0e45BoSaqmp
1S3z3b5wBIFHJUxQULD589MKaFx2Z2A+91pl/pbZWmZkzt55D/hZ05kjUUbXUnDnTYAQE2Gk
WnN+SnrQvfEO+Tz7AdrbLD1q2DgwWW+k0cVJLKjdwRxesGhAkQCZfHVrno6R4iXjTbInIbQv
hXzQiV840iUiUhk282WADd1ffJ0sot2Waf7XHLIE1lZVFQ3iGofYbw8pZlg3sb35AnIWPZKv
fbC6Yh95RV23R4K2NHeBX1rpl4bSSiftnD2RbsBzv7cgw/6M/Lj3O40NFGAaUC+J7TpAaXdi
tvlPsNQhMo8QRf/ub7WK42cPUlz1fKq1k1pzGN96YOsE5azMfF4vLANtbtbVmLIp2WmgBk0P
9IGMWy/xIAe0cOh+bqzru2+ojJGgx9uX4VSTP9BaTOwkVX5+rQfpp1qJodtHiO8sHw6Pg+Mg
WcpqQPC7118ccuT44cVpIRkwOSoJzsW++WM=

--5ZTNvId/H+rlk7Fr--

これがサイズ制限がしばしば期待外れになる理由だ。メールは添付ファイルより33%大きくなる。より効率的なエンコーディング(生のバイナリデータ)は一部のMTAでサポートされているが、経路のどこかでbase64に変換される必要があるかもしれない...それはDKIM署名を壊すことになる。

一般的に:

  • エンコーディングなし(「7ビット」)は、メッセージが短い行を持ち、低ビットASCIIに収まる場合に使用できる。しかし、「7ビット」は、すでにエンコードされたマルチパートコンテナのヌルエンコーディングとしてほとんど見られる。
  • メッセージの大部分がテキストだが、古いソフトウェアを壊す可能性のあるものがある場合は、quoted-printable。
  • バイナリデータの場合はBase64。

TLSについて

メールクライアントが使用するSSL/TLSは、ブラウザのものと実質的に同じだ。メールプロバイダーは認証局に行き、身元を証明し、証明書を取得する必要がある。アルゴリズムと暗号スイートは、それらが安全でない可能性がわずかでも示唆されると無効化される。

しかし、MTAは「信頼された」ネットワーク上で動作する...攻撃者がインターネットトラフィックにアクセスできないというよりは、もしアクセスできたとしても、ACMEチャレンジを通過して信頼された証明書を取得できる可能性があるということだ。

その結果、目標は主に受動的な盗聴から保護することだ。ほとんどのシステム管理者は、CAを扱うのを面倒に思い、自己署名証明書を使用する。(CAも良い実績があるわけではない。4)

メールのもう一つの奇妙な点は、MTAが別のTLSポートを使用しないことだ。ポート25へのすべての接続はプレーンテキストで開始され、その後送信者はSTARTTLSコマンドを発行し、接続をSSL/TLSライブラリに引き渡す。これは少しぎこちないが、サーバーが暗号化の使用を試み、サポートされていない場合にきれいにフォールバックできるようにする。

このアプローチはサブミッションにはあまり適していない。フォールバックがパスワードを漏洩する可能性があるからだ...共有ネットワーク上の悪意のあるユーザーや、詮索好きなISPはSTARTTLSコマンドを削除できる。この場合、専用のSSLサブミッションポートである465をデフォルトで使用するのが最善だ。

(このポートは実際には少し歴史があり、STARTTLSを支持して非推奨になった後、パスワードにオプションのSSLを使用するのが悪い考えだと気づいて再承認された。)

それで、どうなる?

メール関連のソフトウェアを書いたり、インフラストラクチャを実行したりしない限り、この情報のほとんどは非常に役に立たない。しかし、覚えておくと良いことがいくつかある。

基盤となるプロトコルは配信に5日間を許可しており、時にはそれ以上かかることもある。ユーザーは数秒での配信を期待しており、ほとんどのメールは少なくともある程度時間的制約があるため、一部のMTAはメッセージに時間がかかっている場合に遅延通知を送信するように設定されている。

受信者があなたを無視していると仮定する前に、あなたのプロバイダーがこれを行うかどうかを確認すると良いかもしれない。

メールはデジタルポストカードだ。

メッセージは複数のシステムでプレーンテキストで保存および転送される。ネットワークパス上の誰でもあなたのメールを読むことができる可能性がある。SSL/TLSは普遍的にサポートされているわけではなく、アクティブな攻撃者によって簡単に削除される可能性がある。

これはメールの本質的な部分だ。既存のクライアントを壊すことなく、強力な暗号化を追加する方法はない。プライバシーの保証が必要な場合は、送信前にメッセージを暗号化する必要があり、受信者自身がそれを復号する必要がある。PGPのような組み込みツールには注意すること。これらは通常、「返信全員」を暗号化せずに誤ってクリックすることを非常に容易にするだけでなく、件名行を公開するなどの他の欠点もある。

PGP関連

公開後、件名行を難読化すること(またはユーザーが入力した場合に警告すること)が、自己申告のプライバシーツールとしては完全に非現実的であると説明する人が複数いた。少なくとも私の目には、「暗号化メッセージング」とは、90%暗号化され10%プレーンテキストであることではなく、暗号化されていることを意味する。

否認性(deniability)と前方秘匿性(forward secrecy)の欠如は、メールのストアアンドフォワードアーキテクチャの制限として許容できるかもしれないが、デフォルトのプレーンテキストであり、件名行や添付ファイルを暗号化しようとしないのは悲劇のレシピだ。少なくとも通常のメールでは、人々はそれが暗号化されていないことを知っている。

「暗号化された」メールプロバイダーのほとんどはインチキだ。メッセージストアはメッセージを暗号化でき、カスタムMUAはそれらを復号できるが、MTAはプレーンテキストにアクセスする必要がある。その結果、「軍用グレードの暗号化」にもかかわらず、ほとんどの攻撃ベクトルに対してセキュリティはほとんど、あるいは全く提供されない。メールを修正する唯一の方法は、すべての人にエンドツーエンド暗号化プロトコルに切り替えることに同意させることだろう...しかし、メールの全体的なポイントは普遍的な互換性だ。暗号化メッセージングは存在するかもしれないが、暗号化されたメールは矛盾している。

最善の希望は、メッセージを詮索しないことができると信頼できるメールプロバイダーを見つけることだ。つまり、広告会社(Google)やLLMを強く推進している会社(Microsoft/Apple)ではないことだ。どちらのビジネスも、あなたのメッセージを読む強いインセンティブを生み出す。それでも、通信相手がプロバイダーによって詮索されていないことを願う必要がある。

さらに悪いことに、DKIM署名は、メッセージが数年前のものであり、明確な管理チェーンがない場合でも、メールがあなたのプロバイダーのサーバーから来たという生涯の証拠として機能する。これにより、漏洩、ハッキング、または詮索されたメールは、悪意のあるアクターが改ざんされていないことを簡単に証明できるため、恐喝材料として理想的になる。

このプロパティ、非否認性(non-repudiation)と呼ばれるものは、通常、プライベートメッセージングシステムには望ましくない。署名を避けることは、ビッグテックと相互運用したい場合は選択肢ではないが、プライベートキーを定期的にローテーションして公開することは可能だ。キーが公開される前に、署名はそれが正当であることを検証するために信頼できる。しかし、キーが公開されると、署名は誰でも偽造でき、遡って信頼性が損なわれる。

キーローテーションは一般的な慣行であるが、ほとんどのメールプロバイダーは古いプライベートキーを公開していないため、署名は依然として信頼できる(サービスがハッキングされた場合を除く)。公開するのに快適でないものをメールで送信することは避けるべきだ。

関連: