SiteKensa

DMARCレコードの書式エラー|複数レコード・pタグ・値の誤りを見分ける

公開日 更新日 DMARCメール独自ドメイン
DMARCレコードの5つの状態を壊れていない1つ(pタグの省略)と受信側に意図が伝わっていない4つ(書式崩れ・複数レコード・pの値の誤り・レポート送信先の形式)に分けて示す図

診断で「DMARCレコードの書式に問題があります」「pの値が不正です」「DMARCレコードが2本あります」「レポート送信先がmailto:形式ではありません」のいずれかが表示されることがあります。これらは、DMARCレコード自体が無い状態とは違います。_dmarc にレコードはすでに置いてありますが、受信側があなたの意図どおりに読み取れていません。

先に結論を書きます。

  • DMARCレコードがあることと意図どおりに動いていることは別です。当てはまる状態によって直し方が変わります
  • 1つだけ例外があります。p タグを書いていないだけなら、レコードは壊れていません。rua があれば p=none として動きます
  • 残り4つ(書式が崩れている・レコードが複数ある・p の値が違う・レポート送信先の形式)は、受信側にあなたの意図が伝わっていない状態です
  • 1本のレコードの中で v=DMARC1 の位置や値が違う場合だけ、レコード全体が無効になります。まずここを確認してください
  • いま何が適用されているかは、メール認証の診断で確認できます

この記事は、DMARCレコードをすでに追加したことがあり、診断で書式エラーや複数レコードの指摘を受けたものの、何をどう直せばよいか分からない方に向けて書いています。DMARCレコードをまだ追加していない場合は、先にDMARCを設定していないリスクと最初に置く設定を読んでください。

用語をここで揃えます。すでにご存じの場合は読み飛ばしてください。

用語 意味
タグ p=rua= のように、名前=値 の形で書く1つの指定
_dmarc DMARCレコードを置く決まりの名前。_dmarc.example.jp のように、ドメイン名の前に付けます
v レコードの種類を示すタグ。DMARCでは DMARC1 の1つだけが有効です
p 認証に失敗したメールを受信側にどう扱わせるかの指定。none / quarantine / reject
rua 認証結果の集計レポートを受け取るメールアドレス
ruf 認証に失敗した個別のメールについての詳細レポートを受け取るメールアドレス

5つの状態のうち直すのは4つです

まず自分のケースを選んでください。

いまの状態 動いているか 読む見出し
p タグを書いていない 動きます(rua があれば p=none として処理されます) pタグを書いていなくてもレコードは壊れていません
_dmarc にTXTレコードが2本以上ある 動いていません(どちらも無効) レコードが複数あるとどちらも無効になります
書式が崩れている v タグの誤りならレコード全体が無効。そのほかは受信側によって扱いが分かれます vタグの位置や大文字・小文字をまず確認します / そのほかの書式の乱れも書式エラーとして表示されます
p の値が none / quarantine / reject のいずれでもない 動いていません pの値を間違えると書いていないのと同じ扱いになります
rua / rufmailto: 以外の形式 動いていません(対応していない宛先は無視されます) レポート送信先はmailto:形式にします

レコードを書いたはずなのに診断が「DMARCレコードが設定されていません」と表示する場合、この一覧のどれにも当てはまっていない可能性があります。次の見出しで扱います。

pタグを書いていなくてもレコードは壊れていません

p タグは、レコードの中で最も重要な指定に見えますが、書いていないからといってレコード全体が無効になるわけではありません。RFC 9989 セクション4.7 の p タグの定義は、次のように書いています。

(plain-text; RECOMMENDED for DMARC Policy Records) ... If this tag is not present in an otherwise syntactically valid DMARC Policy Record, then the record is treated as if it included "p=none" (see Section 4.10.1).

(plain-text、DMARCポリシーレコードにはRECOMMENDED。それ以外の点で構文上有効なDMARCポリシーレコードにこのタグが無い場合、そのレコードは「p=none」を含んでいたものとして扱われる。セクション4.10.1を参照)

p は「RECOMMENDED」であって「REQUIRED」ではありません。書いていない場合の扱いは、セクション4.10.1がさらに詳しく定めています。

If a retrieved DMARC Policy Record does not contain a valid "p" tag ... then: If a "rua" tag is present and contains at least one syntactically valid reporting URI, the Mail Receiver MUST act as if a record containing "p=none" was retrieved and continue processing. Otherwise, the Mail Receiver applies no DMARC processing to this message.

(取得したDMARCポリシーレコードが有効な「p」タグを含まない場合、次のようにする。「rua」タグがあり、構文上有効な報告先URIを少なくとも1つ含んでいれば、メール受信者は「p=none」を含むレコードを取得したものとして扱い、処理を続けなければならない。そうでなければ、メール受信者はこのメッセージにDMARCの処理を適用しない)

結果は rua の状態で2つに分かれます。

rua に構文上有効な送信先があるか 受信側の扱い
ある p=none として処理します
ない このメッセージにDMARCの判定を一切行いません

つまり p を省略していても rua さえ書いてあれば、なりすましメールの検出自体は動きます(対処は行われません)。rua も無い場合は、DMARCを何も設定していないのと同じ状態です。この違いは、書いていないタグの帰結として見落としやすい箇所です。

書いていなくても壊れてはいませんが、意図を明示することをおすすめします。省略した場合、あとで振り返ったとき、書き忘れなのか意図した設定なのかを自分で判断できなくなります。

置く値は送信ドメインかどうかで変わります。

状態 置く値
メールを送っている、またはこれから送る予定がある p=none から始めます
Null MXを設定済み、またはSPFで送信しないと宣言済み 最初から p=reject で問題ありません

送信しているドメインの場合、次の形にします。

種類: TXT
ホスト名: _dmarc
値: v=DMARC1; p=none; rua=mailto:{報告の宛先}

{報告の宛先} は、あなたが決めるメールアドレスです。ここは推測で埋められない値なので、そのままコピーせず実際に受け取れるアドレスに置き換えてください。rua の書き方や複数宛先の指定はDMARCレポートを受け取る設定で扱っています。

送信しないと宣言済みのドメインの場合は、次の形にします。

種類: TXT
ホスト名: _dmarc
値: v=DMARC1; p=reject

正規のメールを送っていないドメインでは、認証から漏れて困る送信元がそもそも無いため、段階を踏まずに p=reject から始めて問題ありません。

レコードが複数あるとどちらも無効になります

ここでいう「複数」は、1本のレコードの中でタグを2回書くこと(次の見出しで扱います)とは別です。_dmarc の名前にTXTレコード自体が2本以上公開されている状態を指します。

まず、ドメインを診断するでレコードの本数を確認できます。自分で確認する場合は、次のコマンドで _dmarc のTXTレコードを引きます。

dig TXT _dmarc.example.jp +short
nslookup -type=TXT _dmarc.example.jp

v=DMARC1 で始まる行が2つ以上出てきたら、複数のレコードが公開されている状態です。

なぜどちらも無効になるかは、RFC 9989 セクション4.10(DNS Tree Walkの手順)のステップ2とステップ6が定めています。

Records that do not start with a "v" tag that identifies the current version of DMARC are discarded. If multiple DMARC Policy Records are returned for a single target, they are all discarded.

(現行版のDMARCを示す「v」タグで始まらないレコードは破棄される。単一の対象に対して複数のDMARCポリシーレコードが返された場合、それらはすべて破棄される)

受信側は、どちらの内容が正しいかを選びません。2本とも破棄し、DMARCレコードが無いのと同じ扱いにします。片方だけを見て「正しい方が使われるはず」と考えるのは誤りです。

直すには、1本に統合します。既存のレコードそれぞれに ruapct など他のタグが入っている場合、統合の際にどちらかの指定を落とさないよう両方の内容を確認してください。統合したら、片方のレコードを削除します。

vタグの位置や大文字・小文字をまず確認します

DMARCレコードの先頭は v=DMARC1 である必要があります。RFC 9989 セクション4.7 の v タグの定義は、次のように定めています。

v: Version (plain-text; REQUIRED). ... This tag MUST be the first tag in the list. The tag value is case sensitive, and the only possible value is "DMARC1". If the tag is not the first in the list, the tag is absent, or the value is not "DMARC1", then the entire record MUST be ignored.

(v: バージョン(plain-text、REQUIRED)。このタグはリストの最初のタグでなければならない。タグの値は大文字小文字を区別し、可能な値は「DMARC1」のみである。タグがリストの最初になければ、タグが存在しなければ、または値が「DMARC1」でなければ、レコード全体を無視しなければならない)

v の位置か値が違うとレコード全体が無効になります。これはレコードを書いていないのと同じ結末で、他のタグをどれだけ正しく書いていても関係ありません。位置の誤りと大文字小文字の違いで診断の反応は変わります。

v=DMARC1 が最初のタグになっていない場合、または値が別物になっている場合、診断は「DMARCレコードが設定されていません」と表示します。レコードを書いたはずなのにこの表示が出たら、v=DMARC1 が先頭のタグになっているかを確認してください(p=reject; v=DMARC1 のように順序を入れ替えていないか)。

大文字と小文字の違いは、これとは扱いが分かれます。本サイトの診断は現在この違いを検出していません。v=dmarc1 のように小文字で書いてしまっていても他のタグが正しければ問題なしと表示されることがあります。RFCどおりに動く受信側はこの値を無視するため、診断の表示と実際の扱いがずれます。大文字小文字は、dig の出力を自分で確認してください。

そのほかの書式の乱れも書式エラーとして表示されます

v=DMARC1 が正しい位置にある場合でも、そのあとのタグの区切りが崩れていると診断に「DMARCレコードの書式に問題があります」と表示されます。よくあるのは次の3つです。

  • セミコロンが抜けている(v=DMARC1 p=none のようにタグの間の区切りが無い)
  • = を含まない断片が混ざっている(コピーの際に文字が欠けた場合など)
  • 同じタグを1本のレコードの中で2回書いている(p=none; p=reject のように)

RFC 9989 セクション4.8(Formal Definition)は、タグの区切りをセミコロンと定めたうえで次のように書いています。

Unknown tags MUST be ignored. Syntax errors in the remainder of the record MUST be discarded in favor of default values (if any) or ignored outright.

(未知のタグは無視しなければならない。レコードの残りの部分にある構文エラーは、既定値があればそれを採用して破棄し、なければそのまま無視しなければならない)

v タグの誤りとは違い、これらの乱れは受信側の実装によって扱いが分かれます。仕様のうえでは崩れた部分だけが無視されて他のタグは生きる場合もありえますが、その保証はありません。同じタグを2回書いた場合の扱いについては、RFC 9989 に明示的な規定がなく、受信側によって解釈が割れる可能性があります。順序としては、v タグの誤りを最優先で直し、そのうえでこれらの乱れも直しておくことをおすすめします。

なお、レコードに独自のタグや将来追加されるかもしれないタグを書いてもそれだけでレコード全体が壊れることはありません。上に引用したとおり、登録されていないタグは無視されるだけです(セクション4.7も同じ規定を持ちます)。

pの値を間違えると書いていないのと同じ扱いになります

p に指定できる値は none / quarantine / reject の3つだけです。

意味
none 認証に失敗しても扱いを変えるよう依頼しません
quarantine 疑わしいものとして扱うよう依頼します(迷惑メールフォルダへの振り分けが典型です)
reject ドメインの使い方として正しくないものとして扱うよう依頼します

p=monitor のような入力ミスや、値の前後に余計な文字が入っている場合、この3つのいずれとも一致しません。このとき何が起きるかは、p を書いていない場合と同じ規定(セクション4.10.1、上で引用したもの)が適用されます。値が不正な p は「有効な p タグを含まない」場合として扱われるためです。

つまり rua があれば p=none として処理され、無ければDMARCの判定自体が行われません。せっかく p=reject のつもりで書いていても綴りを間違えた時点でその指示は使われません。p を省略した場合と違い、値を間違えた場合は明示的に何かを指定しようとした結果なので、診断はこの状態を要修正として扱います。

直すには、none / quarantine / reject のいずれか正しい値に書き換えます。rua など他のタグはそのまま残してかまいません。

レポート送信先はmailto:形式にします

ruarufmailto: 以外の形式を指定している場合です。RFC 9989 セクション4.7 の rua タグの定義は、次のように書いています。

Any valid URI can be specified. A Mail Receiver that sends aggregate feedback reports MUST implement support for a "mailto:" URI ... URIs involving schemes not supported by Mail Receivers MUST be ignored.

(任意の有効なURIを指定できる。集計フィードバックレポートを送信するメール受信者は「mailto:」URIへの対応を実装しなければならない。メール受信者が対応していない形式のURIは無視しなければならない)

仕様のうえでは mailto: 以外のURIを書くこと自体は禁止されていませんが、対応が必須なのは mailto: だけです。対応していない形式は受信側で無視されるため、実質的にレポートが届きません。mailto: に書き換えてください。

詳しい確認手順と外部ドメイン宛の認可レコードなど関連する原因はDMARCレポートが届かない原因にまとめています。

直したあとに確認する

レコードを直したら、公開DNSに意図した値が1本だけ出ているかを確認します。ドメインを診断するか、次のコマンドで確認できます。

dig TXT _dmarc.example.jp +short
nslookup -type=TXT _dmarc.example.jp

直したはずの内容が反映されていない場合は、反映待ちの可能性があります。再帰リゾルバが変更前の値をキャッシュしていることがあるため、DNSが反映されないときの確認方法で権威サーバーの値と比べて切り分けてください。

DNS上の値が正しくなったら、自分宛にテストメールを送り、届いたメールの Authentication-Results ヘッダーで dmarc=pass が記録されているかも確認してください。ヘッダーの読み方は独自ドメインのメールが迷惑メールに入る原因で扱っています。DNSにレコードがあることと実際のメールがDMARCの判定を通ることは別です。

自分のドメインで確認する

いまのDMARCレコードがこの記事のどの状態に当てはまるかは、メール認証の診断にドメインを入力すると確認できます。書式に問題がある場合はその内容を表示します。レコードが複数ある場合は本数を表示します。

書式は正しいものの pctt の指定について参考情報が出た場合は、この記事の対象ではありません。pct はRFC 9989でタグの一覧から外れており、扱いはDMARCのpctタグは廃止されましたで説明しています。

まずは全体を診断してみましょう

専門知識がなくてもいまの設定状況と具体的な対処方法をわかりやすく確認できます。

ドメイン設定を診断する

利用中のDNS事業者が分かっているなら事業者別の設定手順から直接進めます。