Переношу письма в «Спам» в Outlook — Rspamd в mailcow правда на этом учится?
Короткий ответ: да, но только если письмо попадает в серверную папку с именем Junk и обратно, а не в любую папку «для спама». В mailcow за это отвечает связка Dovecot imapsieve и статистика Bayes в Redis, и без проверки легко решить, что обучение «не работает», хотя оно просто не видит ваших действий. Разбираю механизм, как убедиться, что он реально включён, и когда стоит сбросить модель после накопленных ошибок.
Кейс: сотрудники «дрессируют» спам-фильтр вручную, а толку не видно
«Книжная гавань» — книжный магазин, 35 рабочих мест, склад и интернет-магазин, вся переписка с поставщиками и покупателями идёт через корпоративную почту на mailcow. Осенью в отдел закупок стало приходить много спама под видом рассылок от типографий — не откровенный мусор, а достаточно правдоподобные письма, которые Rspamd пропускал во «Входящие». Администратор дал сотрудникам простую инструкцию: видите спам — тащите в «Спам» в Outlook. Через две недели картина не изменилась: похожие письма продолжали идти мимо фильтра, а часть легитимных писем от нового поставщика, наоборот, стала падать в Junk без видимой причины.
Логичный вопрос, с которым к нам обратились: «мы же вручную помечаем спам каждый день, почему Rspamd как будто не учится?» Проверка началась с самого простого — а точно ли перенос письма в Outlook доходит до Dovecot как ожидаемое действие, а не как обычное перемещение файла между папками IMAP. Дело в том, что «учится на переносе в спам» — не магия и не встроенное поведение любого антиспам-движка по умолчанию: это конкретный механизм, который либо настроен и работает, либо нет, и по внешнему виду почтового клиента понять это невозможно.
Выяснилось: часть сотрудников пользовалась не стандартной папкой Junk, а создала свою папку «Спам-нежелательное» — так исторически повелось с прошлого почтового сервера. Rspamd её не видел вообще, потому что триггер обучения в mailcow завязан на серверную папку с точным именем Junk, а не на любую папку с похожим названием. Вторая часть проблемы — легитимные письма поставщика, которые начали залетать в Junk: их туда перенёс один сотрудник по ошибке в первый день эксперимента, и с этого момента фильтр честно обучился считать их спамом. Обе причины лежат не в самом Rspamd, а в том, как устроена связка Dovecot-Rspamd на уровне протокола IMAP.
- перенос в «свою» папку с названием вроде «Спам-нежелательное» обучение не запускает
- обучение запускается только папкой с серверным именем Junk, а не любой папкой с похожим смыслом
- случайный перенос легитимного письма в Junk — тоже обучение, только в обратную сторону
Как на самом деле устроено обучение: imapsieve, а не магия клиента
Механизм обучения в mailcow работает не на стороне Outlook или веб-почты, а на стороне Dovecot — почтовый клиент здесь только выполняет обычную операцию IMAP MOVE, а дальше в дело вступает плагин imapsieve. Документация mailcow формулирует это прямо: перенос сообщения в папку junk обучает Rspamd как спам, а перенос ИЗ неё в любую папку, кроме Trash, обучает как ham — то есть как легитимное письмо. Перенос в Trash не обучает ничего, это просто удаление. Отдельно документация упоминает автообучение: письма с очень высокой или очень низкой оценкой Rspamd учит сам, без участия пользователей.
Технически это sieve_imapsieve — часть конфигурации Dovecot, которая слушает события перемещения сообщений между папками и по этим событиям запускает Sieve-скрипты report-spam.sieve и report-ham.sieve. Если открыть эталонный dovecot.conf, видно главное: правило imapsieve_mailbox1_name = Junk срабатывает на папку с именем именно Junk, а report-ham.sieve пропускает только перенос в папку с именем ровно Trash. Атрибут \Junk при этом ни при чём: в dovecot.folders.conf mailcow помечает им ещё и «Spam», «Junk E-Mail», «Нежелательная почта», «Спам», но imapsieve на них не реагирует. Скрипты через pipe отдают письмо Rspamd на обучение. Важная деталь: обучение происходит на уровне Dovecot, поэтому оно работает одинаково для любого почтового клиента, который умеет IMAP MOVE — Outlook, Thunderbird, веб-интерфейс SOGo или мобильное приложение. Специфики под конкретный клиент тут нет, разница может быть только в том, как клиент физически перемещает письмо: правило в mailcow настроено на событие COPY, а IMAP MOVE для imapsieve выглядит так же, поэтому и MOVE, и COPY+DELETE обучают одинаково. Проблемы начинаются, когда клиент кладёт «спам» не в серверную Junk, а в свою папку или вообще в локальный файл данных.
Соответственно, диагностика жалобы «не учится» всегда должна начинаться не с Rspamd, а с проверки, что письмо реально долетело до правильной папки на сервере IMAP, а не осело в локальном кэше клиента или в неправильной папке. Это и произошло в «Книжной гавани» — визуально в Outlook у сотрудника была папка «Спам», но фактически это была обычная пользовательская папка, не связанная с серверной папкой Junk.
- обучение запускает не клиент, а Dovecot через imapsieve при событии перемещения письма
- перенос В Junk = учим как spam; перенос ИЗ Junk в любую папку кроме Trash = учим как ham; «Корзина» с другим именем обучит как ham
- перенос в Trash не обучает ничего — это просто удаление
- механизм универсален для любого IMAP-клиента: важно лишь, в какую серверную папку попало письмо
Где физически хранится модель и как её увидеть
Статистика Bayes у Rspamd в mailcow не файл на диске, а данные в Redis. Документация прямо указывает: байесовская статистика пишется в Redis под ключами BAYES_HAM и BAYES_SPAM. Отдельно, для похожих, но не идентичных писем, используется локальное Fuzzy-хранилище — оно ловит повторяющиеся паттерны в тексте или изображениях, характерные для конкретной волны спама, и это отдельный механизм от Bayes, хотя оба участвуют в общей оценке письма.
Заглянуть в статистику Bayes из командной строки можно через redis-cli с паролем из mailcow.conf:
docker compose exec redis-mailcow redis-cli -a "$(grep -oP '(?<=REDISPASS=).*' mailcow.conf)" --scan --pattern 'BAYES_*'Куда информативнее — веб-интерфейс Rspamd, доступный на mailcow по адресу /rspamd/ (пароль к нему задаётся отдельно в админке mailcow): там на вкладке статистики видно суммарное число токенов в классах spam и ham, а на вкладке истории — что конкретно движок посчитал причиной оценки письма (символ BAYES_SPAM или BAYES_HAM в списке сработавших правил означает, что статистическая модель поучаствовала в решении). Если у вас в истории по подозрительным письмам символ BAYES_SPAM не появляется вообще ни разу за последние дни — это самый надёжный признак, что обучение фактически не идёт, даже если сотрудники честно переносят письма в правильную папку.
Для ручного дообучения отдельных сообщений вне механизма imapsieve — например, если нужно скормить фильтру архив уже накопленного спама — mailcow (как и любая инсталляция Rspamd) поддерживает прямые команды через rspamc:
# с хоста, из каталога mailcow-dockerized; письма в несжатом виде
for file in /my/folder/.Junk/cur/*; do docker exec -i $(docker compose ps -q rspamd-mailcow) rspamc learn_spam < "$file"; done
for file in /my/folder/cur/*; do docker exec -i $(docker compose ps -q rspamd-mailcow) rspamc learn_ham < "$file"; doneТакой ручной прогон полезен разово, при переносе большого архива уже классифицированных писем, но не заменяет постоянный механизм imapsieve — он должен продолжать работать сам по себе на текущей переписке.
- статистика Bayes — не файл, а ключи BAYES_HAM/BAYES_SPAM в Redis
- Fuzzy-хранилище — отдельный механизм для похожих писем, не путать с Bayes
- веб-интерфейс /rspamd/ → История: символ BAYES_SPAM/BAYES_HAM в сработавших правилах = модель участвовала в оценке
- rspamc learn_spam / learn_ham — для разового ручного дообучения архивом, не замена постоянному imapsieve
Проверка на живом сервере: диагностика imapsieve по логам
Если внешне всё настроено правильно, а обучение по ощущениям не работает, следующий шаг — заглянуть в отладочные логи, а не гадать по косвенным признакам. Я включаю отладку конкретных модулей Rspamd (debug_modules — штатный параметр логирования Rspamd) через отдельный файл logging.custom.inc: сам override.d/logging.inc в mailcow лежит в git и подключает этот файл, если он есть, так что обновление правку не затрёт:
# на хосте, в каталоге mailcow-dockerized
# override.d/logging.inc — файл mailcow из git, он сам подключает logging.custom.inc
cat > data/conf/rspamd/override.d/logging.custom.inc <<'EOF'
debug_modules = ["fuzzy_backend", "bayes"];
EOF
docker compose restart rspamd-mailcowПосле этого в логе контейнера появляются записи о каждом обращении к байесовскому и fuzzy-модулям — в том числе события обучения. Смотреть удобнее сразу с фильтром, потому что подробный лог быстро становится многословным:
docker compose logs -f --tail=200 rspamd-mailcow | grep -iE 'bayes|learn'Затем в почтовом клиенте вручную переносите тестовое письмо в Junk и наблюдаете за логом в реальном времени: должна появиться запись об обучении с указанием класса (spam/ham) и токенов. Если события нет вообще — проблема на уровне Dovecot и imapsieve, стоит проверить конфигурацию sieve_imapsieve в data/conf/dovecot/dovecot.conf (в mailcow это эталонный файл, который поставляется с проектом, и вручную его лучше не редактировать, а искать отклонения от актуальной версии на GitHub). Если событие есть, но статистика Bayes в интерфейсе не растёт — уже вопрос к доступу Rspamd к Redis или к конфигурации классификатора в local.d/statistic.conf.
Не забудьте выключить расширенное логирование после диагностики — оно ощутимо увеличивает объём логов контейнера, и оставлять его постоянно включённым на боевом сервере смысла нет. Для «Книжной гавани» диагностика заняла один вечер: два сотрудника действительно писали в непривязанную папку, ещё у одного Outlook складывал спам в серверную папку «Нежелательная почта» — у неё есть атрибут \Junk, но имя не Junk, и imapsieve её игнорировал. После пересоздания профиля и перевода всех на серверную папку Junk обучение пошло штатно, и уже через десять дней доля ложных срабатываний по легитимным поставщикам заметно снизилась.
- debug_modules = ["fuzzy_backend", "bayes"] в override.d/logging.custom.inc — не трогая файл из git
- тестовый перенос письма в Junk с логом в реальном времени — самый быстрый способ увидеть, работает ли обучение
- нет события в логе → проблема в Dovecot/imapsieve; событие есть, а статистика не растёт → проблема в доступе Rspamd к Redis или в statistic.conf
- после диагностики отладочное логирование обязательно выключить
Зачем иногда рекомендуют сбросить Bayes и как не задеть остальные данные Redis
Отдельная ситуация — когда обучение технически работает годами, но фильтр всё равно ошибается чаще, чем должен. Причина может быть не в механизме доставки обучающих сигналов, а в самой модели: если в неё долго попадали противоречивые сигналы (сотрудники по-разному оценивали похожие письма, часть спама вручную не переносили, часть легитимных писем ошибочно улетала в Junk), статистика может накопить перекос, который проще сбросить и накопить заново, чем распутывать.
У этого есть и историческая точка отсчёта: в релизе mailcow 2024-08 обновление Rspamd сопровождалось рекомендацией разово сбросить данные Bayes — с явной оговоркой, что это не обязательный шаг, а мера на усмотрение администратора. Причина была в том, что core-токены модели могли продолжать влиять на оценку даже после истечения срока действия остальных токенов, что потенциально вело к переобучению. К сегодняшнему дню, 23 сентября 2026 года, mailcow ушёл далеко вперёд — актуальная ветка обновлений 2026-07 несёт Rspamd версии 4.1.x, и сама рекомендация 2024 года уже не актуальна как обязательная процедура, но сам приём сброса Bayes остаётся рабочим инструментом на случай, когда модель действительно перекошена.
Документация mailcow для этой операции требует аккуратности: сначала сделать копию dump.rdb Redis на случай отката, затем удалить именно байесовские ключи по шаблону, а не всю базу целиком — в том же Redis mailcow хранит настройки fail2ban (F2B_*), DKIM-ключи, лимиты и другие данные, которые трогать нельзя.
cd /opt/mailcow-dockerized && source mailcow.conf
# 1. Сбросить Redis на диск и скопировать dump.rdb — обязательно
docker compose exec redis-mailcow redis-cli -a "$REDISPASS" SAVE
cp /var/lib/docker/volumes/mailcowdockerized_redis-vol-1/_data/dump.rdb /root/dump.rdb.$(date +%F)
# 2. Удаление ключей Bayes и связанных RS*-структур точечно по шаблону (как в документации)
docker compose exec redis-mailcow sh -c \
"redis-cli -a '$REDISPASS' --scan --pattern 'BAYES_*' | xargs -r redis-cli -a '$REDISPASS' del"
docker compose exec redis-mailcow sh -c \
"redis-cli -a '$REDISPASS' --scan --pattern 'RS*' | xargs -r redis-cli -a '$REDISPASS' del"Ключ -r у xargs я добавляю специально: в документации его нет, и если по шаблону ничего не нашлось, del запускается без аргументов и отвечает «wrong number of arguments for del». Это не сбой, а признак, что удалять было нечего. Имя тома mailcowdockerized_redis-vol-1 зависит от COMPOSE_PROJECT_NAME — сверьте его через docker volume ls. После сброса модель начинает учиться заново с нуля, поэтому в первые дни стоит быть внимательнее к ложным срабатываниям и, если нужно, ускорить накопление статистики ручным прогоном rspamc learn_spam/learn_ham по свежему архиву уже классифицированных писем.
- сброс Bayes в mailcow 2024-08 был рекомендован, но не обязателен — к 2026 году это уже не актуальная директива, а инструмент по необходимости
- перед сбросом — SAVE и копия dump.rdb из тома redis-vol-1 на случай отката
- удалять только ключи по шаблону BAYES_* и RS*, не всю базу Redis целиком
- xargs -r не запускает del на пустом списке — без него ошибка «wrong number of arguments» означает «ничего не найдено»
Что я советую настроить сразу, чтобы не разбирать это по жалобам
Из этого и похожих разборов на других клиентах я вынес практику, которую теперь включаю в первичную настройку любого mailcow: убедиться, что у всех почтовых ящиков спам уходит именно в серверную папку Junk — mailcow создаёт её автоматически (auto = subscribe), а клиент подхватывает её как папку спама, если профиль настроен через автонастройку, а не собран вручную по старой памяти. Папки «Спам» или «Нежелательная почта», созданные клиентом рядом, обучение не запускают, даже с атрибутом \Junk.
Второе — короткая памятка для сотрудников без технических подробностей: «спам переносим строго в папку Спам/Junk, случайно попавшее туда легитимное письмо — переносим обратно во Входящие». Это закрывает оба сценария обучения одним предложением и не требует объяснять сотрудникам, что такое imapsieve или Bayes.
Третье — регулярный, но не навязчивый контроль: раз в квартал проверяю в веб-интерфейсе Rspamd долю писем с символом BAYES_SPAM/BAYES_HAM в общей истории. Если она стабильно близка к нулю при заметном объёме подозрительной почты — значит, где-то в цепочке снова сломалось обучение, и дешевле поймать это на плановой проверке, чем на жалобе клиента о пропущенном спаме или потерянном письме от поставщика.
И последнее: обучение через imapsieve — это дополнение к базовой антиспам-конфигурации, а не замена ей. Если у вас в принципе не настроены SPF, DKIM и DMARC на входящей и исходящей стороне, Bayes не вытянет качество фильтрации в одиночку — про базовую настройку у меня есть отдельный разбор DKIM, SPF и DMARC. А плановые проверки вроде этой я свёл в регламент эксплуатации mailcow.
- проверять, что спам попадает в серверную папку с именем Junk, а не в «Спам»/«Нежелательная почта»
- короткая памятка сотрудникам: спам — в Junk, ошибочно попавшее туда — обратно во Входящие
- раз в квартал сверять долю BAYES_SPAM/BAYES_HAM в истории Rspamd
- обучение Bayes не заменяет SPF/DKIM/DMARC — это разные уровни защиты
Частые вопросы
Перенос письма в «Спам» в Outlook точно обучает Rspamd в mailcow?
Да, но только если письмо попадает в серверную папку с именем Junk. В эталонном dovecot.conf mailcow правило imapsieve привязано к имени папки (imapsieve_mailbox1_name = Junk), поэтому своя папка «Спам» или «Нежелательная почта» обучение не запускает, даже если у неё есть атрибут \Junk.
Где посмотреть, что обучение реально происходит?
Проще всего — веб-интерфейс Rspamd (/rspamd/), вкладка История: если в списке сработавших правил по подозрительным письмам регулярно встречается символ BAYES_SPAM или BAYES_HAM, статистическая модель участвует в оценке. Для точечной диагностики можно временно включить debug_modules = ["bayes"] в override.d/logging.custom.inc и смотреть логи rspamd-mailcow в реальном времени при тестовом переносе письма.
Перенос письма в Корзину тоже чему-то учит фильтр?
Нет, если папка называется ровно Trash. Перенос в Junk обучает как spam, перенос из Junk в любую другую папку — как ham; report-ham.sieve пропускает только папку с именем Trash, поэтому «Корзина» с другим серверным именем обучит письмо как легитимное.
Нужно ли сбрасывать Bayes после каждого крупного обновления mailcow?
Нет, это не постоянная практика. Разовая рекомендация была актуальна для релиза 2024-08 из-за конкретного изменения в Rspamd. Сбрасывать статистику стоит только тогда, когда модель реально накопила перекос от противоречивого обучения — например, после периода, когда сотрудники массово ошибались с папками.
Как безопасно сбросить только статистику Bayes, не затронув остальные данные Redis?
Сначала выполнить SAVE в Redis и скопировать dump.rdb из тома redis-vol-1, затем удалить ключи точечно по шаблонам BAYES_* и RS* через redis-cli --scan вместе с xargs del — не трогая остальную базу, где mailcow хранит, например, DKIM-ключи и настройки fail2ban.
Можно ли обучить фильтр сразу большим архивом старого спама, не дожидаясь ручной сортировки почты?
Да, через rspamc learn_spam и rspamc learn_ham с файлами .eml — это разовый способ ускорить накопление статистики, например сразу после переноса на mailcow. Но он не заменяет постоянно работающий imapsieve на текущей переписке.
Источники
- docs.mailcow.email — Work with Spam Data — Проверено: механизм imapsieve (перенос в Junk = spam, из Junk кроме Trash = ham), ключи Redis BAYES_HAM/BAYES_SPAM, команды rspamc learn_ham/learn_spam, процедура Reset Bayes data с SAVE и точечным del по шаблонам BAYES_*/RS*. https://docs.mailcow.email/manual-guides/Rspamd/u-e-rspamd-work-with-spamdata/
- GitHub mailcow-dockerized — dovecot.conf (master) — Эталонная конфигурация Dovecot с sieve_imapsieve и скриптами report-spam.sieve/report-ham.sieve, актуальная на текущую ветку. https://github.com/mailcow/mailcow-dockerized/blob/master/data/conf/dovecot/dovecot.conf
- mailcow.email — Mooly 2026 (release-2026-07) — Проверена актуальная версия стека на 23.09.2026: Postfix 3.10.12, Rspamd 4.1.0 (далее обновлён до 4.1.4 в 2026-07a), Nginx 1.30.3, SOGo 5.12.9 — контекст для оценки актуальности исторической рекомендации 2024-08. https://mailcow.email/posts/2026/release-2026-07/
- mailcow.email — Moogust 2024 (release-2024-08) — Проверена историческая рекомендация об однократном (необязательном) сбросе Bayes после обновления Rspamd в релизе 15.08.2024. https://mailcow.email/posts/2024/release-2024-08/
- docs.rspamd.com — FAQ — Проверена общая логика статистических классификаторов Rspamd и назначение debug_modules для точечной отладки без включения полного debug-режима. https://docs.rspamd.com/faq/



