Postfix принял письмо без авторизации: это open relay или нормальная доставка на ваш домен
Админ открывает лог почтового сервера, видит письмо от незнакомого хоста, принятое без единой попытки AUTH, и у него холодеет спина: «у нас открытый релей». Через полчаса в main.cf появляется строчка, требующая авторизации от всех подряд, и ещё через час клиенты звонят с вопросом, почему им никто не пишет. Я эту последовательность видел столько раз, что могу пересказывать по памяти. Ниже — где именно проходит граница между приёмом почты и пересылкой, какими параметрами Postfix её проводит, как выглядит настоящая дыра и как проверить свой сервер за пять минут, не поломав доставку.
Письмо без AUTH — это норма, а не взлом
Начнём с механики, потому что вся путаница растёт именно отсюда. Когда Gmail, Яндекс или сервер контрагента доставляет письмо на ваш домен, он берёт MX-запись домена, стучится на порт 25 указанного хоста и говорит «MAIL FROM: chuzhoy@gmail.com, RCPT TO: buh@slovo-smysl.example». Никакого пароля у него нет и быть не может. Чтобы каждый внешний MTA авторизовался у вас, вам пришлось бы завести общий пароль со всем интернетом — идея, которую даже сформулировать смешно. Приём почты на собственных адресатов происходит анонимно по определению: так работает SMTP с 1982 года и так он будет работать дальше.
Открытый релей — это принципиально другой сценарий. Он выглядит так: приходит незнакомый клиент, не проходит SASL-аутентификацию, не попадает в доверенные сети, и говорит «RCPT TO: victim@yandex.ru» — то есть просит доставить письмо на домен, к которому ваш сервер не имеет ни малейшего отношения. Если сервер отвечает «250 Ok» — вот это open relay. И это не про отсутствие пароля, это про адресата.
Формула запоминается за один раз. Чужой отправитель плюс ваш получатель — это входящая почта, её обязаны принимать без авторизации. Чужой отправитель плюс чужой получатель — это пересылка, её обязаны запрещать. Свой авторизованный пользователь плюс любой получатель — это отправка, для неё существует порт 587. Всё остальное — детали реализации.
Поэтому первое, что я делаю, когда мне присылают «посмотрите, у нас релей открыт», — прошу показать не факт приёма письма, а строку RCPT TO из лога. В девяти случаях из десяти в ней стоит адрес самого клиента, и никакого релея нет. В десятом — там действительно чужой домен, и тогда разговор становится интересным.
- чужой → ваш домен: входящая почта, авторизация не нужна и не должна требоваться;
- чужой → чужой домен: пересылка, должна быть запрещена (это и есть open relay);
- ваш пользователь после AUTH → любой домен: отправка, порт 587 или 465;
- хост из mynetworks → любой домен: пересылка по доверию к IP, самое опасное место конфига.
Где Postfix принимает это решение: smtpd_relay_restrictions
До версии 2.10 правила пересылки и антиспам жили в одном списке smtpd_recipient_restrictions, и это была бесконечная мина замедленного действия: любой permit, добавленный ради «пропустить конкретного отправителя», заодно открывал релей. В 2.10 разработчики разнесли эти вещи. Появился отдельный параметр smtpd_relay_restrictions, который отвечает только за право пересылки и вычисляется в контексте команды RCPT TO. Документация формулирует это прямо: «As of Postfix 2.10, relay permission rules are preferably implemented with smtpd_relay_restrictions, so that a permissive spam blocking policy under smtpd_recipient_restrictions will no longer result in a permissive mail relay policy».
Значение по умолчанию у него боевое и правильное, менять его в большинстве случаев не нужно вообще. Проверить свои умолчания на конкретной сборке можно так:
# что зашито в бинарник
postconf -d smtpd_relay_restrictions smtpd_recipient_restrictions relay_domains mynetworks_style
# smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination
# smtpd_recipient_restrictions =
# relay_domains =
# mynetworks_style = host
# а что реально задано руками
postconf -n | grep -E 'restrictions|mynetworks|relay_domains|mydestination|virtual_'Читается это слева направо. permit_mynetworks — разрешить, если IP клиента попал в список $mynetworks. permit_sasl_authenticated — разрешить, если клиент прошёл AUTH по RFC 4954. defer_unauth_destination — всё остальное отложить с временной ошибкой. Обратите внимание на defer, а не reject: умолчание Postfix намеренно мягкое, чтобы свежеустановленный сервер с недонастроенными доменами не терял почту навсегда, а возвращал 4xx. В проде я почти всегда меняю его на reject_unauth_destination — постоянный отказ 554, чтобы отправитель узнал правду сразу, а не через пять суток ретраев.
Что считается «своим» получателем, определяет reject_unauth_destination, и определение стоит выучить дословно. Запрос проходит, если разрешённый домен получателя совпал с $relay_domains (режим форвардера) либо с $mydestination, $inet_interfaces, $proxy_interfaces, $virtual_alias_domains или $virtual_mailbox_domains (режим конечной точки) — и при этом в адресе нет маршрутизации, заданной отправителем, вида user@elsewhere@domain. Всё. Никакого «а вдруг это наш клиент» там нет: либо домен перечислен в одном из шести списков, либо письмо отвергается кодом из relay_domains_reject_code, по умолчанию 554.
И ещё одно правило, из-за которого ломаются самые хитрые конфиги: каждый список ограничений вычисляется слева направо до первого результата PERMIT, REJECT или DEFER, а конец списка эквивалентен PERMIT. То есть список, который никого явно не отверг, — это список, который всех пустил. Именно поэтому Postfix отказывается принимать почту вообще, если ни в smtpd_relay_restrictions, ни в smtpd_recipient_restrictions нет ни одного из reject, reject_unauth_destination, defer, defer_if_permit, defer_unauth_destination.
- permit_mynetworks — пропускает клиента, чей IP входит в $mynetworks; проверки пароля нет, только адрес;
- permit_sasl_authenticated — пропускает клиента, успешно прошедшего SMTP AUTH (работает только при smtpd_sasl_auth_enable=yes на этом сервисе);
- reject_unauth_destination — постоянный отказ (relay_domains_reject_code, по умолчанию 554), если домен получателя не ваш и не в relay_domains;
- defer_unauth_destination — те же запросы, но с временной ошибкой 4xx; появился в Postfix 2.10 и стоит в умолчании smtpd_relay_restrictions;
- порядок в документации: client, helo, sender, relay, recipient, data, end-of-data; REJECT или DEFER в одном списке пропускает все последующие.
Практика: как в издательстве «Слово и смысл» за сорок минут выключили входящую почту
Издательство «Слово и смысл»: 34 рабочих места, редакция, корректоры, отдел продаж и бухгалтерия, два домена на одном сервере, около 700 писем в сутки — переписка с авторами, типографиями и книжными сетями, вёрстка в PDF во вложениях. Почта своя: Debian 12, Postfix 3.7.11 из репозитория bookworm, Dovecot, Rspamd, всё в общем-то аккуратно собрано предыдущим подрядчиком. Меня позвали, когда «почта перестала приходить со вчерашнего вечера, но отправляется нормально».
Предыстория оказалась ровно та, с которой начинается статья. Накануне штатный админ читал что-то про безопасность SMTP, обнаружил в логе принятые без авторизации письма и решил закрыть дыру. В main.cf он дописал строку, которая на бумаге выглядит убедительно, а на деле убивает приём:
# так делать нельзя — это правило на порт 25
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
rejectДальше — арифметика Postfix. Внешний сервер типографии-партнёра не в mynetworks и не проходил AUTH, значит первые два правила не сработали, а третье — безусловный reject. В логе это выглядело так, и таких строк за ночь набралось 1 690:
postfix/smtpd[21188]: NOQUEUE: reject: RCPT from mx1.partner-print.example[198.51.100.23]:
554 5.7.1 <buh@slovo-smysl.example>: Recipient address rejected: Access denied;
from=<client@example.com> to=<buh@slovo-smysl.example> proto=ESMTP helo=<mx1.partner-print.example>Обратите внимание: отправитель не получил «попробуйте позже», он получил постоянную ошибку 5.7.1. Значит письма не встали в очередь на стороне отправителя, а сразу вернулись клиентам с отбойником. За неполные сутки компания потеряла всю входящую переписку, включая две вёрстки, вернувшиеся из типографии с правками, и заказ от книжной сети. Лечение заняло минуты: строку убрал, вернул умолчания, перезапустил.
postconf -X smtpd_recipient_restrictions # удалить параметр, вернув умолчание
postconf smtpd_relay_restrictions='permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination'
postfix check && systemctl reload postfix
# контроль: за следующие сутки — ноль таких отказов на свой домен
journalctl -u 'postfix*' --since '24 hours ago' | grep -c 'Recipient address rejected: Access denied'Но интереснее оказалось то, что нашлось при разборе. Пока я читал postconf -n, выяснилось, что настоящая дыра в этом сервере действительно была — только не там, где её искали. В mynetworks стояло 192.168.0.0/16, потому что «у нас несколько филиальных подсетей», а в эту же /16 попадал L2TP-пул, который роутер раздавал всем, кто знал общий preshared key, включая двух внештатных верстальщиков, с которыми издательство давно не работает. Это не открытый релей для интернета, но это релей для любого, кто поднимет VPN. Сузили до трёх конкретных /24 плюс адрес самого хоста — и вот это была настоящая работа по безопасности, в отличие от строки, из-за которой всё встало.
- симптом: «отправляется, но не приходит», у внешних отправителей — отбойники 554 5.7.1, а не задержка;
- причина: безусловный reject в конце smtpd_recipient_restrictions на порту 25 после permit_mynetworks и permit_sasl_authenticated;
- лечение: удалить параметр через postconf -X, правила релея оставить в smtpd_relay_restrictions, postfix check и reload;
- контроль: сутки мониторинга отказов по логу и тестовое письмо с внешнего ящика на адрес каждого домена;
- попутная находка: mynetworks = 192.168.0.0/16 накрывал VPN-пул — сужен до реально используемых подсетей.
Четыре способа действительно открыть релей
Теперь про настоящие дыры. Postfix из коробки закрыт, поэтому открытым релеем он становится только тогда, когда админ своими руками добавил разрешение. Мест, где это происходит, немного, и я перечислю их в порядке частоты, с которой встречаю их на аудитах.
Первое и главное — раздутый mynetworks. permit_mynetworks доверяет IP-адресу без всякой проверки, поэтому любой лишний диапазон в этом списке — это готовый релей для всех, кто в него попадёт. Классика жанра: сервер стоит у хостера, админ где-то скопировал mynetworks_style = subnet, и в доверенные попадает весь /24 провайдера вместе с соседскими виртуалками. Или в списке оказывается 172.17.0.0/16 — вся docker-сеть, включая контейнеры, которые смотрят наружу пробросом портов. Кстати, именно поэтому в Postfix 3.0 умолчание mynetworks_style сменили с subnet на host: при compatibility_level 2 и выше доверенным считается только сам хост. Проверьте, что у вас реально: postconf mynetworks покажет развёрнутый список.
Второе — путаница с порядком вычисления списков и старым синтаксисом. Тут есть тонкость. Документация Postfix (postconf(5), smtpd_relay_before_recipient_restrictions) прямо признаёт: исторически smtpd_relay_restrictions вычислялся ПОСЛЕ smtpd_recipient_restrictions, вопреки описанному поведению. В 3.6 появился параметр smtpd_relay_before_recipient_restrictions, и значение yes он получает только при compatibility_level 3.6 и выше. Важно понимать, что это меняет: PERMIT завершает только свой список, а пропуск последующих списков SMTPD_ACCESS_README описывает лишь для REJECT и DEFER. Поэтому permit в recipient-списке сам по себе не отменяет smtpd_relay_restrictions — зато при старом порядке антиспам-проверки (policy-сервис, reject_unverified_recipient, запросы в DNSBL) отрабатывают на попытках релея раньше, чем они будут отбиты, тратят ресурсы и шлют пробы проверки адресов на чужие домены. Настоящая дыра здесь другая: сервер, мигрированный с Postfix до 2.10, с пустым smtpd_relay_restrictions и правилами релея в recipient-списке. Там любой check_client_access с OK или permit, поставленный левее reject_unauth_destination, открывает пересылку, и защитной сетки второго списка нет.
Третье — relay_domains, набитый чужими доменами «на всякий случай». Параметр честно означает: «я готов принимать и пересылать почту для этих доменов». Если вы добавили туда домен клиента, для которого больше не обслуживаете почту, вы стали для него открытым релеем. Хуже того, без relay_recipient_maps сервер примет письмо на любой адрес такого домена, попытается доставить, получит отказ и сгенерирует backscatter — а за это в чёрные списки попадают не хуже, чем за спам. С Postfix 3.0 relay_domains по умолчанию пуст, и в 95 % случаев так и должно остаться.
Четвёртое — таблицы доступа с ответом OK. check_client_access hash:/etc/postfix/relay_ip, куда «на пару дней» вписали IP принтера, старого 1С-сервера или подрядчика, живут годами, а OK в access-таблице — это полноценный PERMIT, прекращающий проверку всего списка. Если нужно лишь исключить адрес из конкретной проверки, есть ответ DUNNO: по access(5) он означает «ключ не найден» и не даёт Postfix искать совпадения по более широким подсетям или родительским доменам, а список продолжает вычисляться дальше — индульгенции на пересылку он не выдаёт.
- mynetworks шире, чем реально нужно (подсеть хостера, docker0, VPN-пул, «весь офис» /16);
- пустой smtpd_relay_restrictions (наследие миграции с версии до 2.10), а в smtpd_recipient_restrictions permit или OK стоит левее reject_unauth_destination;
- relay_domains с доменами, которые вы больше не обслуживаете, и без relay_recipient_maps;
- OK вместо DUNNO в check_client_access / check_sender_access;
- compatibility_level ниже 1 без явного smtpd_relay_restrictions — действует backwards-compatible «(empty)», и вся защита держится на одном recipient-списке.
Разложить роли по портам: 25 отдельно, 587 отдельно
Половина проблем с релеем растёт из попытки сделать один порт универсальным. Не надо. Порт 25 — это только приём почты от чужих MTA, там не должно быть ни AUTH, ни требования авторизации. Порты 587 (submission со STARTTLS) и 465 (submissions, implicit TLS) — только для своих пользователей, там авторизация обязательна для всех без исключения. Когда роли разведены, конфиг перестаёт быть компромиссом и обе задачи решаются жёстко.
Выглядит это в master.cf примерно так — обратите внимание, что на клиентских портах я вообще не полагаюсь на mynetworks, только на SASL:
# master.cf
smtp inet n - y - - smtpd
-o syslog_name=postfix/smtp
# приём чужой почты: никаких требований авторизации
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_restrictions=reject_sender_login_mismatch
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,rejectТут стоит объяснить один нюанс, который экономит часы отладки. Директивы -o в master.cf переопределяют main.cf только для конкретного сервиса, и главный параметр здесь — smtpd_relay_restrictions=permit_sasl_authenticated,reject без permit_mynetworks. Это значит, что даже машина из доверенной сети, подключившаяся на 587-й, обязана представиться логином и паролем. Заражённый рабочий компьютер в вашей же сети — самый частый источник исходящего спама, и разделение портов ровно этот сценарий и закрывает: на 25-м он не сможет отправить на чужой домен, а на 587-м у него нет пароля.
Отдельно про smtpd_sender_restrictions = reject_sender_login_mismatch. Правило требует, чтобы авторизованный пользователь отправлял письма только от своих адресов, перечисленных в smtpd_sender_login_maps. Без него любой сотрудник с рабочим паролем может отправить письмо от имени директора, и это регулярно всплывает в историях с «поддельными» распоряжениями об оплате. Настраивается за десять минут, окупается один раз и навсегда.
- 25/tcp (smtp) — приём от чужих MTA, без AUTH, smtpd_relay_restrictions по умолчанию или с reject_unauth_destination;
- 587/tcp (submission) — STARTTLS обязателен (smtpd_tls_security_level=encrypt), AUTH только поверх TLS, permit_sasl_authenticated,reject;
- 465/tcp (submissions) — implicit TLS через smtpd_tls_wrappermode=yes, те же ограничения, что на 587;
- reject_sender_login_mismatch требует заполненной smtpd_sender_login_maps — без неё авторизованные пользователи получат отказы;
- после правки master.cf — postfix check, postconf -M для проверки переопределений и postfix reload.
Как проверить свой сервер за пять минут
Гадать не надо, всё проверяется руками. Сначала смотрим, что вообще задано: postconf -n показывает только отличия от умолчаний, а postconf -M — разложенный master.cf со всеми переопределениями. Отдельно я всегда разворачиваю mynetworks, потому что там любят прятаться сюрпризы из mynetworks_style.
postconf -n | grep -E 'restrictions|mynetworks|relay_domains|mydestination|virtual_(alias|mailbox)_domains'
postconf mynetworks mynetworks_style compatibility_level
postconf -M | grep -A12 -E '^(smtp|submission|smtps)'Потом — живой тест. Берём хост ЗА пределами вашей сети (VPS, домашний интернет, что угодно, лишь бы IP не был в mynetworks) и пробуем то, что делает спамер: конверт с чужим отправителем и чужим получателем. Если под рукой есть swaks — одна команда; если нет, хватит и telnet.
# вариант со swaks: должно вернуться 554
swaks --server mail.slovo-smysl.example --port 25 \
--from spammer@example.org --to victim@gmail.com \
--helo test.example.org --quit-after RCPT
# без swaks, руками
printf 'EHLO test.example.org\r\nMAIL FROM:<spammer@example.org>\r\nRCPT TO:<victim@gmail.com>\r\nQUIT\r\n' \
| nc mail.slovo-smysl.example 25Правильный ответ выглядит как «554 5.7.1 <victim@gmail.com>: Relay access denied». Ответ «250 2.1.5 Ok» на этом месте означает, что вы открытый релей, и чинить надо прямо сейчас, до конца рабочего дня. Проверьте заодно второй вектор: тот же тест с подделанным отправителем от вашего же домена (--from direktor@slovo-smysl.example) — некоторые конфиги с check_sender_access OK пропускают именно его, и на форумах это самая частая жалоба такого рода.
И последнее, чем регулярно пренебрегают: почитайте, о чём предупреждает сам Postfix. Механизм backwards compatibility с версии 3.0 пишет в лог строки вида «using backwards-compatible default setting …» каждый раз, когда старое умолчание влияет на реальный запрос. Для темы релея важны три из них: smtpd_relay_restrictions = (empty) при compatibility_level < 1, mynetworks_style = subnet и relay_domains = $mydestination при уровне < 2, и smtpd_relay_before_recipient_restrictions = no при уровне < 3.6. Актуальная стабильная ветка на сентябрь 2026 — Postfix 3.11 (последний релиз 3.11.7 от 7 сентября, legacy-ветки 3.10.14, 3.9.15, 3.8.21, 3.7.23), и максимальный уровень совместимости там 3.11. Если у вас в main.cf compatibility_level вообще отсутствует, вы работаете на умолчаниях десятилетней давности.
journalctl -u 'postfix*' --since '7 days ago' | grep -i 'backwards-compatible'
# разобрались и ничего не сломается — фиксируем уровень
postconf compatibility_level=3.6 && postfix reload- postconf -n: в smtpd_relay_restrictions или smtpd_recipient_restrictions есть reject_unauth_destination/defer_unauth_destination (без этого Postfix вообще откажется принимать почту);
- postconf mynetworks: только адрес хоста и подсети, которые вы можете объяснить поимённо;
- postconf -M: на submission и smtps стоит permit_sasl_authenticated,reject без permit_mynetworks;
- внешний тест на чужой домен — 554 Relay access denied, тест на свой адрес с внешнего хоста — 250;
- лог за неделю: нет строк «using backwards-compatible default setting», касающихся relay и mynetworks.
Приоритеты: что делать сегодня, а на что можно забить
Порядок работ у меня всегда один. Первым делом — mynetworks и внешний тест на релей: это то, за что домен улетает в Spamhaus, а компания на неделю остаётся без почты. Вторым — разделение портов и запрет AUTH на 25-м, потому что брутфорс по SMTP идёт круглосуточно и рано или поздно подберёт пароль к учётке вида test/test. Третьим — reject_unauth_destination вместо мягкого defer и reject_sender_login_mismatch на submission. Это часа три работы суммарно, и после них сервер закрыт по-настоящему.
А теперь про то, на что можно спокойно забить, потому что паника вокруг этого сильно преувеличена. Не надо требовать авторизацию от внешних отправителей — это физически невозможно и ломает почту. Не надо включать smtpd_helo_required и жёсткие проверки HELO в надежде отсечь спам: реального эффекта почти нет, а кривых, но легитимных отправителей вы отрежете обязательно, и они будут именно вашими клиентами. Не надо перетаскивать правила релея в recipient-список ради «стройности» — вы получите ровно ту ошибку, от которой Postfix избавился в 2.10. И не надо ставить всё подряд из статей вида «20 обязательных настроек Postfix»: половина оттуда устарела на десять лет, а reject_unknown_client_hostname до сих пор кочует по интернету и до сих пор режет живую почту.
Спорный момент, где единого мнения в сообществе нет, и я это честно проговариваю: reject или defer для неавторизованной пересылки. Умолчание Postfix — defer_unauth_destination, то есть временная ошибка, и логика разработчиков понятна: недонастроенный сервер лучше пусть тормозит почту, чем теряет её. Я в проде ставлю reject_unauth_destination, потому что временный отказ у спамера ничего не меняет (он уйдёт к следующей жертве), а вот администратора соседней компании 4xx на неделю оставит в неведении, почему его письма застряли. Но если вы прямо сейчас перекраиваете список обслуживаемых доменов — оставьте defer до конца работ, это разумная страховка.
И общий вывод, который стоит держать в голове при любой правке smtpd_*_restrictions: список читается слева направо, первый сработавший вердикт побеждает, а конец списка равен PERMIT. Любой permit, который вы добавляете «временно, для одного клиента», ставится в начало и отменяет всё, что стоит правее. Прежде чем дописать строку в конфиг, задайте себе один вопрос: чей адрес стоит в RCPT TO у того письма, которое вы этой строкой собираетесь пропустить. Если ответ «чужой» — вы открываете релей.
- сегодня: postconf mynetworks, внешний swaks-тест, сузить доверенные сети;
- на этой неделе: убрать AUTH с 25-го, поднять 587/465 с permit_sasl_authenticated,reject;
- в течение месяца: reject_sender_login_mismatch, актуальный compatibility_level, мониторинг очереди и попаданий в DNSBL;
- можно забить: HELO-проверки, reject_unknown_client_hostname, требование авторизации от внешних MTA.
Частые вопросы
Мой Postfix принимает письма от внешних серверов без пароля. Это открытый релей?
Нет, если получатель — адрес вашего домена. Приём входящей почты на локальных адресатов по определению происходит без авторизации: у чужого MTA нет и не может быть вашего пароля. Открытый релей — это когда сервер соглашается доставить письмо на ЧУЖОЙ домен от неавторизованного клиента. Смотрите не на факт приёма, а на адрес в RCPT TO.
Как быстро проверить, что мой сервер не open relay?
С внешнего хоста, не входящего в mynetworks, выполните: swaks --server mail.slovo-smysl.example --port 25 --from spammer@example.org --to victim@gmail.com --quit-after RCPT. Корректный ответ — 554 5.7.1 Relay access denied. Ответ 250 означает открытый релей. Тест с самого сервера или из офиса недействителен: вы почти наверняка попадёте в доверенные сети.
Чем smtpd_relay_restrictions отличается от smtpd_recipient_restrictions?
Первый отвечает за право пересылки (кому вы вообще готовы доставлять почту), второй — за антиспам. Разделение появилось в Postfix 2.10 именно потому, что раньше любой permit, добавленный ради спам-фильтра, заодно открывал релей. Правила релея держите в smtpd_relay_restrictions, антиспам — в smtpd_recipient_restrictions, и не смешивайте.
Что означает ошибка 554 5.7.1 Relay access denied у отправителя?
Ваш сервер не считает домен получателя своим: его нет ни в mydestination, ни в virtual_alias_domains, ни в virtual_mailbox_domains, ни в relay_domains, ни на интерфейсах. Если письмо шло на реально ваш домен — вы забыли добавить домен в соответствующий список или у вас лишний reject в правилах. Если на чужой — Postfix отработал правильно.
Нужно ли включать smtpd_sasl_auth_enable на порту 25?
Нет. Авторизация нужна только вашим пользователям, а для них есть порты 587 и 465. AUTH на 25-м порту не даёт ничего полезного, зато открывает круглосуточному брутфорсу дополнительную мишень. Переведите клиентов на submission и уберите AUTH с 25-го.
Почему по умолчанию стоит defer_unauth_destination, а не reject_unauth_destination?
Это намеренно мягкое умолчание: свежеустановленный сервер с недонастроенными доменами будет возвращать временную ошибку 4xx, и почта не потеряется, а полежит в очереди отправителя. В проде я меняю на reject_unauth_destination — постоянный отказ 554 сразу сообщает отправителю правду. Мягкий вариант оправдан, пока вы перекраиваете список обслуживаемых доменов.
Источники
- Postfix SMTPD_ACCESS_README — «Postfix SMTP relay and access control», разделы «Delayed evaluation of SMTP access restriction lists» и описание порядка вычисления списков (каждый список читается слева направо до PERMIT/REJECT/DEFER, конец списка = PERMIT) — https://www.postfix.org/SMTPD_ACCESS_README.html
- postconf(5), Postfix 3.11 — Умолчания и описания параметров smtpd_relay_restrictions (default: permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination; появился в Postfix 2.10), reject_unauth_destination, relay_domains (Postfix ≥ 3.0: empty), mynetworks_style (Postfix ≥ 3.0: host), smtpd_delay_reject, smtpd_relay_before_recipient_restrictions (Postfix 3.6+) — https://www.postfix.org/postconf.5.html ; там же требование: smtpd_relay_restrictions или smtpd_recipient_restrictions должен содержать reject, reject_unauth_destination, defer, defer_if_permit или defer_unauth_destination
- Postfix COMPATIBILITY_README — Список backwards-compatible умолчаний по уровням: < 1 — smtpd_relay_restrictions=(empty); < 2 — mynetworks_style=subnet и relay_domains=$mydestination; < 3.6 — smtpd_relay_before_recipient_restrictions=no — https://www.postfix.org/COMPATIBILITY_README.html
- Исходники Postfix, src/global/mail_params.h — Определения DEF_RELAY_CHECKS, DEF_RCPT_CHECKS (пустой), DEF_RELAY_DOMAINS и DEF_MYNETWORKS_STYLE с привязкой к compatibility_level; константа LAST_COMPAT_LEVEL = 3.11 — https://github.com/vdukhovni/postfix/blob/master/postfix/src/global/mail_params.h
- Postfix stable release 3.11.7 — Анонс стабильного релиза 3.11.7 и legacy-релизов 3.10.14, 3.9.15, 3.8.21, 3.7.23 от 7 сентября 2026 — https://www.postfix.org/announcements/postfix-3.11.7.html
- access(5) — Postfix SMTP server access table: действия OK (accept) и DUNNO (pretend that the lookup key was not found) — https://www.postfix.org/access.5.html
- Postfix SASL_README — «Postfix SASL Howto», раздел о разрешении пересылки аутентифицированным клиентам (permit_sasl_authenticated в smtpd_relay_restrictions) и настройке submission — https://www.postfix.org/SASL_README.html
- Postfix BASIC_CONFIGURATION_README — Разделы «What relay destinations to accept from strangers» и «What clients to relay mail from» (mynetworks, mynetworks_style, relay_domains) — https://www.postfix.org/BASIC_CONFIGURATION_README.html
