DevKitLab Logo DevKitLab
メール / SPF / DKIM / DMARC / DNS

SPF・DKIM・DMARC はそれぞれ何をしているのか

3 つのレコード、3 つの別々の役割。SPF と DKIM が何を検証するのか、なぜアライメントこそが DMARC の要なのか、そして SPF に通ったのに DMARC で失敗する理由。

スクリーンショットが回ってくる。請求書のメール、差出人欄には自社の名前、そして自社のものではない支払いリンク。送信サーバーのログを確認しても、何も出ていない。このメールは自社のインフラに一度も触れていません。相手は差出人欄に自社のドメインを打ち込んだだけ——封筒の差出人欄に好きな住所を書くのと同じことです。

SPF・DKIM・DMARC はこの穴をふさぐために存在します。三つはいつもひと息に並べて呼ばれるので、同じ考えの三つのバージョンのように見えてしまう。その印象こそが混乱のもとです。三つは重複してもいないし、互いの代わりにもなりません。それぞれ答えている問いが違い、しかも受信者が実際に目にするアドレスを守っているのは三つめだけです。

誰も教えてくれない「二つの差出人」

レコードの話に入る前に、その土台にある仕組みをひとつ押さえておく必要があります。理解しづらい DMARC の結果は、ほぼすべてここに行き着くからです。メールには差出人アドレスが二つあり、しかも一致している必要がない。

  • エンベロープ送信者MAIL FROM とも呼ばれ、配送後は Return-Path ヘッダーとして残ります。SMTP レベルの値で、送信サーバーがハンドシェイク時に申告するアドレスであり、バウンスの戻り先です。受信者の目には入りません。
  • From ヘッダー。メールクライアントに表示されるほうです。人間が読み、それを根拠に信用するアドレスです。

この二つは独立したフィールドです。マーケティング配信基盤から正規に送ったメールなら、エンベロープ送信者は bounces.mailer-provider.com、From ヘッダーは yourcompany.com というのが普通で、偽装でも何でもありません。しかしこの隙間こそが攻撃者の狙いどころでもあります。自分が管理するドメインで認証を通し、自分のものではないドメインを表示する、というわけです。

この区別を覚えておいてください。SPF だけではなりすましを止められない理由も、DMARC がアライメントという仕組みを用意しなければならなかった理由も、ここにあります。

SPF:どのサーバーがこのドメインで送ってよいか

SPF(Sender Policy Framework、RFC 7208)は、あるドメインの代理で送信してよい IP アドレスの一覧を DNS の TXT レコードとして公開します。

v=spf1 include:_spf.google.com include:sendgrid.net ip4:198.51.100.25 -all

左から読みます。Google Workspace のレンジからのメールは通る、SendGrid のレンジからのメールも通る、指定したそのサーバーからも通る、そして最後の -all が「それ以外はすべて失敗」と宣言します。受信側は接続元 IP を持ってきて一覧を順に照合し、結果を返します。

最後のメカニズムは、見た目の短さに反して重い意味を持ちます。

末尾名称意味
-allfail未認可。本来こうすべき厳格な設定
~allsoftfail未認可だが受け取ってマークする。移行期の設定
?allneutral態度を示さない。公開しないのとほぼ変わらない
+allpass全員が認可済み。これは公開しないこと

実運用では三つの制限が効いてきます。第一に、SPF には DNS 参照を伴う項が 10 個までという上限があります(RFC 7208 §4.6.4)。includeamxptrexistsredirect がそれぞれ 1 回を消費し、include は再帰的に消費します。SaaS を 4〜5 社使っていれば、気づかないうちに上限を超えます。10 を超えた評価は PermError を返し、これは DMARC から見れば SPF の失敗と同じ扱いです。レコード自体はどこも壊れて見えないのに、一部の送信経路でだけ機能しなくなります。

第二に、こちらのほうが根本的です。SPF が認証しているのはエンベロープ送信者であって、From ヘッダーではありません。 攻撃者は使い捨てドメインを取得し、そこに何の問題もない SPF レコードを公開し、自前のサーバーから送信すれば SPF に通ります。それでいて From ヘッダーには自社名が入る。SPF は仕事を正しく果たしています。読み手が見るアドレスを守ることは、そもそも SPF の仕事ではないのです。

第三に、現場で厄介なのがこれです。SPF は転送で壊れます。 受信者が自動転送を設定していると、転送サーバーは自分の IP から中継するため、その IP はあなたのレコードに載っていません。落ち度がなくても SPF は失敗します。

自分の予算がどう展開されているか、include の中の include が食っている分も含めて見たいときは、ドメインを SPF/DMARC チェッカーに入れてください。ツリー全体をたどり、参照を消費する項をすべて数え上げます。この合計は判定ではなく上限として読んでください。評価は最初に一致したメカニズムで止まるため、10 を超えるというのは「10 回目より先まで到達する送信経路が失敗する」であって、「送るメールがすべて失敗する」ではありません。

DKIM:メールと一緒に旅をする署名

DKIM(DomainKeys Identified Mail、RFC 6376)は、メールそのものに暗号署名を添付します。 送信サーバーが秘密鍵でヘッダー群と本文に署名し、DKIM-Signature: ヘッダーを付けます。公開鍵は DNS に置かれ、受信側がそれを取得して検証します。

署名ヘッダーは、鍵のありかを自分で明示しています。

DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=selector1;
  h=from:to:subject:date; bh=...; b=...

d= が署名ドメイン、s=セレクター です。この二つが DNS 名 selector1._domainkey.example.com を指し、そこに公開鍵があります。鍵の場所をセレクターで切り分ける設計のおかげで、一つのドメインが同時に複数の鍵を運用できます。プロバイダーごとに一つ、あるいはローテーション中の新旧二つ、といった具合です。

証明がメールの内部を一緒に移動するので、DKIM は中継に耐えます。署名済みのメールを転送しても、中身が変わっていなければ署名は検証を通ります。裏を返せば——DKIM は改変に弱い。フッターを追記したり件名を書き換えたりするメーリングリストは、通過させた署名を無効にしてしまいます。

署名を読むときに知っておきたい点が二つあります。h= はどのヘッダーに署名したかを列挙しており、From を含まない署名はほぼ無価値です。攻撃者は署名に触れないまま表示上の差出人を差し替えられてしまいます。もう一つは l= で、本文に長さの上限を設けて先頭 N バイトだけに署名します。それ以降に追記された内容は署名されず、気づかれもしません。

ドメインを調べるときに覚えておきたい非対称性がもう一つ。あるドメインが公開しているセレクターを DNS から列挙する方法は存在しません。 既知のセレクターを引くことはできますが、一覧にすることはできない。DKIM の状態を報告するツールは、よくある名前を総当たりしているか、あなたに尋ねているかのどちらかです。つまり「鍵が見つからない」は常に「試した名前がどれも一致しなかった」の意味であり、「このドメインに DKIM がない」ではありません。

DMARC:二つの検証を目に見える差出人に結びつける

ここでようやく前の二つが役に立ちます。SPF が認証するのはエンベロープ、DKIM が認証するのは署名ドメイン。どちらも From ヘッダーと関係がある必要はありません。 そして受信者が読むのは From ヘッダーだけです。

DMARC(RFC 9989)は、アライメントという規則でこの隙間をふさぎます。SPF や DKIM の成功は、それが認証したドメインが From ヘッダーのドメインと一致している場合にのみ意味を持つ、という規則です。

メールが DMARC を通過するのは、次のどちらかが成り立つときです。

  • SPF が成功し、かつエンベロープ送信者のドメインが From ドメインとアラインしている
  • DKIM が成功し、かつ署名の d= ドメインが From ドメインとアラインしている

片方で十分です。転送で SPF が壊れた後も DKIM だけでメールが通り続けるのは、このためです。

これで冒頭の攻撃は成立しなくなります。攻撃者の使い捨てドメインは相変わらず SPF に通りますが、そのドメインは From ヘッダーとアラインしないため、DMARC には何も寄与しません。アラインした成功が一つもなければ DMARC は失敗し、あとは公開したポリシーが受信側の対応を決めます。

アライメントには二段階あり、aspfadkim で別々に設定します。

  • relaxedr、既定):組織ドメインが一致すればよい。mail.example.comexample.com とアラインします。
  • stricts):完全一致が必要。mail.example.comexample.comアラインしません

ほとんどの場合は relaxed が正しい既定値です。strict は意識して選ぶ価値があります。サブドメインを使った悪用を一括で排除できる一方、認証されたドメインが From ヘッダーのドメインのサブドメインになっている形のメールはすべて落ちます。そして SaaS 経由の送信はまさにその形をしています。

組織ドメインの決め方が変わりました。 RFC 9989 は、RFC 7489 のように Public Suffix List を参照するのではなく、DNS ツリーウォーク——名前を順に短くしながらポリシーレコードを問い合わせる方式——で組織ドメインを決定します。普通の company.com ならどちらの方式でも答えは同じなので、大半のドメインには何の影響もありません。効いてくるのは端のケースです。複数ラベルのサフィックスや、名前空間の複数階層にポリシーを公開している組織などがそれにあたります。

ポリシー本体は _dmarc.yourdomain.com の TXT レコードです。

v=DMARC1; p=reject; sp=reject; np=reject; adkim=r; aspf=r;
  rua=mailto:dmarc-reports@yourdomain.com
タグ役割
pアラインしないメールの扱い。nonequarantinereject
sp既存サブドメインのポリシー。省略時は p に従う
npDNS に存在しないサブドメインのポリシー。省略時は sp、次に p
adkim / aspfアライメントの段階。r または s、既定は r
tテストモード。t=y は公開ポリシーをそのまま適用しないよう求め、一段弱い扱いが想定される
foどの失敗をレポートするか。01ds
rua集約レポートの送り先
ruf個別の失敗レポートの送り先

意識して足す価値がいちばん高いのは np です。攻撃者は、あなたが作った覚えのないサブドメインを好んで捏造します。billing.yourcompany.com は DNS に何のレコードもないので、実際のメール設定では何も縛れません。np=reject はこの経路を一行でふさぎ、しかも実際に使っているサブドメインには一切影響しません。

一方 t は最も読み違えられているタグです。t=y は「ポリシーを無視してよい」という意味ではありません。 公開したポリシーをそのまま適用しないよう求めるものです。RFC 9989 では一段弱い扱いが想定され、rejectquarantinequarantinenone になりますが、最終的な扱いは受信側が決めます。これは展開用のブレーキであり、t=y を付けた p=reject はタグを外すまで隔離を要請しています。

2026 年より前に DMARC を学んだなら、現行仕様と突き合わせてください。 DMARC は 2026 年 5 月に改訂され、RFC 9989(プロトコル本体)・RFC 9990(集約レポート)・RFC 9991(失敗レポート)として公開され、あわせて RFC 7489 を廃止し、DMARC を初めて標準化過程の文書へ格上げしました。この改訂で pctrfri の三つのタグが削除されpct が担っていた役割は t に引き継がれました。また p が必須から推奨に変わりました。p がない場合、または pspnp が無効な場合は、有効な rua があるときだけ p=none として処理され、なければ受信側は DMARC 処理を行いません。既存の v=DMARC1 レコードはそのまま動きます。受信側は削除されたタグを無視するだけで、レコードごと拒否したりはしません。次に DNS を触るときに整理すれば十分です。

つなげて見る:一通のメールが判定される流れ

受信側は、届いた一通に対しておおよそ次を実行します。

  1. From ヘッダーのドメインを読む。 以降の判断はすべてこれを基準にします。
  2. エンベロープ送信者のドメインに対して SPF を評価する。 接続元 IP と照合し、成否とどのドメインを検証したかを記録します。
  3. DKIM 署名を検証する。 成否と各署名の d= を記録します。
  4. アライメントを判定する。 SPF が検証したドメインは From ドメインと一致するか。成功した d= のいずれかが一致するか。
  5. アラインした成功が一つでもあれば DMARC 成功。 ドメイン利用は認証されますが、配送とフィルタリングは受信側の通常の規則に従います。
  6. 一つもなければ DMARC 失敗。 送信者が要請する p(または spnp)を参照します。t=y なら一段弱い扱いが想定されますが、最終的な処理は受信側が決めます。

意外な結果はすべて手順 4 で生まれます。バグを疑わせるあの結果もここで説明がつきます。spf=passdmarc=fail が同時に出るのは矛盾ではありません。 これは「あるプロバイダー経由で送っているが、アライメントの設定を一度もしていない」典型的な兆候です。エンベロープ送信者はプロバイダーのバウンス用ドメインで、SPF はそのドメインで成功し、それをあなたの From ヘッダーに結びつけるものが何もない。直し方は、そのプロバイダーで d=yourdomain.com の DKIM 署名を設定することです。それこそがアライメント側の検証が探しているものです。

自分の設定を読む

確認すべき方向は二つあり、必要な証拠が違います。

外向き——何を公開しているか。 三つのレコードはいずれも公開 DNS なので、誰でも読めますし、当然あなたも読めます。ドメインを SPF/DMARC チェッカーに通してください。10 回の予算に照らして SPF ツリーを展開し、DMARC レコードをタグ単位で読み、外部のレポート送信先があなたに許可を出しているかを検証し、よくある DKIM セレクターを探索します。解釈を加えない生のレコードが見たいときは、DNS 検索ツールyourdomain.com_dmarc.yourdomain.com の TXT を直接引けます。

内向き——ある一通に実際に何が起きたか。 公開されたレコードが教えてくれるのは規則であって、特定のメールへの判定ではありません。判定はヘッダーにあります。受信サーバーが調べた結果をそこに書き残しています。

Authentication-Results: mx.example.net;
  spf=pass smtp.mailfrom=bounces.provider.com;
  dkim=pass header.d=yourcompany.com;
  dmarc=pass header.from=yourcompany.com

この数行を丁寧に読むと、モデル全体が一か所に現れます。SPF はプロバイダーのドメインで成功し、DKIM はあなたのドメインで成功し、DKIM の d=header.from とアラインしているので DMARC が成功しています。任意のメールをソース形式で保存し、ヘッダーをメールヘッダー解析ツールに貼れば、この分解が得られます。処理は完全にブラウザー内で行われるので、メールが手元の端末から出ることはありません。Received の連鎖やなりすましの痕跡まで含めた読み方は、メールヘッダーの読み方で扱っています。

要点だけ

  • SPF は「この IP はこのドメインの代理で送ってよいか」に答えます。検証対象はエンベロープ送信者で受信者には見えず、DNS 参照は 10 回まで、転送で壊れます。
  • DKIM は「このメールはそのドメインが公開した鍵で署名されたか」に答えます。メールとともに移動し、転送に耐え、改変に弱く、セレクターは列挙できません。
  • DMARC は「その SPF や DKIM の成功は、読み手が実際に見ているドメインのものか」に答えます。それがアライメントであり、三つの中で From ヘッダーを守るのはこれだけです。あわせて失敗時の扱いを受信側に伝え、レポートを届けてくれます。

三つとも必要で、しかもアラインしている必要があります。DMARC のない SPF と DKIM は誰も見ないアドレスを認証しているだけですし、アラインして成功する SPF や DKIM を伴わない DMARC は、自社のメールを拒否させるだけです。

部品がそろったところで、次の問いは運用の話になります。何もしないポリシーから p=reject まで、自社の請求書メールをブラックホールに落とさずにどう進めるか。これはプロトコルではなく展開手順の問題であり、その段階的な進め方はp=none から p=reject へで扱っています。