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.com | mx、include×2、a | 4 |
_spf.mail.example.net | include×3 | 3 |
spf.crm.example.org | include×2 | 2 |
_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 になります。「設定は通るのに、特定のサービスから送ったメールだけ失敗する」という症状はこれで説明できることがあります。
手で数える手順
- 自分のドメインの TXT レコードを取得し、
v=spf1で始まるものを探します。v=spf1のレコードが 2 つ以上あると、それだけでpermerrorです(RFC 7208 §4.5)。dig +short TXT example.com - レコードを SPF レコード解析 に貼り付け、このレコードに書かれた参照を伴う項目の数を確認します。複数の文字列に分かれた TXT もそのまま貼り付けられます。
include:とredirect=の先のドメインについて、1〜2 を繰り返して合計します。同じドメインを複数回たどる場合も、その回数だけ数えます。- 応答が空・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 の規則の説明です。受信側の実際の判定やログの表示は、受信システムで確認してください。