本文へ移動
QKQuickKitEN

SPF の DNS 参照回数(10 回の上限)と permerror の切り分け

include を足したら SPF が permerror になった、一部の送信元だけ失敗する——RFC 7208 の参照回数の数え方、手で数える手順、減らし方と限界をまとめます。

一次資料とコマンドの確認日:

SPF のレコードに include: を 1 つ足したら、受信側の認証結果が spf=permerror になった。あるいは、一部の送信元からのメールだけ SPF が失敗する。こうした場合にまず確かめたいのが、RFC 7208 が定める DNS 参照回数の上限です。

上限のルール(RFC 7208 §4.6.4)

  • 評価の途中で DNS を問い合わせる項目は include、a、mx、ptr、exists の各メカニズムと、redirect 修飾子です。SPF の実装はこれらの合計を 10 個までに制限しなければならず(MUST)、超えると permerror を返します。
  • all、ip4、ip6、exp は評価中に DNS を問い合わせないので、数えません。ただし exp は、結果が fail になった後で説明文を得るために、指定したドメインの TXT を問い合わせることがあります(RFC 7208 §4.6.4、§6.2)。この問い合わせは 10 個の上限には含まれません。
  • 数えるのは評価全体です。include: や redirect= の先にあるレコードの項目も、たどった分だけ合計に加わります。
  • さらに、1 つの mx の評価で問い合わせるアドレスレコード(A / AAAA)が 10 を超えると、その mx は permerror になります。
  • 応答が空(NOERROR で回答 0 件)または存在しない名前(NXDOMAIN)だった参照を「void lookup」と呼び、実装は 2 回までに制限すべき(SHOULD)とされています。削除済みのサービスへの include: が残っていると、これに当たることがあります。

例:数え方

次のような構成を考えます。ドメインとアドレスは例示用です(ドメインは RFC 2606、IPv4 は RFC 5737、IPv6 は RFC 3849 の文書用の範囲)。各行の TXT の中身は、そのまま SPF レコード解析に貼り付けられます。

example.com.            TXT "v=spf1 mx include:_spf.mail.example.net include:spf.crm.example.org a:relay.example.com -all"
_spf.mail.example.net.  TXT "v=spf1 include:_nb1.mail.example.net include:_nb2.mail.example.net include:_nb3.mail.example.net ~all"
_nb1.mail.example.net.  TXT "v=spf1 ip4:192.0.2.0/26 ip6:2001:db8:1::/48 ~all"
_nb2.mail.example.net.  TXT "v=spf1 ip4:192.0.2.64/26 ip6:2001:db8:2::/48 ~all"
_nb3.mail.example.net.  TXT "v=spf1 ip4:192.0.2.128/26 ip6:2001:db8:3::/48 ~all"
spf.crm.example.org.    TXT "v=spf1 include:spf1.crm.example.org include:spf2.crm.example.org ip4:198.51.100.0/24 ~all"
spf1.crm.example.org.   TXT "v=spf1 ip4:203.0.113.0/25 ~all"
spf2.crm.example.org.   TXT "v=spf1 ip4:203.0.113.128/25 ~all"
レコード参照を伴う項目数
example.commx、include×2、a4
_spf.mail.example.netinclude×33
spf.crm.example.orginclude×22
_nb1〜_nb3.mail.example.net、spf1 / spf2.crm.example.orgなし(ip4 / ip6 だけ)0
どれにも一致しない送信元で、最後の -all まで評価した場合の合計9

9 は、上限の対象になる項目を評価の順にたどった数です。送信元のアドレスが途中で一致すると評価はそこで終わるので、実際に数える項目はこれより少なくなります(たとえば _nb1 の範囲から送られ、mx には一致しないメールなら、mx、include:_spf.mail.example.net、include:_nb1.mail.example.net の 3 個で pass になります)。また、これは DNS の問い合わせの回数そのものではありません(mx の後には MX ごとのアドレスの問い合わせが続きます)。

ここに、include: を 2 つ持つ別サービスのレコードを include: で足すと、合計は 9 + 1 + 2 = 12 になり、上限を超えます。

一部の送信元だけ失敗する理由

メカニズムは左から順に評価され、一致した時点で評価が終わります(RFC 7208 §4.6.2)。そのため、前のほうの mx や最初の include: で一致する送信元は 10 回に届く前に pass になり、後ろの include: で一致する送信元や、どれにも一致しない送信元だけが上限に達して permerror になります。「設定は通るのに、特定のサービスから送ったメールだけ失敗する」という症状はこれで説明できることがあります。

手で数える手順

  1. 自分のドメインの TXT レコードを取得し、v=spf1 で始まるものを探します。v=spf1 のレコードが 2 つ以上あると、それだけで permerror です(RFC 7208 §4.5)。
    dig +short TXT example.com
  2. レコードを SPF レコード解析 に貼り付け、このレコードに書かれた参照を伴う項目の数を確認します。複数の文字列に分かれた TXT もそのまま貼り付けられます。
  3. include: と redirect= の先のドメインについて、1〜2 を繰り返して合計します。同じドメインを複数回たどる場合も、その回数だけ数えます。
  4. 応答が空・NXDOMAIN のドメインがあれば、void lookup として別に数えます。

QuickKit は DNS を問い合わせないため、SPF レコード解析の数は、貼り付けた 1 レコード分だけです。評価全体の合計は、たどった各レコードの数を足して求めます。

減らし方

  • 使っていないサービスの include: を削除します。void lookup の原因にもなります。
  • ptr は公開すべきでない(SHOULD NOT)とされています(RFC 7208 §5.5)。残っていれば削除を検討します。
  • 自分で管理していて変わらないアドレスなら、a や mx を ip4: / ip6: に置き換えると数が減ります。
  • サービスの include: を IP アドレスの列に展開する方法(いわゆる flattening)は、そのサービスがアドレスを変えたときに気づけず、正当なメールが失敗する原因になります。採る場合は、変更を追う仕組みとセットにしてください。
  • SPF が確認するのは主に SMTP の MAIL FROM(エンベロープ送信者)のドメインです(RFC 7208 §2.4)。サービスごとに MAIL FROM に別のサブドメインを使えば、そのサービスのための include: をそのサブドメインのレコードに分けられます。DMARC を使っている場合は、分けた後も整合(alignment)が取れるか確認してください。

限界と注意

  • 上限に達するかどうかは、送信元のアドレスと評価の順序で変わります。最悪の場合(どれにも一致しない送信元)の合計を 10 以下にしておくのが確実です。
  • DNS の応答が遅い・失敗する場合は temperror になり得ます。参照回数とは別の原因です。
  • このガイドは RFC 7208 の規則の説明です。受信側の実際の判定やログの表示は、受信システムで確認してください。

参考資料(一次資料)