В ядре уже работает эндпоинт для обработки отписок Mandrill — POST /webhooks/mandrill в WebhooksController — который обрабатывает события hard_bounce и soft_bounce, применяет hard_bounce_score / soft_bounce_score и отключает адреса, превысившие bounce_score_threshold. Сопоставление основывается на заголовке message_id из X-MC-Metadata, который добавляет Email::Sender, если DISCOURSE_SMTP_ADDRESS точно равен smtp.mandrillapp.com.
Я пытался это настроить, но столкнулся с некоторыми проблемами, которые, возможно, стоит обсудить, чтобы помочь другим. Я понимаю, что это нишевый случай использования, так как Mandrill перестал предлагать «только SMTP» более десяти лет назад и теперь предоставляет SMTP-услуги только как дополнение к продукту Mailchimp для транзакционной почты. Тем не менее у одного из моих клиентов была именно такая настройка, и вот мы здесь!
1. Это нигде не задокументировано. В теме о VERP об этом не упоминается, что логично, так как VERP — это не то, как работает Mandrill: в собственной документации Mailchimp указано, что они обрабатывают отписки самостоятельно, даже если вы настроили собственную доменную область Return-Path, поэтому отписки по отдельным сообщениям никогда не достигают самостоятельно хостингуемого почтового сервера. Вебхуки провайдера — это единственный путь, и нет очевидной ссылки на них для тех, кто начинает с темы о VERP.
2. Вебхук фактически не может быть создан. WebhooksController#mandrill возвращает 406 каждый раз, когда mandrill_authentication_key пуст. Это поведение намеренное — это исправление для CVE-2026-26077 (Discourse 2025.12.2 / 2026.1.1 / 2026.2.0), которое закрыло возможность несанкционированной подделки пакетов отписок через эндпоинты SendGrid, Mailjet, Mandrill, Postmark, SparkPost и Mailpace. Поэтому это не просьба ослабить безопасность; проблема в том, что исправление оставило Mandrill без возможности начальной настройки (bootstrap).
Mandrill проверяет новый вебхук с помощью POST (а не HEAD, для которого был написан mandrill_head), видит 406 и отказывается сохранять вебхук — поэтому ключ, который вам нужен, никогда не отображается. Путь через API также терпит неудачу:
{"status":"error","code":-98,"name":"ValidationError","message":"Unable to validate webhook URL"}
Лог источника для попытки через интерфейс:
"POST /webhooks/mandrill HTTP/2.0" "Mandrill-Webhook/1.0" 406
У других провайдеров есть токены на уровне аккаунта, поэтому администратор может установить произвольный секрет до создания вебхука. Ключ Mandrill выпускается для каждого вебхука, только после его сохранения — так что это тупик (Catch-22).
Я почти уверен, что этот процесс можно исправить, возможно, ответив 200 на первую проверку (которая не содержит полезной нагрузки mandrill_events), что позволит создать вебхук в Mandrill, затем секрет можно будет вручную скопировать в Discourse, и всё заработает. Буду рад создать PR, если это приемлемо.
3. Обходной путь, если кому-то это нужно прямо сейчас. Создайте вебхук для URL, который уже возвращает 200, без триггеров (пакеты отписок содержат адреса получателей, поэтому никогда не указывайте вебхук с триггерами на заглушку), затем установите ключ и перенаправьте его:
# 1. создать для заглушки, без событий
curl -sS -X POST https://mandrillapp.com/api/1.0/webhooks/add.json \
-H 'Content-Type: application/json' \
-d '{"key":"<api-key>","url":"https://httpbin.org/status/200","description":"Discourse bounce handling","events":[]}'
# 2. поместите возвращенный auth_key в настройку сайта mandrill_authentication_key
# 3. перенаправьте на форум и включите триггеры - теперь проверка пройдена
curl -sS -X POST https://mandrillapp.com/api/1.0/webhooks/update.json \
-H 'Content-Type: application/json' \
-d '{"key":"<api-key>","id":<id>,"url":"https://<forum>/webhooks/mandrill","description":"Discourse bounce handling","events":["hard_bounce","soft_bounce"]}'
Проверено на 2026.9.0-latest.