SPF 10회 조회 한도 초과(permerror) 해결
SPF의 10회 DNS 조회 한도를 넘겨 permerror가 날 때 원인 진단과 평탄화로 해결하는 법.
메일을 보내는데 수신측 로그에 Received-SPF: permerror 또는 "too many DNS lookups"라는 문구가 보인다면, SPF 레코드를 평가하는 과정에서 DNS 조회 횟수가 RFC 7208이 정한 10회 한도를 넘었다는 뜻입니다. 이 상태가 되면 수신 서버는 SPF 결과를 신뢰할 수 없는 영구 오류(permanent error)로 처리하고, 그 결과 정상적인 메일조차 인증에 실패할 수 있습니다.
가장 까다로운 점은 이 한도가 중첩된 include까지 모두 합산된다는 것입니다. 내 SPF 레코드는 include 한두 개로 짧아 보여도, 그 안에 또 다른 include가 들어 있으면 실제 조회 수는 순식간에 10을 넘깁니다. 지금 내 도메인이 몇 회를 쓰는지부터 SPF 조회 횟수 계산기로 확인한 뒤 아래 절차로 줄여 나가는 것이 가장 빠릅니다.
10회 한도가 무엇이고 왜 존재하나
SPF는 v=spf1 레코드를 보고 발신 IP가 허용 목록에 있는지 판정합니다. 이때 일부 메커니즘은 판정을 위해 DNS를 추가로 조회해야 합니다. RFC 7208 §4.6.4는 이런 DNS 조회를 요구하는 메커니즘의 총합을 10회로 제한합니다. 한도가 없다면 악의적인 또는 잘못 구성된 SPF가 수신 서버에 수십~수백 건의 DNS 질의를 유발하는 증폭(amplification) 공격 수단이 될 수 있기 때문입니다.
중요한 점은 이 10회가 실제로 발생한 질의 수가 아니라 "조회를 유발하는 메커니즘의 개수"로 센다는 것입니다. include:example.com 하나가 1회로 카운트되고, 그 include가 가리키는 레코드 안에 또 include·a·mx가 있으면 그것들도 전부 같은 10회 예산에서 차감됩니다. 별도로 mx와 ptr은 응답이 여러 호스트를 반환할 때 추가 질의를 만들 수 있는데, MX가 반환하는 호스트가 10개를 넘으면 그 자체로 permerror가 됩니다.
어떤 메커니즘이 카운트되나 (대조표)
한도 안에 들어가는 것과 들어가지 않는 것을 정확히 구분하는 것이 진단의 핵심입니다. 다음 표로 정리합니다.
| 메커니즘 / 수정자 | 10회에 포함? | 설명 |
|---|---|---|
include | 예 (가장 흔한 원인) | 참조한 레코드 내부의 조회까지 재귀적으로 합산 |
a | 예 | 도메인의 A/AAAA를 조회 |
mx | 예 | MX 1회 + 반환 호스트 각각 추가 질의(호스트 10개 초과 시 즉시 permerror) |
ptr | 예 (사용 비권장) | 느리고 신뢰성 낮아 RFC가 사용 자제 권고 |
exists | 예 | 매크로 기반 A 조회 1회 |
redirect= | 예 | 대상 레코드로 평가가 넘어가며 그쪽 조회도 합산 |
ip4 / ip6 | 아니오 | IP가 직접 적혀 있어 DNS 조회 불필요 (평탄화의 핵심) |
all | 아니오 | -all/~all 등 종결자, 조회 없음 |
내 도메인이 몇 회 쓰는지 세는 법
손으로 세려면 레코드를 한 줄씩 따라가며 include 안에 들어 있는 레코드까지 모두 펼쳐야 하는데, 공급자 레코드는 자주 바뀌어 수작업은 금방 어긋납니다. 가장 확실한 방법은 SPF 조회 횟수 계산기로 중첩 include를 전부 펼쳐 합계를 받는 것입니다. 원본 레코드를 그대로 보고 싶다면 SPF 조회 도구에서 published 레코드를 먼저 확인하세요.
합산 예시: 11회로 permerror가 나는 경우
짧아 보이는 레코드가 어떻게 한도를 넘기는지 실제 합산으로 보겠습니다. 도메인 레코드가 다음과 같다고 합시다.
v=spf1 include:_spf.google.com include:spf.protection.outlook.com include:sendgrid.net include:mailgun.org a mx -all
include:_spf.google.com= 1, 내부에 다시 3개의 include → +3 (소계 4)include:spf.protection.outlook.com= 1, 내부 include 1개 → +1 (소계 6)include:sendgrid.net= 1 (소계 7)include:mailgun.org= 1 (소계 8)a= 1 (소계 9)mx= 1 (소계 10)
여기까지 정확히 10인데, 위 google include 내부가 사례에 따라 include를 하나 더 품으면 합계가 11이 되어 permerror가 발생합니다. 실무에서 흔한 시나리오로, "아무것도 안 바꿨는데 어느 날 갑자기 SPF가 깨졌다"는 신고는 대부분 공급자가 자기 include 내부 레코드를 늘렸기 때문입니다.
한도를 줄이는 3가지 방법
- 안 쓰는 include 제거. 예전에 썼다가 해지한 마케팅·트랜잭션 메일 서비스의 include가 그대로 남아 있는 경우가 많습니다. 실제로 메일을 보내지 않는 공급자는 즉시 삭제하세요. 가장 위험 없이 한도를 회복하는 방법입니다.
- SPF 평탄화(flattening). include가 최종적으로 가리키는 IP 범위를 직접 조회해
ip4:/ip6:로 바꿔 넣는 방식입니다.ip4/ip6는 조회를 유발하지 않으므로 10회 예산을 전혀 쓰지 않습니다. 단점은 공급자가 IP를 바꾸면 내 레코드를 직접 갱신해야 한다는 점이므로, IP가 잘 안 바뀌는 자체 인프라에 적합합니다. - 발신 경로 통합. 같은 일을 하는 메일 공급자가 여럿이면 하나로 합치고, 서브도메인별로 발송 책임을 나눠(예: 마케팅은
m.example.com) 도메인당 include 수를 분산하세요. 각 도메인이 독립적으로 10회 예산을 가집니다.
마지막으로, permerror는 단순히 SPF 한 줄의 문제로 끝나지 않습니다. DMARC는 SPF/DKIM 중 하나라도 정렬되어 통과해야 하는데, SPF가 permerror로 무너지면 DKIM이 받쳐주지 못하는 메일은 DMARC까지 실패해 격리·반송될 수 있습니다. SPF를 정리한 뒤에는 DMARC 레코드 생성기로 정책과 리포트(rua)를 함께 점검해 두면 회귀를 빠르게 잡을 수 있습니다.