Синтаксис записей SPF: механизмы, макросы и лимиты DNS по стандарту RFC 7208
Запись SPF (Sender Policy Framework — инфраструктура политики отправителя) представляет собой стандарт аутентификации электронной почты, позволяющий владельцу доменного имени публично указать список серверов и IP-адресов, имеющих право отправлять письма от его имени. Опубликованный в апреле 2014 года стандарт RFC 7208 строго регламентирует грамматику, порядок обработки и системные ограничения этих записей.
Нарушение даже одного правила синтаксиса или превышение лимита в 10 DNS-запросов мгновенно приводит к статусу постоянной ошибки (PermError). В результате почтовые серверы получателей (такие как Gmail, Яндекс или Microsoft 365) перестают доверять письмам домена и отправляют их в папку «Спам» либо отклоняют вовсе. Чтобы поддерживать надежную доставляемость почты, системным администраторам и разработчикам необходимо понимать внутреннюю логику и ограничения SPF.
Грамматика и анатомия SPF-записи
Запись SPF публикуется исключительно как текстовая DNS-запись типа TXT. Она состоит из трех обязательных компонентов: версии, списка механизмов проверки и опциональных модификаторов:
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all
Правила синтаксиса требуют соблюдения строгих норм:
- Версионный тег
v=spf1: обязан стоять в самом начале. Если запись начинается, например, сv=spf10, парсер получателя полностью проигнорирует ее. - Разделители: все элементы разделяются строго одинарными пробелами. Использование пробела после двоеточия (например,
include: example.com) делает всю запись невалидной. - Единственность записи: доменное имя обязано иметь ровно одну запись, начинающуюся с
v=spf1. Если администратор публикует две отдельные TXT-записи для SPF, почтовый сервер возвращаетPermError. Все сервисы должны быть объединены в одну строку.
Механизмы и квалификаторы: логика первого совпадения
Почтовый сервер получателя выполняет процедуру check_host(), проверяя механизмы записи строго слева направо до первого совпадения. Как только IP-адрес отправителя совпал с каким-либо правилом, обработка немедленно останавливается.
Перед каждым механизмом может указываться квалификатор, определяющий результат проверки:
+(Pass): отправитель авторизован (квалификатор по умолчанию, если знак опущен).-(Fail): отправитель явно не авторизован (жесткий отказ).~(Softfail): отправитель, скорее всего, не авторизован; письмо принимается с понижением репутации.?(Neutral): домен не делает утверждений о подлинности адреса.
Спецификация RFC 7208 определяет восемь механизмов проверки:
| Механизм | Синтаксис | Условие совпадения | Влияние на лимит 10 DNS-запросов |
|---|---|---|---|
all | all, -all, ~all | Совпадает всегда (ставится в самом конце) | 0 (DNS не запрашивается) |
ip4 | ip4:192.0.2.0/24 | IP-адрес входит в указанную IPv4-подсеть | 0 (локальная проверка) |
ip6 | ip6:2001:db8::/32 | IP-адрес входит в указанную IPv6-подсеть | 0 (локальная проверка) |
include | include:domain.com | Вложенная политика домена вернула Pass | +1 (плюс все вложенные запросы) |
a | a, a:domain.com | IP совпадает с A/AAAA-записями домена | +1 DNS-запрос |
mx | mx, mx:domain.com | IP совпадает с адресами MX-серверов | +1 DNS-запрос (кап на 10 хостов) |
exists | exists:domain.com | Сформированное имя имеет любую A-запись | +1 DNS-запрос |
ptr | ptr:domain.com | Обратный DNS резолвится в домен (запрещен) | +1 (крайне медленный, не использовать) |
Лимиты DNS и скрытые ловушки стандартов
Главное ограничение RFC 7208 (§4.6.4) — лимит в 10 DNS-запросов. Это защитная мера против атак типа «отказ в обслуживании» (DoS), предотвращающая бесконечную генерацию DNS-трафика при проверке почты.
Скрытые опасности переполнения лимита:
- Каскадные
include: подключение внешних SaaS-провайдеров (Google Workspace, Mailgun, SendGrid, Unisender) быстро исчерпывает бюджет. Например, одинinclude:spf.protection.outlook.comможет внутри содержать еще 2–3 вложенных вызова. - Лимит Void Lookups: стандарт рекомендует ограничивать число запросов к несуществующим доменам (
NXDOMAINили пустой ответ) максимум двумя. Если в записи остался старыйincludeна удаленный домен, проверка вернетPermErrorзадолго до достижения 10 запросов. - Ограничение строки в 255 байт: размер одной текстовой строки в DNS TXT ограничен 255 октетами. Чтобы опубликовать длинную запись, ее разбивают на несколько строк в кавычках внутри одной TXT-записи:
"v=spf1 ip4:... " "include:... -all". Почтовый сервер склеивает эти строки без добавления пробелов.
Модификаторы redirect, exp и динамические макросы
Помимо механизмов, стандарт поддерживает модификаторы в формате имя=значение:
redirect=domain.com: передает полную оценку политике другого домена, если ни один собственный механизм не совпал. В отличие отinclude:, результат перенаправленного домена полностью заменяет текущий. Если в записи присутствуетall, модификаторredirectигнорируется.exp=domain.com: указывает на TXT-запись с текстом объяснения причин отказа, который возвращается при статусе Fail. Запросexpпроисходит только после завершения проверки и не расходует лимит 10 DNS-лукапов.
Динамические макросы (RFC 7208 §7) позволяют конструировать DNS-имена в реальном времени на основе параметров входящего письма:
%{i}— IP-адрес отправителя (в точечном формате для IPv4 или посимвольном для IPv6).%{ir}— реверсивный IP-адрес (например,192.0.2.1превращается в1.2.0.192).%{d}— проверяемый домен, а%{d2}оставляет только два правых сегмента (главный домен).
Связка механизма exists: и макросов позволяет авторизовывать тысячи динамических серверов всего одним DNS-запросом без перечисления IP-диапазонов:
v=spf1 exists:%{i}._spf.mta.salesforce.com -all
При получении письма почтовый сервер формирует запрос вида 198.51.100.7._spf.mta.salesforce.com. Если провайдер отдает для этого имени A-запись, письмо признается легитимным.
Типовые ошибки и пошаговая процедура аудита
Анализ реальных конфигураций показывает, что большинство ошибок возникает из-за опечаток и непонимания синтаксиса:
| Неправильная запись | Корректный синтаксис | Описание проблемы |
|---|---|---|
ipv4:192.0.2.0/24 | ip4:192.0.2.0/24 | Использовано ipv4 вместо стандартного ip4 |
include: example.com | include:example.com | Пробел после двоеточия нарушает грамматику ABNF |
ip4=192.0.2.0/24 | ip4:192.0.2.0/24 | Знак = допустим только в модификаторах |
Две TXT-записи v=spf1 | Одна объединенная запись | Множественные записи возвращают PermError |
v=spf1 -all include:... | v=spf1 include:... -all | Элементы после -all игнорируются |
Официальная процедура настройки и верификации SPF:
- Инвентаризация отправителей: собрать перечень всех легитимных источников почты (корпоративная почта, CRM, транзакционные шлюзы, мониторинг).
- Сборка единой политики: сформировать строку
v=spf1, разместив сначала прямые IP-диапазоны (ip4,ip6), затем проверенныеinclude, и завершить терминатором~all(на этапе внедрения) или-all(в стабильном режиме). - Расчет бюджета DNS: проверить сумму DNS-запросов с помощью утилиты
digили валидатора SPF, убедившись, что число лукапов строго меньше 10. - Публикация в DNS: добавить единственную TXT-запись на уровне домена.
- Тестирование и DMARC: отправить тестовые сообщения на внешние почтовые службы, проверить заголовки
Authentication-Results: spf=passи настроить мониторинг отчетов DMARC для отслеживания ошибок.

