このページは、dkim2.com(英語)のページを日本語に翻訳した非公式の日本語版です。内容に食い違いがある場合は、英語の原文が優先されます。デモサーバ、バリデータ、検証ツールは dkim2.com 上で提供されています。
ステータス: 作業中
DKIM2 は、IETF のDKIM ワーキンググループで策定が進められています。現在も活発に更新されている Internet-Draft であり、正式な標準ではありません。詳細は今後変更される可能性があります。
現在の DKIM では分からないこと
DKIM 署名が証明するのは、あるドメインがメッセージの何らかの版に署名した、という事実だけです。DMARC や ARC を組み合わせても、次の 3 点は確かめられません。
- 誰宛てのメッセージだったのか。 有効な署名があっても、あなたが正当な宛先だったことの証明にはなりません。そのため、正しく署名されたメッセージが奪取され、何百万もの他のアドレスにリプレイ(再送)されても、認証に通り続け、元の署名者の評判に便乗できてしまいます。
- バウンスがどこへ行くのか。 メッセージのリターンパスには、そのメッセージを一度も取り扱っていないドメインを指定できます。そのため、バウンス、不正利用の報告、配達通知を信頼することも、送信元までたどることもできません。
- 途中で何が変更されたのか。 転送サービスやメーリングリストがメッセージを編集すると、署名は単に壊れてしまいます。件名やフッターの無害な書き換えなのか、悪意ある第三者による全面的な差し替えなのかを区別する方法がありません。
DKIM2 はどう解決するか
DKIM2 は、配送経路上のすべてのホップに責任を負わせます。各ホップは次のことを行います。
- メッセージを送り先に結び付けます — 次のホップと受信者がそのホップ自身の署名の中に含まれるため、署名済みのメッセージを別の場所へリプレイすることはできません。(誰宛てか)
- 行った変更を記録します。元に戻せる手順(レシピ)として記録するため、次のホップはその変更を取り消し、それ以前のすべての署名を再検証できます。(何が変更されたか)
- 制御メッセージを前のホップへ返送することを約束します。妥当な期間にわたって返送を引き受けることで、バウンスや不正利用の報告に、信頼できる戻りの経路を与えます。(バウンスがどこへ行くか)
この仕組みは、2 つのメカニズムで成り立っています。1 つはMessage-Instance(MI)ヘッダで、各ホップにおけるメッセージのハッシュによるスナップショットです。もう 1 つは連鎖する DKIM2-Signature ヘッダで、各ホップが現在のスナップショットとそれ以前のすべての署名の両方に署名することで、作成者から受信者までを結ぶ、改ざんを検知できるチェーンを形成します。
この設計の根拠は、DKIM2 motivation draft にまとめられています。
実装とデモ
dkim2.com では、稼働中の DKIM2 デモサーバが運用されています。Python、Perl、Go、C による 4 つの独立した実装が、プロジェクトのリポジトリ内で相互運用されています。dkim2.com 上の 2 つのメーリングリスト管理ソフトウェアは、メールを転送する際に DKIM2 で署名します。
これらのいずれかのリストに登録すると、DKIM2 署名付きのリストメールを受信でき、リストによる各種の変更がどのように記録されるかを確認できます。
- test@mailman.dkim2.com — 件名プレフィックスとフッター
- test-subject-only@mailman.dkim2.com — 件名プレフィックスのみ
- test-body-only@mailman.dkim2.com — フッターのみ
- test-passthrough@mailman.dkim2.com — 変更なし
- dkim2stock@mailman.dkim2.com — 修正を加えていない Mailman の動作を、Postfix の milter 経由で署名 (ガイド)
- test@sympa.dkim2.com — Sympa
その他の DKIM2 実装
DKIM2 は、複数の場所で独立して開発が進められています。以下は、dkim2.com のデモサーバ以外で確認されている取り組みです。
| 実装 | 作者 | 言語 | 概要 |
|---|---|---|---|
| croessner/dkim2 | Christian Rößner | Go | dkim2d デーモン、milter、Exim の local_scan。署名と検証の両方を行います。Apache-2.0 |
| go.turscar.ie/dkim2 | Steve Atkins | Go | ライブラリと、dkim2sign、dkim2verify、dkim2explain の各コマンドラインツール。BSD-2-Clause |
| turscar/dkim2tests | Steve Atkins | — | 適合性テストベクタ — このプロジェクトのすべての検証実装が実行対象とするテスト一式。BSD-2-Clause |
| mail-auth | Stalwart Labs | Rust | ライブラリ。Ed25519 と RSA による署名とチェーン検証に対応し、1 つの署名の中に複数のセレクタを持てます。Apache-2.0 または MIT |
| SocketLabs DKIM2 verify | SocketLabs | ホスト型 | ブラウザおよび JSON API で利用できる検証サービス。dkim2.net からもアクセスできます |
| dkim2.eu | 運営者の記載なし | ホスト型 | 独自の実装一覧を備えた、バリデータ兼解説サイト |
2026 年 8 月時点の調査に基づきます。ここに掲載すべき DKIM2 実装に取り組んでいる方、またはご自身の実装についての誤りに気付いた方は、ぜひお知らせください。
試してみる: リフレクタアドレス
dkim2.com のアドレスを使うと、DKIM2 の動作をエンドツーエンドで確認できます。種類は 3 つあります。送ったメッセージを下記の所定の変換を加えて送り返すリフレクト用が 6 つ、あなた宛てに新しいメッセージを発信するものが 3 つ(新しいメッセージの発信)、バウンスと配送通知を実演するものが 2 つです(バウンスと配送通知)。
たとえばリファレンス実装から、DKIM2 署名付きのメッセージを reflector-*@dkim2.com のアドレスへ送ってください。下表のモードに従って変換された返信が届きます。返信に署名が付くかどうかは、そのメッセージがどのように認証されたかによって決まります(返信に署名が付く場合を参照)。署名の有無にかかわらず、返信には、何が起きたかを説明する Authentication-Results ヘッダと X-DKIM2-Reflector ヘッダが含まれます。返信をバリデータに貼り付けると、結果を確認できます。
| アドレス | 動作 | 期待される結果 |
|---|---|---|
reflector-raw@dkim2.com |
変更のないメッセージに再署名します | チェーンが問題なく検証されます |
reflector-subject@dkim2.com |
件名の先頭に [DKIM2] を付加します |
検証に成功します。変更は元に戻せるため、元の件名が復元されます |
reflector-body@dkim2.com |
本文の末尾にフッター行を追加します | 検証に成功します。変更は元に戻せるため、元の本文が復元されます |
reflector-both@dkim2.com |
件名プレフィックスと本文フッターの両方 | 検証に成功します。両方の変更が元に戻せます |
reflector-redacted@dkim2.com |
本文を変更し、元に戻せない変更として記録します
(r={"b":null}) |
draft -09 では PERMERROR(「null レシピがある」)になります。元の本文を復元して確認することができないため、検証を完了できません。受け入れるかどうかはローカルポリシー次第です |
reflector-damage@dkim2.com |
署名した後に本文を改変します | 本文ハッシュの検証が失敗します — 改ざん検知が働いている例です |
注: body / both のフッターは、生のメッセージ本文の末尾に追加されます。multipart/* のメッセージでは、MIME のエピローグ(終端バウンダリの後ろ)に置かれるため、ほとんどのメールクライアントでは表示されません。ただし、生のバイト列には存在し、本文ハッシュの対象となり、Message-Instance のレシピにも記録されます(そのため、変更は引き続き検証でき、元に戻せます)。単純な text/plain のメッセージでは、フッターが表示されます。
返信に署名が付く場合
リフレクタが自身の dkim2.com のチェーンリンクを追加するのは、そのメッセージを保証できる場合に限られます。
- あなたのメッセージがすでに検証済みの DKIM2 チェーンを持っていた場合 — 返信はそのチェーンを継続します。
- あなたのメッセージに DKIM2 チェーンはなく、有効な DKIM1 署名があり、それが
From:ドメインと整合していた場合 — 返信は DKIM1 → DKIM2 ブリッジとして署名されます。 - どちらでもない場合 — 返信は署名なしで返ります(モードごとの変換は適用されます)。
メッセージを変更するすべてのモード(subject、body、both、redacted)では、返信に署名が付くかどうかにかかわらず、変更を記録する Message-Instance が追加されます。
返信されたメッセージで確認するヘッダ
| ヘッダ | 分かること |
|---|---|
X-DKIM2-Reflector |
リフレクタによる要約です。mode、確認した判定結果(auth = DKIM2、dkim1)、署名の根拠(basis = dkim2/dkim1/none)、そして signed が含まれます。 |
Authentication-Results |
リフレクタが根拠とした dkim2= の結果と、(ブリッジが適用された場合は)dkim=pass header.d= の結果です。 |
DKIM2-Signature |
返信に署名が付いた場合にのみ存在します — チェーンにおけるリフレクタのリンクです。 |
Message-Instance |
リフレクタによる変更を記録した m= のスナップショットです(変更を行うモードで存在します)。 |
DKIM-Signature(従来の DKIM1) |
すべての返信には、通常の DKIM1 署名も付きます(d=dkim2.com。brand アドレスでは、d=<your-domain> の署名がさらに 1 つ付きます)。これにより、デモメールが実際の運用メールのように扱われます。 |
新しいメッセージの発信
3 つのアドレスは、あなたのメッセージを返すのではなく、まったく新しい DKIM2 メッセージを発信して、あなたに送ります。dkim2.com と整合した送信元から送信されるため、返信は DMARC に合格し、受信トレイに届きます。
reflector-fresh@dkim2.com
最もシンプルな有効な DKIM2 メッセージを生成します。Message-Instance が 1 つ(m=1)、dkim2.com の DKIM2-Signature が 1 つで、転送チェーンはありません。これに加えて、対応する dkim2.com の DKIM1 署名も付きます。送信元は <fresh@dkim2.com>、宛先はあなたです。バリデータに貼り付けると、クリーンな署名 1 つとインスタンス 1 つを確認できます。
reflector-brand@dkim2.com — ブランド委任
ブランドに代わって、自身の識別情報を表に出さずに送信するメール配信プラットフォーム(ESP)をモデル化したものです。DNS レコードを 1 つ設定するだけで署名鍵を dkim2.com に委任でき、その結果、あなたのドメインとして署名されたまったく新しいメッセージが返されます。
- 1 つの Message-Instance に 2 つの DKIM2-Signature —
i=1はあなたのドメイン(委任された鍵)、i=2はdkim2.comで、管理の連鎖(chain of custody)を形成します。 - 2 つの従来型 DKIM1 署名 —
d=<your-domain>(同じ委任された鍵)とd=dkim2.com— 実際の ESP の署名方法そのものです。 - 見える
From:はdkim2demo@<your-domain>、To:はあなたです。dkim2.comは、読み手に見えるヘッダには現れず、署名とエンベロープの中にだけ存在します。
委任された d=<your-domain> の DKIM1 が From: ドメインと整合するため、メッセージは DMARC に合格して受信トレイに届きます。これは、Mailchimp や SendGrid などのプラットフォームが、現在ブランドに代わって送信している方法と同じです。(<your-domain> には、ご自身のドメイン名を入れてください。)
セットアップ — CNAME を 1 つ公開します(あなたのドメインの DNS に):
dkim2test._domainkey.<your-domain>. CNAME dkim2test._domainkey.dkim2.com.
この 1 つの委任で、DKIM2 のチェーン署名と DKIM1 署名の両方がまかなわれます。つまり、dkim2.com が保持する 1 つの鍵を、あなたのドメインが使用を許可する形です。その後、そのドメインのアドレスから
reflector-brand@dkim2.com
にメールを送り、返信をバリデータに貼り付けて、2 つの DKIM2 署名がどちらも検証される様子を確認してください。
CNAME が設定され(かつ伝播し)終わるまでは、このアドレスは、委任の設定方法を説明する、reflector-fresh 形式の簡素なメッセージを返信します。
reflector-brand-nd@dkim2.com — nd= によるブランド委任
reflector-brand と同じブランド委任ですが、i=1 のブランドのホップは、mf=/rt= ではなく、nd=(「次のドメイン」、架空のホップの形式、draft §12.3)によるエンコードを使います。最初のリンクは、エンベロープの経路ではなく、次に署名するドメインを指名します。チェーンは引き続き検証されます — i=1 の nd= が、i=2 の d=(dkim2.com)と一致します。セットアップは reflector-brand と同じ、CNAME 1 つです。返信をバリデータに貼り付けて、nd= のリンクが検証されることを確認してください。
バウンスと配送通知
2 つのアドレスは、DKIM2 が配送状況通知(DSN)、つまり MTA がメッセージを配送できないときに送るバウンスをどのように扱うかを示します。仕様では、DKIM2 の DSN はそれ自体が通常の DKIM2 メッセージです。エンベロープは MAIL FROM <> で、最上位のメッセージに固有の Message-Instance と DKIM2-Signature を持ち、失敗したメッセージが記録したリターンパス宛てに送られます。
reflector-dsn@dkim2.com — DKIM2 署名付きの DSN
あなたのメッセージを受け付け、そのメッセージに対する、新しく署名された DSN を返します。元のメッセージを message/rfc822 パートとして埋め込んだ multipart/report で、Message-Instance 1 つと dkim2.com の DKIM2-Signature 1 つを自身で持ちます。クリーンな 1 ホップの DKIM2 メッセージです(あなたのチェーンの継続ではありません)。DKIM2 署名付きで届いたかどうかにかかわらず、すべてのメッセージをバウンスします。返信をバリデータに貼り付けると、DSN が新しい 1 ホップのメッセージとして検証される様子を確認できます。
reflector-delayedbounce@dkim2.com — MTA が発生させるバウンス
上記のすべてのアドレスとは異なり、これはリフレクタによる変換ではありません。このアドレスは SMTP プロンプトで受理され(250 が返るため、送信セッションは正常に完了します)、その後の配送で失敗します。そのため、このバウンスは本物の遅延バウンスであり、セッションが終わった後に、実際の遅延失敗とまったく同じように、Postfix 自身のバウンス生成機能(bounce(8))によって非同期に生成されます。送信側の DKIM2 milter は、そのバウンスを送り出す際に、新しい DKIM2 メッセージ(固有の Message-Instance と DKIM2-Signature、MAIL FROM <>)として署名します。署名されたバウンスはそれ自体が有効な DKIM2 メッセージであり、検証に成功します。これは、リフレクタのコードではなく MTA が生成する、メールサーバ自身のバウンスにも DKIM2 署名を付けられることを示しています。
(運用上の要件が 1 つあります。milter が署名した後で、MTA がメッセージを再エンコードしてはなりません。署名を壊してしまう 8bit→7bit の書き換えを防ぐため、disable_mime_output_conversion を設定しています。仕様の「Preventing Transport Conversions」を参照してください。)
さらに詳しく
- DKIM2 メッセージを検証する — メールを貼り付けると、レベルごとの内訳が分かります
- ブラウザで DKIM2 メッセージを検証する — クライアントサイドで動作する独立した検証ツール(サーバへの往復なし)
- 自分で DKIM2 のリストホストを運用する — Mailman 3 または Sympa を使う Postfix 向けのインストールガイド
- 標準の Mailman 向けの DKIM2 — 修正していない Mailman 3 の、選択したリスト向け。milter と Postfix のルーティングだけで構成します
- IETF DKIM ワーキンググループ
- DKIM2 仕様(Internet-Draft)
- GitHub のソースとリファレンス実装