Короткий ответ
У домена contoso.example должен быть ровно один TXT, который начинается с v=spf1. Для почты в Microsoft 365 в нём обязателен include:spf.protection.outlook.com. Политика на конце — -all, когда инвентарь отправителей закрыт, не +all. Вложенные include/a/mx/redirect суммарно не должны требовать больше 10 DNS-запросов (RFC 7208). «Too many DNS lookups» = permerror = для DMARC это не pass, письма ведут себя как fail.
Не плодите второй SPF «для Mailchimp». Не вставляйте mx «на всякий случай», если MX и так Exchange Online: это лишние lookups. Сначала нарисуйте список отправителей, потом одну строку.
Симптомы и как отличить
nslookup -type=TXT contoso.exampleпоказывает дваv=spf1.- В
Authentication-Results:spf=permerrorилиspf=fail(fail — хост не в механизме; permerror — запись сломана). - После добавления
include:thirdparty.exampleобычная почта Outlook стала попадать под permerror. - Письма с
contoso.onmicrosoft.comпроходят, с кастомного домена — нет: смотрят не ту зону.
| Наблюдение | Диагноз | Не то |
|---|---|---|
| Два SPF TXT | невалидный SPF как таковой | «нужен SPF на поддомене» |
| permerror lookups | >10 вложенных запросов | «Microsoft сломал DNS» |
| fail, один include EO | письмо шло не из EO | сломанный DKIM |
| pass на return-path другого домена | SPF не выровнен к From | «SPF ок, DMARC обязан пройти» |
Возможные причины
- Хостер при подключении Microsoft 365 добавил свой SPF, не заменив старый.
- Несколько
includeмаркетинга, CRM, старого регистратора, плюсmx, плюсa— взрыв lookups. +allили?allпосле миграции «чтобы точно доходило».- Нет
include:spf.protection.outlook.com, исходящие из Exchange Online fail. - SPF повешен на
wwwили наmail, а люди шлют с apexcontoso.example. - Макрос
%{i}и экзотика, скопированная с форума, плюсptr(дорого и непредсказуемо;ptrв SPF лучше не использовать). - TXT разрезан так, что у регистратора получилось два рекорда вместо одного длинного.
Диагностика
1. Сколько SPF
nslookup -type=TXT contoso.exampleResolve-DnsName contoso.example -Type TXT |
Where-Object { $_.Strings -join '' -like 'v=spf1*' }Больше одной строки v=spf1 — стоп. Сначала слияние, потом lookups.
Проверяйте именно apex, с которого From. Поддомен info.contoso.example имеет свой SPF, если с него шлют.
2. Ручной разбор lookups
Считайте: каждый include, a, mx, ptr, exists, redirect — как минимум один запрос, плюс то, что внутри include. ip4:/ip6: lookups не тратят. include:spf.protection.outlook.com — несколько вложенных, это нормально и уложимо, если не добавить ещё пять ESP.
Цепочка:
nslookup -type=TXT spf.protection.outlook.comНе копируйте в свой SPF содержимое Microsoft: используйте include, чтобы они могли менять диапазоны.
3. Совпадает ли источник письма с SPF
Заголовок Received / spf=pass (sender IP is …). IP должен попадать в механизмы. Если IP офиса 203.0.113.40, а в SPF только include Microsoft — сканер, отправивший напрямую, получит fail. Это не «SPF настроен неправильно для Outlook», это неучтённый отправитель.
4. Связка с DMARC
Даже идеальный SPF не спасёт, если Return-Path bounce.crm.example, а From ivan.petrov@contoso.example, без DKIM на вашем домене. Тогда идите в DKIM и проверку комплекта.
Решение
Целевой минимум для только Exchange Online
Один TXT на contoso.example:
v=spf1 include:spf.protection.outlook.com -allTTL поставьте умеренный (например 600–3600) на время отладки, потом можно поднять. Не делайте 60 секунд навсегда.
Слияние двух записей
Было: v=spf1 mx a -all у хостера и отдельно v=spf1 include:spf.protection.outlook.com ~all. Станет одна, без лишнего mx, если почтовый контур — Microsoft 365. a оставляйте, только если веб-сервер на том же имени реально шлёт почту — обычно нет.
Добавить ESP, не превысив 10
Предпочитайте include поставщика, который сам укладывается в 1–2 lookup, или ip4: их фиксированных шлюзов, если документация даёт стабильные сети. Если после добавления permerror — уберите mx/a/include мёртвого регистратора. Не решайте permerror через +all.
Политика -all vs ~all
~all (softfail) терпим на период инвентаря. Боевой контур Microsoft 365 + закрытый список отправителей — -all. +all не используйте. ?all почти ничего не даёт фильтрам.
Поддомены
Сканер с From: scanner@contoso.example должен попасть в SPF apex. Либо шлите через Exchange, либо ip4: шлюза, либо отдельный scan.contoso.example со своим SPF и From на этом поддомене (плюс DMARC sp).
Как проверить, что проблема устранена
- Ровно один
v=spf1на apex. - Письмо из Outlook / OWA:
spf=pass, IP в диапазоне Microsoft. - Письмо с каждого ESP: pass или вы сознательно перевели их на DKIM-only alignment.
- Нет
permerrorна контрольных заголовках через 2×TTL.
Resolve-DnsName contoso.example -Type TXT
Connect-ExchangeOnline -UserPrincipalName admin@contoso.example
Get-MessageTrace -SenderAddress ivan.petrov@contoso.example `
-StartDate (Get-Date).AddHours(-2) -EndDate (Get-Date)Трейс не показывает SPF сам по себе — смотрите заголовки копии на контрольном ящике.
Если не помогло
- Pass в заголовках, DMARC fail: проблема alignment/DKIM, не «ещё один include».
- Fail только у одного получателя: они могли закешировать старый SPF (их право); подождите TTL, не плодите записи.
- Используете flattening (разворот include в ip4): документ устаревает, когда Microsoft меняет диапазоны. Для EO flatten обычно хуже, чем
include. - Зона на split-DNS: внутренний TXT без include, внешний другой. Проверяйте публичный резолвер, не DC.
Профилактика
- Чеклист отправителей в wiki: Exchange Online, ESP, шлюз, сканеры.
- Любой новый SaaS с From вашего домена — изменение SPF или DKIM, не «потом».
- После миграции на Microsoft 365 удалите include старого ISP.
- Не копируйте SPF конкурента. Готовьте домен по чеклисту.
FAQ
Нужен ли mx в SPF для Exchange Online?
Обычно нет. MX указывает, куда принимать, SPF — кто шлёт. Исходящие EO покрывает include:spf.protection.outlook.com. mx тратит lookups.
Можно ли несколько SPF, если регистратор так рисует GUI?
Нет. Несколько TXT v=spf1 — ошибка. Один TXT, в нём несколько механизмов.
include чужого ESP «на будущее»?
Нет. Лишний include = lookups и право ESP слать от вашего имени с точки зрения SPF.
Почему письмо с contoso.onmicrosoft.com проходит без вашего SPF?
Это другой домен. SPF смотрит зону envelope sender. Кастомный From без своей записи — другая история (DKIM/DMARC).
SPF pass, но Gmail в спаме. SPF бесполезен?
SPF — один сигнал. Репутация, DKIM, контент, жалобы. Чините спам как класс, не добавляйте +all.
Как считать lookups, если include Microsoft «внутри ещё include»?
Считаются вложенные запросы до листа. Документация Microsoft рассчитана на укладку в лимит; ваша задача — не добавить сверху пять тяжёлых include.