SPFのDNS参照回数が10回を超える原因と直し方|PermErrorの数え方

この記事の末尾には、広告 (紹介リンク) が含まれます。リンクをたどって申し込みがあった場合、運営者が紹介料を受け取ることがあります。記事の内容は、紹介料の有無で変えていません。
SPFの診断結果に「DNS参照回数が上限を超えています」と表示されることがあります。これは、SPFレコードが無いのとも書き間違えているのとも違います。レコードの中身自体は、正しくても参照している先をすべてたどって数えるとDNSへの問い合わせが10回を超えてしまっている状態です。
この記事ではこの参照回数の数え方と超えてしまったときの直し方を扱います。「送信・受信のどちらが問題か分からない」という段階であれば、先に独自ドメインのメールが届かない原因の切り分けを確認してください。
診断結果が「DNS参照回数が上限を超えています」と出たら
SPFを診断すると次のような形式で結果が返ります。
DNS参照回数が上限を超えています (13回 / 上限10回)
example.jp → include:_spf.google.com
_spf.google.com → include:_netblocks.google.com
_spf.google.com → include:_netblocks2.google.com
example.jp → include:spf.protection.outlook.com
spf.protection.outlook.com → include:spf-a.outlook.com
...
上の値は、この記事用の例です。実際に表示される回数と参照先は、ドメインごとのSPFレコードによって、変わります。
最初の行が結論、その下が「どの参照で回数を消費したか」という証跡です。数字だけでなく、この証跡を見れば、どのincludeが原因になっているかを自分で判断できます。
見ての通り、この状態は、「SPFレコードが設定されていない」とはまったく別です。レコードは、存在し、構文も正しいのに評価の途中で参照回数の上限に達し、受信側がそこで評価を打ち切っています。
SPF fail・PermError・DMARCの関係
SPFの評価結果にはいくつかの種類があり、PermErrorは、そのひとつです(RFC 7208 セクション2.6)。
- fail は、「送信元が、その識別子においてこのドメインの利用を認可されていないという明示的な判定」です(RFC 7208 セクション2.6.4)
- PermError は、「公開されているレコードを正しく解釈できなかった」という状態です(RFC 7208 セクション2.6.7)
failは、判定した結果として、送信元を拒否している状態で、PermErrorは、判定そのものを完了できずに終わっている状態です。原因が違うため、直し方も違います。
DMARCを設定している場合への影響は、次のとおりです。
PermErrorは、公開されたレコードを正しく解釈できなかったという結果で(RFC 7208 セクション2.6.7)、passではありません。そのためSPF経由ではDMARCの認証を成功させられません。ただし、Fromアドレスのドメインと整合したDKIMの署名が成功していれば、DMARCは、成功します(検証に成功した署名の d= のドメインが識別子になります。RFC 9989 セクション4.4.1)。DMARCがSPFから得る識別子は、MAIL FROMのドメインがSPFで検証されたときのものです(RFC 9989 セクション4.4.2)。DMARCは、SPFかDKIMの識別子のどちらか一方がFromドメインと整合していれば通る仕組みです(RFC 9989 セクション5.3.5)。SPFがPermErrorになっているからといって、DMARCの判定も連動して失敗するとは限りません。
受信メールのヘッダーで実際の判定結果を確認したい場合は、Authentication-Resultsヘッダーにspf=permerrorやdmarc=passのように記載されます。診断ツールが確認できるのは公開されているDNSの設定までで、実際に届いたメールがどう判定されたかは、受け取った本人がヘッダーを見るまで分かりません。
PermErrorになる原因を切り分ける
PermErrorには参照回数の超過以外にもいくつかの原因があります。この記事で深く扱うのは1行目の「DNS参照回数の超過」だけです。
| 原因 | 根拠 |
|---|---|
| DNS参照を起こす機構と修飾子(include・a・mx・ptr・exists・redirect)の数が10を超えている | RFC 7208 セクション4.6.4(MUST) |
| 応答が空、または存在しないドメインへの参照(void lookup)が2回を超えている。この上限はSHOULDで、実装が変えてよいとされています | RFC 7208 セクション4.6.4 |
| SPFレコードが2本以上ある | RFC 7208 セクション4.5 |
| レコードの構文に誤りがある | RFC 7208 セクション4.6 |
redirectまたはexp修飾子が同じレコード内に2つ以上ある |
RFC 7208 セクション6 |
redirectの参照先にSPFレコードが無い |
RFC 7208 セクション6.1 |
10個の上限は、「MUST」、2回の空応答の上限は、「SHOULD」という違いがあります(RFC 7208 セクション4.6.4)。前者は、実装が必ず守らなければならない上限、後者は、実装側で設定可能な推奨値という位置づけの違いです。本サイトの診断ツールは、どちらも固定値(10回、2回)で判定しています。
この記事は、参照回数が10回を超えた場合を扱います。ほかの原因については別の記事があります。応答が空の参照が2回を超えている場合はSPF void lookupの推奨上限は2件、レコードの構文に誤りがある場合はSPFレコードの書式エラーを直すを確認してください。
以降は、参照回数の超過に絞って説明します。
DNS参照回数10回の対象になる項
SPFレコードの中には参照回数を消費する項と消費しない項があります(RFC 7208 セクション4.6.4)。
The following terms cause DNS queries: the "include", "a", "mx", "ptr", and "exists" mechanisms, and the "redirect" modifier.
日本語にするとDNS参照を発生させるのはinclude・a・mx・ptr・existsの5つの機構とredirect修飾子です。
| 参照を消費する | 消費しない |
|---|---|
include / a / mx / ptr / exists / redirect= |
ip4: / ip6: / all |
ip4:やip6:は、IPアドレスをそのまま書くだけなのでDNSへの問い合わせが発生しません。一方、includeのようにドメイン名を指定する項は、そのドメインのSPFレコードを取得しに行くため参照を消費します。
ここで、本サイトの診断ツールが数えている回数の性質について、明記しておきます。
数えているのはレコードに書かれた全ての項を評価した場合の最大値です。実際にメールが送信されたときの評価は、途中でallにマッチした時点で打ち切られるため、実際に消費される参照は、これより少ないことがあります。逆に言えば、この最大値が10回以内に収まっていれば実際の評価でも上限を超えることはありません。
また、a・mx・ptr・existsは、「1項につき1参照」として、数えており、参照先のドメインが持つAレコードやMXレコードの件数までは展開していません。これらの機構を使っている場合、実際の参照回数は、ここで示す数より多くなる可能性があります。
応答が空の参照(void lookup)についても同様の注意が必要です。本サイトの診断ツールが数えているのは次の2つです。
include・redirectで辿った先のTXTが1件も返らなかった場合a・mx・existsの参照先の名前が存在しなかった場合
一方、a・mx・existsの参照先が「名前はあるがAレコードが無い」状態とptr機構は数えていません。前者は送信元のIPアドレスが分からないとAとAAAAのどちらを引くべきか決められないため、後者は接続してきたIPアドレスが必要でDNSだけを見る診断では引けないためです。どちらも実際の受信側より少なく出る方向の判断になります。
この上限は、参照回数10回の上限とは規範の強さが違います。詳しくはSPF void lookupの推奨上限は2件で扱っています。
includeの入れ子を含めて数える
参照回数を数えるときに見落としやすいのは見た目の行数ではなく、includeの中でさらに発生する参照まで含めた合計だという点です。
自分のSPFレコードが次の1行だけだったとします。
v=spf1 include:_spf.google.com ~all
この状態ではincludeが1つなので、参照は、1回に見えます。しかし_spf.google.com自身のSPFレコードが内部でさらに複数のincludeを使っていれば、その分もすべて合計に加算されます。自分のレコードを何も変更していなくても参照先のサービスが内部構成を変えて参照が増えれば、ある日突然この上限に達することがあります。
redirectを使っている場合は、もう1点注意が必要です。SPFレコードにall機構がある場合、redirect修飾子は、無視されます(RFC 7208 セクション6.1)。ただし、本サイトの診断ツールでは無視されると分かっているredirectであっても参照回数のカウント自体は、先に加算してから展開をスキップしています。実際の評価では効果を持たないredirectが、参照回数の集計には影響するという、食い違いが起こり得ます。レコードにallとredirectが両方書かれている場合は、この点を踏まえて数えてください。allに付ける修飾子の選び方はSPFレコードのall修飾子の違いで扱っています。
どの参照が上限を使っているか、証跡で確認する
診断結果には合計回数だけでなく、どのドメインのどの項が参照を消費したかという一覧(証跡)が付きます。冒頭の例で示した
example.jp → include:_spf.google.com
_spf.google.com → include:_netblocks.google.com
という形式がそれです。左側が参照元、右側がその時点で消費した項を表します。この一覧を上から順に確認し、まだ使っているサービスかどうかを1つずつ照合してください。
自動で判定できないケースもあります。%{i}のようなマクロを含む項は、送信元のIPアドレスが分からないと展開できないため、参照回数としては、カウントしますが、その先の中身までは追っていません。このような項がレコードに含まれている場合、証跡だけでは全体像を確認しきれないことがあります。
手動で数え直す方法
診断ツールを使わずに digコマンドで同じことを手作業で確認できます。
dig +short txt example.jp
まず自分のドメインのSPFレコードを取得し、include:で指定されているドメインを書き出します。次に、その各ドメインに対して、同じコマンドを実行します。
dig +short txt _spf.google.com
これを includeが出てこなくなるまで再帰的に繰り返し、出てきたinclude・a・mx・ptr・exists・redirect=の数を合計すれば、参照回数を自分で検算できます。レコードの階層が深い場合は、この作業自体が大変になりますが、診断ツールが返す証跡と照らし合わせて、数え方に食い違いがないかを確認する手段として、使えます。
安全な直し方
参照回数を減らす方向で直します。
- 使っていないサービスの
includeを削除する。契約を解約したサービスのincludeが残っていることがあります - 送信元のIPアドレスが固定されているサービスに限り、
include:をip4:に置き換える。ただしサービス側がIPアドレスを変更した場合にメールが届かなくなるため、変更の通知を受け取れる契約になっているサービスに限ります - 利用している送信サービスの数自体を見直す
SPFレコードを2本に分けるのは解決になりません。SPFレコードは、複数が選ばれる状態にしてはならず(RFC 7208 セクション3.2、MUST NOT)、2本あるとその時点で受信側は、PermErrorと判定します(同 セクション4.5)。参照回数の上限を回避する目的でレコードを分割すると状況が悪化します。
送信サービスを1つ追加すると参照回数も増えます。現在の回数が上限に近い場合、次にサービスを追加するタイミングで超過する可能性があることも踏まえて整理してください。
自動で修正値を出さない理由
本サイトの診断ツールは、他の項目では設定に貼り付けられる値を自動生成しますが、参照回数の超過については、その値を出しません。
理由は、どのincludeが現在も実際に使われている送信サービスかを公開されているDNSの情報だけから判断できないためです。使われていないように見えるincludeを自動で削除する値を提示すると実は稼働中の送信元を誤って除外してしまう可能性があります。実際に使っているサービスかどうかは、契約状況を知っている運用者にしか判断できません。上の証跡を見ながら1つずつ照合して削除の判断をしてください。
修正後に再診断する
レコードを修正したら、再度診断して参照回数が上限内に収まっているかを確認してください。
修正した直後は、DNSの反映を待っている再帰リゾルバが残っている場合があります。再診断で古い値のまま表示される場合は、設定を変更する前にまず反映状況を確認してください。
まずは全体を診断してみましょう
専門知識がなくてもいまの設定状況と具体的な対処方法をわかりやすく確認できます。
ドメイン設定を診断する利用中のDNS事業者が分かっているなら事業者別の設定手順から直接進めます。