Автоответчик mailcow молчит на catch-all: причина и фикс
АйТи Фреш
Linux, Docker и DevOps

Автоответчик mailcow отвечает на основной адрес, но молчит на catch-all: почему и как исправить

Автор: , директор ООО «АйТи-Фреш» · · ~13 мин чтения
Автоответчик mailcow отвечает на именной адрес, но молчит на письмо, пришедшее через catch-all
Один и тот же автоответчик, но письмо, дошедшее через catch-all, не проходит проверку получателя в Sieve.

Сотрудник в отпуске поставил автоответ, письма на его личный адрес получают ответ, а те же письма на catch-all-ящик компании — тишина. Это не баг и не сломанный Sieve: с 21 июля 2021 года mailcow сознательно проверяет получателя перед vacation-ответом, и catch-all эту проверку не проходит по умолчанию. Разбираю механику и то, как включить ответ адресно, не открывая компанию для backscatter-спама.

Симптом: одному адресу отвечает, другому — нет

Классическая картина: в корпоративной почте на mailcow сотрудник уходит в отпуск, ставит vacation-автоответ через веб-почту SOGo, всё работает — письма на его личный ящик ivanov@domain.ru получают автоматический ответ мгновенно. Но у компании есть общий адрес info@domain.ru, реализованный как catch-all (все письма на несуществующие адреса домена сваливаются в один ящик), и на него тот же самый автоответ включён, но молчит. Отправитель пишет — ответа нет, хотя письмо доставлено и лежит в ящике.

Первая реакция администратора — грешить на сломанный Sieve-скрипт: полезть в контейнер dovecot, посмотреть, скомпилировался ли .sieve в .svbin, проверить синтаксис. Это тупиковый путь: скрипт компилируется нормально, ошибок в логах Dovecot нет, а vacation просто тихо не срабатывает — без единой строки в error.log, которую можно было бы загуглить.

На деле проблема не в конфигурации конкретного ящика и не в синтаксисе Sieve, а в том, как Dovecot вообще решает, отвечать ли на письмо. Это решение завязано на параметр, который в mailcow один на весь сервер, и с 2021 года он по умолчанию выключает автоответ именно для писем, у которых получатель не совпадает буквально с адресом ящика — а catch-all по определению принимает письма на адреса, которых в системе официально не существует. Если в компании вообще ещё не настроена серверная фильтрация почты через Sieve, разобраться с логикой vacation-правил стоит заодно с базовыми фильтрами — они используют один и тот же движок.

Почему так: проверка получателя в Sieve vacation и история mailcow

RFC 5230 (раздел 4.5), описывающий Sieve-расширение vacation, прямо требует (MUST NOT): автоответчик не должен отвечать на письмо, если адрес получателя-пользователя не встречается в заголовках To, Cc, Bcc, Resent-To, Resent-Cc или Resent-Bcc. Адрес считается «своим» тремя способами — реализация знает его сама, это конечный envelope-адрес доставки, либо он явно перечислен в параметре :addresses самого vacation-правила.

На catch-all-ящике это условие почти никогда не выполняется естественным образом: письмо адресовано, например, на sales@domain.ru, которого как отдельного ящика не существует, Postfix доставляет его в catch-all-mailbox info@domain.ru по правилам маршрутизации — а в заголовках To: стоит sales@domain.ru, а не info@domain.ru. Формально для Sieve это письмо «не адресовано» владельцу ящика, и по RFC вообще отвечать не положено.

До 21 июля 2021 года mailcow обходил эту проверку глобально: параметр Dovecot sieve_vacation_dont_check_recipient стоял в yes, и vacation отвечал вообще на любое письмо независимо от получателя — в том числе на catch-all. Проект сознательно сменил значение на no по умолчанию и вынес это отдельной страницей в документацию, потому что глобальный обход проверки получателя — это готовый механизм backscatter: спамер шлёт письма на случайные несуществующие адреса домена (в том числе с поддельным From: реального человека), catch-all их принимает, а автоответчик безусловно отвечает на этот поддельный адрес — компания начинает рассылать спам-эхо по всему интернету от своего имени.

Важно понимать, что это изменение не привязано к конкретной версии mailcow как к разовому патчу — это смена поведения по умолчанию для новых установок и для тех, кто явно не переопределял параметр вручную. Если администратор никогда не переопределял этот параметр руками (в mailcow для этого служит data/conf/dovecot/extra.conf), значение сейчас no: штатный dovecot.conf приходит из репозитория и обновляется вместе с update.sh, и молчание на catch-all — ожидаемое поведение системы, а не деградация после обновления. Если же сервер живёт с 2019–2020 года и его кто-то «чинил» вручную, стоит явно проверить текущее значение командой docker compose exec dovecot-mailcow doveconf -n | grep dont_check_recipient, а не полагаться на предположение.

Схема: почему vacation-автоответ mailcow срабатывает на именной адрес и не срабатывает на catch-all без :addresses
Дело не в поломке — Sieve буквально сверяет адрес получателя с адресом ящика.

Как включить ответ на catch-all без побочных эффектов

Правильный путь после смены дефолта в 2021 году — не возвращать глобальный обход, а явно перечислить в самом vacation-правиле дополнительные адреса, которые тоже считаются «своими» для этого ящика — это ровно механизм :addresses из RFC 5230. В mailcow это делается через веб-почту: в SOGo — раздел настроек почты с автоответчиком (Preferences → Mail → Vacation) — есть поле для дополнительных адресов, на которые тоже нужно реагировать.

Для catch-all-ящика туда стоит вписывать не абстрактный список, а конкретные адреса, которые реально важны бизнесу и на которые вы готовы отвечать автоматически: sales@domain.ru, info@domain.ru, возможно ещё один-два адреса из старых визиток и форм на сайте. Каждый добавленный адрес — это явное решение «да, на письма сюда автоответ можно слать», а не слепой обход защиты для всего домена сразу.

Важный нюанс про интервал: параметр :days определяет период, за который отправителю не шлют повторный vacation-ответ. По RFC 5230 без :days действует 7 дней либо больший минимум сервера, но в mailcow Dovecot собран с расширением vacation-seconds, и в штатном data/conf/dovecot/dovecot.conf стоит sieve_vacation_default_period = 60s (минимум — 5s). SOGo обычно пишет :days в правило явно из своего поля интервала, а вот в самописном Sieve-скрипте без :days повтор уйдёт уже через минуту. Для catch-all-ящика, который получает рассылки-боты и автоматизированные системы чаще, чем личная почта, это единственное, что защищает от бесконечного пинг-понга автоответов; уменьшать это значение вручную без веской причины я не рекомендую.

Ещё один момент, который упускают почти всегда: список дополнительных адресов — это не разовая настройка «включил и забыл». Когда компания заводит новый алиас (например, отдел добавляет partners@domain.ru для внешних контактов), про него часто вспоминают только через неделю, когда первый партнёр жалуется, что писал и не получил даже автоматического подтверждения. Я рекомендую держать короткий регламент: любой новый алиас, который заводят на catch-all и на который планируют присылать автоответ, сразу же добавляется в список дополнительных адресов того же vacation-правила — это одна строка в чек-листе выдачи нового адреса, а не отдельная задача постфактум.

Почему не стоит просто вернуть глобальный обход

Соблазн очевиден: дописать в data/conf/dovecot/extra.conf строку sieve_vacation_dont_check_recipient = yes внутри блока plugin { } (в штатном dovecot.conf mailcow этого параметра сейчас вообще нет — действует умолчание Dovecot no), перезапустить dovecot-mailcow и получить рабочий автоответ на catch-all за одну правку. Формально это сработает — и именно поэтому так было по умолчанию до июля 2021 года. Но это решение действует на весь почтовый сервер сразу, для всех доменов и всех ящиков, а не только для одного catch-all, который вы хотели починить.

На практике это означает: любое письмо с поддельным From:, отправленное на любой несуществующий адрес любого домена на этом сервере, если у соответствующего catch-all-ящика включён vacation, получит автоматический ответ. Это ровно тот сценарий backscatter, из-за которого IP сервера имеет все шансы попасть в DNSBL — включая Spamhaus, после чего проблемы с доставкой получит уже вся компания.

Я в своей практике глобальный флаг не трогаю ни на одном клиентском сервере — только точечные :addresses в конкретных vacation-правилах, которые нужны бизнесу. Это чуть дольше на старте (нужно явно перечислить адреса, а не поставить один флаг), но избавляет от риска, что через полгода сервер окажется в блок-листах из-за автоответов на спам-рассылки, которые никто не отслеживал. Похожая логика «не давать глобальный обход ради локального удобства» стояла за разбором уязвимости в шаблоне mailcow, которая тоже открывала доступ шире, чем требовалось конкретной задаче.

Не включайте sieve_vacation_dont_check_recipient=yes глобально ради одного catch-all-ящика — это открывает backscatter для всех доменов на сервере разом.
Сравнение глобального обхода проверки получателя и точечных дополнительных адресов в vacation mailcow
Глобальный флаг решает проблему на пять минут быстрее и создаёт риск на годы вперёд.

Кейс: «СвязьЛиния», общий ящик поддержки на catch-all

Клиент — телекоммуникационный провайдер «СвязьЛиния», 46 рабочих мест. Похожую задачу — перевод компании на собственный mailcow с публичной почты — мы решали и для другого клиента, но здесь сервер уже был развёрнут, и требовалось только донастроить автоответ. У «СвязьЛинии» исторически было настроено несколько адресов техподдержки: support@, noc@, abuse@ — все они собирались в один catch-all-ящик catchall@domain.ru, который читает дежурная смена. При переходе на новый регламент захотели включить автоответ «заявка принята, среднее время реакции — 20 минут» на все три адреса разом, но настроили vacation только на самом catch-all-ящике и не понимали, почему письма на support@ молчат, а на сам catchall@ (по прямой ссылке, которую никто не использует) — отвечают.

Разбор занял около часа: подняли документацию mailcow по этому конкретному кейсу, проверили дату смены дефолта, убедились, что sieve_vacation_dont_check_recipient на сервере клиента стоит no (как и должно быть — сервер разворачивался в 2024 году, историческое значение yes там никогда не стояло). Дальше — просто добавили support@domain.ru, noc@domain.ru, abuse@domain.ru в поле дополнительных адресов vacation-правила catch-all-ящика через SOGo.

После правки автоответ пошёл на все три адреса в течение первого же тестового письма — задержки не было, перезапуск сервисов не потребовался: Sieve-правило пересобирается сразу при сохранении из SOGo. Отдельно предупредил дежурную смену: если понадобится добавить четвёртый адрес техподдержки, это те же два клика в интерфейсе, а не заявка на изменение конфигурации сервера.

Отдельно проговорили с клиентом риск, из-за которого я категорически отказался включать глобальный обход, хотя дежурная смена изначально просила «сделать быстрее». У «СвязьЛинии» как у телеком-провайдера есть публичные формы обратной связи на сайте и десятки внешних интеграций, которые шлют письма на технические адреса компании — это ровно та среда, где боты и спамеры массово перебирают несуществующие адреса на домене. Обход проверки получателя на всём сервере в такой ситуации означает не «автоответ на catch-all заработает», а «сервер начнёт автоматически отвечать на любой спам, адресованный на любой выдуманный адрес домена» — и это первый шаг к попаданию в DNSBL.

Чек-лист: диагностика автоответчика на catch-all за 10 минут

Если автоответ молчит именно на catch-all-адресах, а на именные ящики работает — не тратьте время на пересборку Sieve-скриптов и перезапуск dovecot-mailcow. В 9 случаях из 10 причина ровно в проверке получателя, и лечится она на уровне интерфейса, без правок серверных конфигов.

Порядок действий: убедитесь, что vacation вообще включён на нужном ящике в SOGo; проверьте, что адрес, на который реально приходит письмо (алиас, попадающий в catch-all), внесён в дополнительные адреса этого vacation-правила; убедитесь, что письмо от тестового отправителя не попадает под :days-подавление повторных ответов (если вы уже тестировали пять минут назад — подождите или используйте другой тестовый ящик); и только после этого лезьте в логи Dovecot командой docker compose exec dovecot-mailcow doveadm log errors, если проблема не в этом.

Отдельно зафиксируйте для себя список алиасов, у которых включён vacation на catch-all — на практике таких обычно немного (в проектах, что я вёл, от одного до пяти на компанию), и держать его актуальным вручную проще, чем автоматизировать. При смене состава сотрудников, заводящих новые публичные адреса, эта короткая проверка занимает меньше времени, чем один разбор жалобы клиента на молчащий автоответ.

Чек-лист из пяти шагов диагностики автоответчика mailcow на catch-all-адресах
В большинстве случаев чинится в интерфейсе SOGo, без единой правки конфигов сервера.

Частые вопросы

Можно ли настроить автоответ сразу на весь домен, а не перечислять адреса вручную?

Через штатный механизм — нет, и это осознанное ограничение mailcow: перечисление конкретных адресов в :addresses защищает от backscatter. Если адресов много и они меняются часто, проще завести отдельный процесс актуализации списка в SOGo, чем включать глобальный обход.

Автоответ на catch-all работал до обновления mailcow, а после перестал — что случилось?

Скорее всего сервер обновлялся через промежуточную версию, где менялся дефолт sieve_vacation_dont_check_recipient (граница — 21 июля 2021 года), и старое значение yes при обновлении не сохранилось или было сброшено. Проверьте текущее значение и переходите на явные адреса в :addresses, а не возвращайте старое поведение.

Что будет, если не добавить адрес в :addresses, а просто включить vacation на catch-all-ящике?

Vacation формально включён, но Sieve проверит заголовки To/Cc/Bcc письма и не найдёт там адрес, который сервер считает «своим» для этого ящика — ответ не уйдёт. Внешне это выглядит как «автоответчик не работает», хотя правило настроено верно.

Сколько дополнительных адресов можно указать в :addresses для одного ящика?

RFC 5230 не задаёт жёсткого лимита на количество адресов в :addresses, ограничение обычно практическое — удобство сопровождения списка. Для типового catch-all с 3–5 алиасами это не проблема.

Влияет ли :days на то, что автоответ вообще не срабатывает на новый адрес?

Нет, :days влияет только на повторные ответы одному и тому же отправителю в пределах периода (по RFC — 7 дней, в штатном конфиге mailcow без явного :days — 60 секунд) — на первое письмо с нового адреса это ограничение не действует.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи