Пошта ламається найпринизливішим способом: вона «переважно працює», поки одного дня не перестає, і тоді ваші керівники дізнаються фразу SPF permerror з повідомлення про відскік о 6:12 ранку.
Це про тупі збої — підводні камені з лапками та пробілами в SPF TXT‑записах, які перетворюють цілком дійсну політику на мовчазний збій, періодичний збій або фестиваль взаємних звинувачень постачальників. Якщо ви керуєте продакшеном, вам не потрібні розмірковування «перевірте ваш DNS». Вам потрібен чекліст, швидкий план діагностики та чітка думка про те, де людям не можна дозволяти вводити подвійні лапки.
Чому форматування ламає SPF (навіть коли текст здається правильним)
SPF — це текст. DNS — це текст. Люди люблять текст. Ось у чому проблема.
SPF оцінюється приймачами та шлюзами, які парсують TXT‑запис у послідовність механізмів і модифікаторів. Правила розбору суворі в нудних деталях і дивно поблажливі в заплутаних. В результаті запис може виглядати нормально в DNS‑інтерфейсі, нормально на скриншоті та водночас інтерпретуватися по-різному в різних резолверах, бібліотеках і поштових приймачах.
Помилки форматування діляться на кілька категорій:
- Подання DNS проти формату «на дроті»: інструменти на кшталт
digпоказують лапки; провайдери DNS зберігають рядки; бібліотеки з’єднують «character-strings». Люди копіюють лапки у значення і випадково публікують буквальні лапки. - Пробіли та токенізація: механізми SPF розділені пробілами. Додаткові пробіли зазвичай терпляться, але не завжди там, де ви думаєте. Табуляції, нерозривні пробіли та «розумне форматування» UI можуть створити токени, які не парсуються як очікувалося.
- Розбиття на рядки: RDATA TXT у DNS може містити кілька character-strings. Багато провайдерів розбиває довгі значення. Обробка SPF конкатенує їх без додавання пробілів. Якщо розрив стався в невдалому місці, ви можете зварити два токени в один невірний токен.
- Кілька SPF‑записів: більше одного SPF‑політики на одному імені — це протокольна помилка. Це не «воно вибере одне». Це «деякі приймачі трактують це як permerror і відхиляють SPF».
- Пошуки та redirect: це не форматування, але з’являється в тій самій черзі інцидентів. include/redirect збільшують кількість DNS‑запитів, і SPF повертає permerror. Люди часто «виправляють» це згладжуванням (flattening), що приносить нові ризики форматування.
Ще одна причина, чому це боляче: збої SPF не завжди викликають повернення пошти. Багато приймачів трактують SPF як сигнал, а не як жорсткий бар’єр, особливо коли політика DMARC пом’якшена. Тож ви не отримаєте чистого простою — лише «проблеми з доставкою», потрапляння в папку спаму та повільна втрата довіри.
Швидкий план діагностики (перший/другий/третій)
Коли ви на виклику і керівник пересилає «Чому цей постачальник сказав, що наша пошта підроблена?», вам не потрібна філософія. Потрібен порядок триажу, що сходиться.
Перший: перевірте, що насправді опубліковано (не те, що показує ваш DNS‑UI)
- Запитуйте TXT за точним доменом, що використовується у MAIL FROM / Return-Path (часто це піддомен). Багато організацій редагують
example.com, але відправник використовуєbounces.example.com. - Порахуйте SPF‑записи: якщо є більше одного значення
v=spf1у TXT, ставте це в категорію пожежі, поки не доведете протилежне. - Шукайте артефакти лапок: ведучі або кінцеві символи лапок всередині опублікованого рядка та «escaped quotes», що з’явилися після копіювання/вставки.
Другий: оцініть, як це парситимуть приймачі
- З’єднайте розбиті TXT‑рядки і перевірте межі токенів (особливо навколо
include:,ip4:,redirect=та кваліфікаторів на кшталт~all). - Запустіть оцінку SPF для відомого IP‑адреса відправника (або хоча б перевірте синтаксис). Не припускайте, що «виглядає правильно» означає «парситься правильно».
- Перевірте кількість DNS‑запитів, якщо ви близькі до ліміту; один новий include може перекинути вас через 10.
Третій: підтвердіть, що реально зламалося в польових умовах
- Отримайте реальний приклад заголовка з невдалого отримувача, що показує
Authentication-Results. Це приймач, що каже, як він інтерпретував ваш SPF. - Порівняйте між приймачами (Gmail vs Microsoft vs шлюз безпеки). Якщо один каже «permerror», а інший — «none», ймовірно, у вас або кілька записів, або розриви, або проблеми резолверів.
- Перевірте поширення та кешування перед тим, як продовжувати крутити записи як ігровий автомат.
Парафраз думки Вернера Фогельса (CTO Amazon): «Все ламається, весь час». Помилки форматування SPF — це поштовий варіант цієї істини.
Факти та історичний контекст (дивні деталі, що мають значення)
- SPF народився як “Sender Permitted From” на початку 2000‑х, створений для боротьби з повсюдним спуфінгом і спамом; пізніше став «Sender Policy Framework». Назви менш важливі, ніж механіка DNS.
- SPF публікується в TXT‑записах DNS здебільшого заради зворотної сумісності. Колись був окремий тип RR для SPF, але TXT виграв у впровадженні.
- DNS TXT може містити кілька “character-strings” (фрагментів). Інструменти відображають їх у лапках, що вводить людей в оману, наче лапки — частина значення.
- SPF має жорсткий ліміт у 10 DNS‑запитів під час оцінки (для механізмів як
include,a,mx,ptr,existsтаredirect). Одна занадто заповзятлива маркетингова фішка може вас погубити. - SPF перевіряє домен відправника в конверті (MAIL FROM / Return-Path), а не заголовок «From:», який бачать користувачі. Ось чому SPF може проходити, а фішинг усе ще працює.
- DMARC залежить від вирівнювання між SPF (домен в конверті) і заголовком From, або від вирівнювання DKIM. SPF може бути ідеальним і все одно провалити DMARC, якщо домени не вирівняні.
- Деякі приймачі трактують кілька SPF‑записів як permerror і фактично «провалюють» SPF. Інші вибирають один або об’єднують — у будь‑якому разі це занадто невизначено, щоб бути безпечним.
- Пробіли в DNS — це не те саме, що пробіли в SPF. DNS зберігає байти. SPF інтерпретує байти як токени. Плутання цих шарів спричиняє саме ті помилки, про які ця стаття.
- Старі механізми SPF, як PTR, часто використовувалися і тепер не рекомендуються через повільність і нестійкість. Ви все ще знаходите їх у застарілих записах, як забутий cron.
Як парсується SPF: що насправді оцінюють приймачі
Уточнимо ментальну модель, бо більшість помилок форматування SPF походить від неправильного розуміння.
Два шари: кодування TXT у DNS проти розбору тексту SPF
Рівень DNS: TXT‑запис — це один або кілька рядків. Провайдери можуть зберігати його як один довгий рядок або розбивати. У мережі це список чанків з довжиною. Резолвери повертають чанки; клієнти зазвичай конкатенують їх.
Рівень SPF: після конкатенації SPF — це один рядок, що починається з v=spf1, за яким ідуть механізми і модифікатори, розділені пробілами. Кожний механізм може мати необов’язковий кваліфікатор: + (pass), - (fail), ~ (softfail), ? (neutral).
Що бачить приймач (спрощено)
Приймач отримує з’єднання з IP. Він читає домен відправника в конверті (іноді використовується ім’я HELO для перевірок SPF «HELO identity», але головним є MAIL FROM). Він запитує TXT для цього домену. Він обирає SPF‑запис (якщо ровно один). Він оцінює механізми поки один не співпаде. Якщо не може оцінити (синтаксична помилка, DNS‑помилки, занадто багато запитів), ви отримуєте permerror або temperror.
Permerror — це не «ніби провал»
permerror означає, що опублікована політика зламана або порушує обмеження. Багато приймачів трактують permerror як провал або як «немає сигналу», залежно від їхньої політики. Така непослідовність — причина, чому помилки форматування такі болючі: ви не отримаєте одного чистого режиму збоїв.
Лапки та пробіли: режими відмов, які можна відтворити
1) Копіювання лапок з dig у DNS
dig друкує TXT‑рядки в лапках. Люди бачать:
cr0x@server:~$ dig +short TXT example.com
"v=spf1 ip4:203.0.113.10 include:_spf.vendor.example ~all"
Потім вони вставляють усе — включно з лапками — в DNS‑інтерфейс, який вже трактує значення як сирий рядок. Результат: опубліковане значення стає "v=spf1 ... ~all" (з буквальними символами лапок). Деякі парсери SPF негайно падають; інші ігнорують ведучі лапки, а потім спотикаються пізніше. Це чудовий спосіб створити проблему, яка проявляється лише у одного постачальника пошти.
Що робити: публікуйте текст без обгортних лапок, якщо ваш DNS‑UI явно не вимагає їх (а більшість сучасних не вимагають). Якщо UI показує лапки в прев’ю, це зазвичай лише подання.
2) «Розумні лапки» і нерозривні пробіли з табло звернень
SPF очікує ASCII‑пробіли й ASCII‑пунктуацію. Вставка з форматованого листа або чату може призвести до:
- нерозривних пробілів (U+00A0) замість пробілів
- фігурних лапок (“ ”) замість прямих (” )
- en dash (–) замість дефіса (-) у рідкісних випадках (зазвичай в копійованих доменах у прозі)
Приймачі по‑різному трактують це. Багато хто вважатиме весь запис недійсним.
3) Розбиття запису по декількох TXT‑рядках у невдалому місці
Це найпоширеніший «виглядає нормально» злам. DNS дозволяє:
cr0x@server:~$ dig +short TXT example.com
"v=spf1 ip4:203.0.113.10 include:_spf.vendor.example"
" ~all"
Ці два рядки конкатенуються в:
v=spf1 ip4:203.0.113.10 include:_spf.vendor.example ~all
Це добре, бо другий рядок починається з пробілу.
Але якщо провайдер розбиває так:
cr0x@server:~$ dig +short TXT example.com
"v=spf1 ip4:203.0.113.10 include:_spf.vendor.ex"
"ample ~all"
Це конкатенується в include:_spf.vendor.example ~all, що також нормально.
А якщо розбив так:
cr0x@server:~$ dig +short TXT example.com
"v=spf1 ip4:203.0.113.10 include:_spf.vendor.example"
"~all"
Тепер ви отримаєте include:_spf.vendor.example~all, що є одним токеном. Це сміття. Деякі парсери трактують це як невідомий механізм; інші — як синтаксичну помилку. У будь‑якому разі ви не застосовуєте те, що думаєте.
Правило: якщо запис розбито, переконайтеся, що межа на кордоні токена і що пробіли збережені. У сумнівах явно починайте наступний рядок з пробілу.
4) Багато TXT‑записів, кожен з v=spf1
Класика. Хтось додає постачальника і «просто додає ще один SPF‑запис», бо DNS‑інтерфейс дозволяє кілька TXT‑входів на одному імені.
SPF каже: один запис. Якщо ви публікуєте два, багато оцінювачів повернуть permerror. Деякі виберуть один, що гірше, бо «працює», поки резолвер не змінить поведінку.
5) Додаткові пробіли і табуляції: не завжди безпечні
Кілька пробілів між механізмами зазвичай проходять. Табуляції, повернення каретки або дивні вставлені пробіли — не гарантовано. Також: кінцевий пробіл в кінці фрагмента може з’єднатися погано при конкатенації з наступним фрагментом.
6) Екранізація, що виглядає як екранізація
У файлах зони TXT‑записи іноді використовують backslash для екранізації лапок. UI провайдерів DNS різниться: деякі очікують сирий текст; деякі — формат zone‑file. Якщо ви вставите \"v=spf1 ...\", можете буквально опублікувати зворотні слеші, лапки й сум.
Жарт №1: SPF — єдине місце, де один відсутній пробіл може зруйнувати дохід і при цьому рахуватися «лише текстовим записом».
Практичні завдання: команди, виводи та рішення (12+)
Це польові завдання: запустіть команду, інтерпретуйте вивід, прийміть рішення. Виконуйте їх у порядку під час відлагодження або обирайте ті, що відповідають симптомам.
Завдання 1: Визначте домен особистості SPF з реального повідомлення
Команда: витягніть Return-Path та Authentication-Results зі збереженого повідомлення (приклад із збереженим сирим листом).
cr0x@server:~$ grep -E '^(Return-Path|Authentication-Results):' -n sample.eml
12:Return-Path: <bounces@mail.example.com>
45:Authentication-Results: mx.google.com; spf=permerror (google.com: domain of bounces@mail.example.com has multiple SPF records) smtp.mailfrom=bounces@mail.example.com
Що це означає: SPF оцінюється відносно mail.example.com (або можливо піддомену bounces), а не обов’язково example.com.
Рішення: запитуйте TXT для точного домену з smtp.mailfrom=. Не «виправляйте» апекс, якщо пошта використовує піддомен.
Завдання 2: Запит TXT‑записів так, як їх бачить світ
cr0x@server:~$ dig TXT mail.example.com +noall +answer
mail.example.com. 300 IN TXT "v=spf1 include:_spf.vendor.example ~all"
Що це означає: є один TXT‑запис і він містить один рядок (в цій відповіді).
Рішення: переходьте до перевірки синтаксису та підрахунку запитів; якщо є декілька відповідей або кілька рядків v=spf1, зупиніться і виправте це спочатку.
Завдання 3: Виявити кілька SPF‑політик на одному імені
cr0x@server:~$ dig +short TXT mail.example.com | grep -i 'v=spf1'
"v=spf1 include:_spf.vendor.example ~all"
"v=spf1 ip4:203.0.113.10 ~all"
Що це означає: два SPF‑записи. Це протокольна помилка і ймовірно дає permerror десь.
Рішення: об’єднайте механізми в один SPF‑запис; видаліть зайвий.
Завдання 4: Перевірити буквальні лапки всередині опублікованого рядка
cr0x@server:~$ dig +short TXT mail.example.com
"\"v=spf1 include:_spf.vendor.example ~all\""
Що це означає: TXT‑рядок містить фактичні символи лапок на початку і в кінці (екрановано для відображення). Це часто ламає розбір.
Рішення: відредагуйте DNS‑запис, щоб видалити внутрішні лапки; опублікуйте v=spf1 ... як простий текст.
Завдання 5: Помітити розбиття на кілька рядків TXT і перевірити межі
cr0x@server:~$ dig TXT example.com +noall +answer
example.com. 300 IN TXT "v=spf1 ip4:203.0.113.10 include:_spf.vendor.example" "~all"
Що це означає: два character-strings. Вони будуть конкатеновані без вставленого пробілу, в результаті ...vendor.example~all.
Рішення: виправте розрив так, щоб другий рядок починався з пробілу, або зберігайте запис як один рядок, якщо провайдер це підтримує.
Завдання 6: Порівняйте результати з кількох резолверів (проблеми кешування/проксі)
cr0x@server:~$ dig @1.1.1.1 +short TXT mail.example.com
"v=spf1 include:_spf.vendor.example ~all"
cr0x@server:~$ dig @8.8.8.8 +short TXT mail.example.com
"v=spf1 include:_spf.vendor.example" "~all"
Що це означає: різні резолвери повертають різне розбиття TXT (ще потенційно еквівалентне), або ви бачите часткову пропагацію чи помилкову конфігурацію між провайдерами DNS.
Рішення: якщо розбиття змінює межі токенів (як вище), вважайте це зламаним; інакше стежте за TTL/пропагацією і перевіряйте узгодженість авторитетних серверів.
Завдання 7: Запитайте безпосередньо авторитетні ім’я‑сервери
cr0x@server:~$ dig NS example.com +short
ns1.dns-provider.example.
ns2.dns-provider.example.
cr0x@server:~$ dig @ns1.dns-provider.example TXT mail.example.com +noall +answer
mail.example.com. 300 IN TXT "v=spf1 include:_spf.vendor.example ~all"
cr0x@server:~$ dig @ns2.dns-provider.example TXT mail.example.com +noall +answer
mail.example.com. 300 IN TXT "v=spf1 include:_spf.vendor.example" "~all"
Що це означає: ваші авторитетні сервери не погоджуються. Це не «пропагація». Це непослідовність.
Рішення: припиніть редагувати SPF і виправте процес публікації DNS (пуш зони, синхронізація провайдерів або split‑brain). Поштові приймачі можуть звертатися до будь‑якого з них.
Завдання 8: Перевірити синтаксис SPF локальним парсером (швидка санітарна перевірка)
Встановіть інструмент (назва пакету залежить від дистрибутива; тут показано як вже встановлений) і перевірте запис, який ви плануєте опублікувати.
cr0x@server:~$ spfquery --scope mfrom --id bounces@mail.example.com --ip 203.0.113.10
pass: domain of bounces@mail.example.com designates 203.0.113.10 as permitted sender
Що це означає: для цього IP політика SPF повертає pass. Синтаксис принаймні парситься для цього інструменту.
Рішення: якщо це повертає permerror, виправляйте форматування або межі запитів перед продовженням.
Завдання 9: Винести permerror перевіркою записів з великою кількістю запитів
cr0x@server:~$ spfquery --scope mfrom --id bounces@mail.example.com --ip 198.51.100.25
permerror: too many DNS lookups
Що це означає: ви перевищили ліміт у 10 DNS‑запитів. Це часто трапляється після «ще одного include».
Рішення: зменшіть кількість include/redirect, видаліть a/mx, якщо непотрібні, або спроектуйте відправку по‑новому (виділені піддомени для постачальників). Не заклеюйте це випадково flattening без контролю оновлень.
Завдання 10: Перевірити на наявність не‑ASCII пробілів
Отримайте TXT‑запис і подивіться на байти. Це ловить нерозривні пробіли та інші невидимі підстави.
cr0x@server:~$ dig +short TXT mail.example.com | tr -d '\n' | hexdump -C | head
00000000 22 76 3d 73 70 66 31 c2 a0 69 6e 63 6c 75 |"v=spf1..inclu|
00000010 64 65 3a 5f 73 70 66 2e 76 65 6e 64 6f 72 |de:_spf.vendor|
00000020 2e 65 78 61 6d 70 6c 65 20 7e 61 6c 6c 22 |.example ~all"|
Що це означає: c2 a0 — це нерозривний пробіл (UTF‑8). Це не звичайний ASCII‑пробіл.
Рішення: наберіть запис у простому текстовому редакторі або DNS‑UI без «красивого» форматування. Вважайте все не‑ASCII підозрілим.
Завдання 11: Підтвердити, що ваш MTA використовує як відправника в конверті
Приклад для Postfix: перевірте, що smtpd_sender_restrictions не переписує відправника, і перевірте canonical maps, якщо використовуються.
cr0x@server:~$ postconf -n | egrep 'myhostname|mydomain|sender_canonical|smtp_generic_maps'
myhostname = mx1.internal.example
mydomain = example.com
sender_canonical_maps =
smtp_generic_maps =
Що це означає: тут ніде не налаштовано переписування канонічних імен (принаймні в цьому фрагменті). Якщо ви очікували піддомен для bounce‑адреси, він може бути налаштований в додатку або ESP, а не в Postfix.
Рішення: ідентифікуйте справжній MAIL FROM у фактичних відправлених повідомленнях (Завдання 1) і публікуйте SPF там.
Завдання 12: Отримати авторитетний SPF‑запис і нормалізувати в один рядок
Це допомагає помітити зварені токени через розбиття.
cr0x@server:~$ dig @ns1.dns-provider.example TXT mail.example.com +short | tr -d '\n' | sed 's/" "/ /g'
"v=spf1 include:_spf.vendor.example ~all"
Що це означає: після наївної нормалізації ви бачите, чи є відсутній пробіл між чанками.
Рішення: якщо бачите шаблони на кшталт example~all або cominclude:, виправте границі чанків.
Завдання 13: Перевірити, чи випадково не з’явилися крапки з комою чи коми
Крапка з комою не є допустимим роздільником у SPF. Деякі люди «форматують» SPF як конфіг файл.
cr0x@server:~$ dig +short TXT mail.example.com | tr -d '\n' | grep -E '[;,]'
"v=spf1 ip4:203.0.113.10; include:_spf.vendor.example, ~all"
Що це означає: у вас є роздільники, яких SPF не розуміє. Багато оцінювачів повернуть permerror.
Рішення: видаліть пунктуацію; механізми мають бути розділені пробілами.
Завдання 14: Перевірка вирівнювання DMARC, коли SPF «проходить», але DMARC не проходить
cr0x@server:~$ grep -i '^Authentication-Results:' -n sample.eml
45:Authentication-Results: mx.google.com; spf=pass smtp.mailfrom=bounces.vendor-mail.example; dmarc=fail (p=reject) header.from=example.com
Що це означає: SPF пройшов для bounces.vendor-mail.example, але DMARC не пройшов, бо заголовок From — example.com і домен SPF не вирівняний (можливо також DKIM не вирівняний).
Рішення: виправте вирівнювання (налаштуйте власний MAIL FROM під вашим доменом для постачальника, або забезпечте вирівняний DKIM), а не постійно тонко налаштовуйте форматування SPF.
Жарт №2: DNS‑інтерфейси, що автообгортають TXT‑записи, схожі на стажера з sudo — іноді корисні, часто впевнені і завжди без нагляду.
Три корпоративні міні-історії з полі бою
Міні‑історія 1: Інцидент через хибне припущення
Вони були середньою компанією зі звичною інфраструктурою: внутрішня пошта, CRM і кілька SaaS‑інструментів, що відправляли від їх імені. Маркетинг хотів додати нову платформу подій перед запуском продукту — бо так зазвичай буває.
Інженер, який вніс зміни, припустив, що провайдер DNS хоче значення SPF «саме так, як показує dig». Це разумне припущення, якщо ви роками дивилися у файли зони і недостатньо часу проводили в браузерних DNS‑редакторах. Він вставив запис разом з навколишніми лапками. UI прийняв це. Ніхто не закричав. Зміна вийшла у продакшен.
Наступного ранку доставляння стало… дивним. Gmail показував SPF permerror для деяких отримувачів, тоді як шлюз безпеки, що використовувався партнерами, показував SPF none. Постачальник платформи наполягав, що їхні IP вірні. Внутрішня команда пошти стверджувала, що їхні сервери в порядку. Тим часом торгові представники пересилали скриншоти відскоків як інцидент‑репорти. Вони не були неправі.
Виправлення зайняло п’ять хвилин, коли хтось витягнув запис і помітив, що опублікований TXT‑рядок буквально починався з символу лапки. Діагностика зайняла три години, бо всі довіряли тому, що відображає DNS‑UI, і бо команда не мала стандартного «запитати авторитетний і зробити hexdump при потребі» плану.
Урок: ніколи не довіряйте тому, що UI рендерить. Довіряйте тому, що резолвер повертає. І не погоджуйте зміни SPF без перевірки командним рядком.
Міні‑історія 2: Оптимізація, що відкотилася назад
Інша компанія розросла свій SPF до монстра: п’ять include, кілька mx і a «на всякий випадок» і redirect для спадщини. Вони flirtували з лімітом 10 запитів. Іноді все проходило; іноді — permerror, залежно від таймаутів DNS і від того, як приймачі розгортали include.
Хтось запропонував оптимізацію: «давайте flatten SPF. Ми розв’яжемо всі include, конвертуємо їх у ip4: і ip6: записи і опублікуємо один запис без запитів». На папері — чудово: швидше, менше залежностей DNS, менше ризику permerror.
На практиці їхній скрипт flattening видав довгий рядок, який DNS‑UI провайдера автоматично загорнув у кілька character-strings. Точки обгортання були довільні. Одна обгортка впала між ip4:198.51.100.0/ і 24. Інша — між include: і доменом. Третя зруйнувала пробіл на межі.
Запис став синтаксично зламаним, і тепер кожен приймач бачив це. До оптимізації лише деякі приймачі ловили permerror при таймаутах. Після оптимізації запис був просто недійсний. Їхній моніторинг (який перевіряв лише один резолвер) цього не помітив, бо цей резолвер повертав інше розбиття, яке маскувало одну з помилок межі в їхньому простому чекері.
Вони відкотили зміни, а потім реалізували flattening правильно: контрольовані межі чанків, явні ведучі пробіли в продовженнях рядків і автоматична валідація через кілька резолверів перед публікацією. Flattening може працювати, але це тепер ланцюг постачання програмного забезпечення. Трактуйте його як такий.
Міні‑історія 3: Нудна, але правильна практика, що врятувала ситуацію
Фінансова організація мала культуру «автентифікація пошти — це продакшен», що рідше за потреби. У них була проста практика: будь‑яка зміна SPF вимагала невеликого виконання рунбуку, а скриншоти були заборонені. Лише реальні команди. Також була політика: кожна велика система відправки має свій піддомен з власним SPF.
Коли procurement втягнув новий HR‑інструмент, що потребував прав на відправку, команда не чіпала example.com. Вони створили hrmail.example.com для цієї системи, опублікували там мінімальний SPF і налаштували постачальника використовувати його як домен bounce. Апекс SPF залишався стабільним, а маркетинговий хаос був ізольований.
Через два місяці постачальник повернув інфраструктуру і оновив include‑ціль. Багато клієнтів побачили періодичний SPF permerror через ланцюги include і таймаути. Ця організація не побачила проблем. Чому? Їхній SPF мав лише один include і нічого зайвого. Достатньо запиту залишалося, і шлях оцінки був чистим.
Нудна частина — сегментація піддоменами плюс обов’язкова перевірка командним рядком — означала, що інцидент ніколи не потрапив на їхню сигналізацію. Він дійшов лише до тижневого огляду змін постачальника, де вони кивнули, нічого не змінили і повернулися до основної роботи.
Поширені помилки: симптом → причина → виправлення
1) Симптом: SPF permerror «multiple SPF records»
Причина: Більше одного TXT‑запису на одному імені містить v=spf1 (часто створюється додаванням постачальника «SPF‑запису» замість оновлення існуючого).
Виправлення: Консолідуйте в один SPF‑політику. Видаліть зайві SPF TXT‑входи. Якщо потрібні окремі політики, використовуйте окремі піддомени і налаштуйте постачальників використовувати їх як MAIL FROM.
2) Симптом: SPF permerror «invalid domain found» або «invalid mechanism»
Причина: Зварені токени через конкатенацію TXT‑чанків без пробілу (наприклад, include:_spf.vendor.example~all) або розрив всередині токена.
Виправлення: Переконайтеся, що розриви відбуваються на кордонах токенів і що наступний фрагмент починається з ведучого пробілу. Перепублікуйте і перевірте за допомогою dig, що токени розділені як треба.
3) Симптом: SPF падає в Gmail, але «працює» в інших
Причина: Різні оцінювачі по‑різному обробляють хибні пробіли/лапки; або якісь обирають один SPF‑запис, тоді як інші повертають permerror; або непослідовність між авторитетними серверами.
Виправлення: Запитуйте кілька резолверів та авторитетних серверів. Видаліть буквальні лапки. Усуньте кілька SPF‑записів. Нормалізуйте до одного чистого рядка (або акуратно розбийте).
4) Симптом: SPF періодично permerror «too many DNS lookups»
Причина: Кількість запитів залежить від порядку розгортання include і таймаутів DNS; ви близькі до ліміту 10.
Виправлення: Зменшіть include, приберіть a/mx/ptr, сегментуйте піддомени. Якщо ви flatten‑ите, автоматизуйте це і перевіряйте межі токенів і чанків.
5) Симптом: SPF — «neutral» або «none» несподівано
Причина: SPF‑запис не знайдено за доменом MAIL FROM (ви оновили неправильне ім’я), або запис починається зі сміттєвих символів через лапки/вставки.
Виправлення: Підтвердіть домен ідентичності з заголовків. Опублікуйте SPF там. Переконайтеся, що запис починається точно з v=spf1 (без ведучих лапок, BOM або дивних пробілів).
6) Симптом: SPF проходить, але DMARC не проходить (і ви все ще в спамі)
Причина: Невирівнювання доменів: домен SPF не вирівняний з заголовком From, і DKIM не вирівняний (або відсутній).
Виправлення: Налаштуйте власний bounce‑домен під вашим доменом для постачальника або виправте вирівняний DKIM. Не продовжуйте «підтюнювати» форматування SPF.
7) Симптом: SPF падає лише для відправників IPv6
Причина: Ви додали ip4: записи, але забули ip6:, або покладалися на a/mx, які не покривають IPv6 як очікувалося; іноді це поєднано з помилками розбиття навколо ip6: токенів.
Виправлення: Додайте явні ip6: механізми де потрібно, перевірте токенізацію запису і протестуйте з IPv6 IP.
Чеклісти / покроковий план
Чекліст: публікація SPF‑запису без зламування
- Визначте домени ідентичності: перелічіть кожен домен MAIL FROM, що використовується (апекс, маркетингові піддомени, піддомени bounce постачальників).
- Один домен — один SPF‑запис: переконайтеся, що на кожен домен ідентичності є рівно одне TXT‑значення, що містить
v=spf1. - Напишіть запис у простому текстовому редакторі: без форматованого тексту, без форматування з тикетних систем.
- Тримайте його простим: віддавайте перевагу явним
ip4:/ip6:для своїх MTA; використовуйтеinclude:лише коли треба. - Уникайте старих механізмів: не використовуйте
ptr. Будьте обережні зaіmx; вони спалюють запити і змінюються з DNS. - Плануйте ліміт у 10 запитів: рахуйте include і redirect, і передбачайте, що у постачальників також є include.
- Якщо потрібно розбивати TXT: розбивайте лише на кордонах токенів і починайте наступний рядок з пробілу.
- Публікуйте і перевіряйте у авторитетних NS: робіть запит до кожного авторитетного сервера безпосередньо.
- Перевіряйте через кілька публічних резолверів: виявляйте дивну пропагацію та кешування.
- Валідуйте через SPF‑оцінювач: протестуйте принаймні один відомо‑хороший IP і один відомо‑поганий IP.
- Збирайте докази: зберігайте точний текст запису, виводи запитів і тикет. Вони знадобляться пізніше.
Покроково: як безпечно об’єднати два SPF‑записи
- Витягніть всі TXT‑записи і відокремте ті, що містять
v=spf1. - Скопіюйте механізми в один запис, зберігаючи порядок так, щоб найконкретніші збіги були раніше.
- Залиште рівно один механізм
allв кінці (наприклад,~allабо-all, залежно від політики). - Опублікуйте об’єднаний запис і видаліть дублі.
- Запустіть перевірку кількості запитів і реальні SPF‑чекі (Завдання 8/9).
Покроково: виправлення зламаного розбитого TXT‑запису
- Запитайте запис і подивіться точне розбиття (
dig ... +answer). - Конкатенуйте рядки ментально (або за допомогою скрипта) і шукайте зварені токени.
- Відредагуйте запис так, щоб кожен рядок‑продовження починався з пробілу, якщо він не продовжує токен навмисно (рідко і ризиковано).
- Повторно запитайте авторитетні сервери і перевірте і розбиття, і відновлений текст.
- Повторно протестуйте оцінку SPF з відомим IP‑адресом відправника.
FAQ
1) Чи потрібні лапки навколо мого SPF‑запису в DNS?
Зазвичай ні. Лапки часто просто спосіб відображення TXT‑рядків інструментами. Якщо ваш DNS‑UI просить поле значення, введіть v=spf1 ... без обгортних лапок, якщо UI явно не документує інше.
2) Чому dig показує лапки тоді?
Тому що TXT‑записи — це рядки, і лапки — безпечна конвенція відображення. Вони не обов’язково є частиною того, що зберігається як дані в тому розумінні, в якому ви звикли.
3) Чи дійсно допустимо розбивати SPF‑запис по кількох TXT‑рядках?
Так, якщо конкатенований текст і далі є валідним SPF. Підступ: конкатенація не вставляє пробілів. Якщо ваш розрив прибирає пробіл між токенами, ви ламаєте запис.
4) Який найпростіший «безпечний» SPF‑запис?
Для домену, що відправляє лише через одне відоме джерело, щось на кшталт v=spf1 ip4:203.0.113.10 -all є чистим і стійким. Реальні середовища складніші; принцип — мінімізувати і робити механізми явними.
5) Чому SPF почав падати після додавання одного include нового постачальника?
Ймовірно, ви вдарилися в ліміт у 10 DNS‑запитів, або новий ланцюг include ввів таймаути. Приймачі можуть повертати permerror, коли не можуть завершити оцінку. Перевірте кількість запитів до і після додавання include.
6) Чи можна опублікувати SPF на апексі і все?
Тільки якщо всі ваші відправники використовують апекс як MAIL FROM і ви можете тримати політику в межах обмежень. На практиці чистіше використовувати піддомени для постачальників: менший радіус ураження, легше зміни, менше конфліктів.
7) Чому SPF проходить, але пошта все одно потрапляє в спам?
SPF — лише один сигнал. Якщо DMARC не проходить (невирівнювання), DKIM відсутній/збитий або репутація відправника погана, ви все одно можете опинитися в спамі. Не плутайте «SPF pass» з «проблема доставки вирішена».
8) Що оперативно означає SPF permerror?
Ваша SPF‑політика не може бути оцінена як опублікована (синтаксична помилка, кілька записів, занадто багато запитів тощо). Ставте це як продакшн‑конфіг‑помилку. Виправляйте її як зламане правило фаєрволу: акуратно, з валідацією і планом відкату.
9) Чи завжди додаткові пробіли в SPF безпечні?
Додаткові ASCII‑пробіли між токенами зазвичай так. Табуляції, нерозривні пробіли і розбиття, що прибирає потрібні пробіли — ні. Якщо ви відлагоджуєте «виглядає нормально» запис, перевірте байти.
10) Чи варто нам flatten‑ити SPF, щоб уникнути ліміту запитів?
Іноді. Flattening обмінює виконувані DNS‑запити на конвеєр підтримки, що має залишатися коректним при ротації IP у постачальників. Якщо ви flatten‑ите, автоматизуйте оновлення, валідуйте синтаксис та межі чанків і моніторте дрейф. Інакше ви міняєте один режим відмови на дорожчий.
Наступні кроки, які можна впровадити цього тижня
Якщо ви зробите лише три речі, зробіть ці:
- Перелікуйте ваші MAIL FROM домени з реальних заголовків, а не з пам’яті. Публікуйте SPF там, де його фактично оцінюють.
- Забезпечте «один v=spf1 на ім’я» і додайте DNS lint‑перевірку в процес змін. Кілька SPF‑записів — це самоубивство.
- Впровадьте ритуал перевірки: робіть запит до авторитетних серверів, перевіряйте межі чанків і запускайте оцінку SPF для принаймні одного IP перед оголошенням перемоги.
SPF не складний. Він просто безжальний у тих місцях, де люди люблять бути неуважними: пробіли, лапки і «невеликі правки». Трактуйте його як продакшн‑конфіг, бо ваші комерційні листи вже так і роблять.