Core tiene un punto de finalización (endpoint) funcional para rebotes de Mandrill — POST /webhooks/mandrill en WebhooksController — que procesa eventos de hard_bounce y soft_bounce, aplica hard_bounce_score / soft_bounce_score y deshabilita las direcciones que superan el bounce_score_threshold. El emparejamiento se basa en la cabecera message_id de X-MC-Metadata que Email::Sender añade cuando DISCOURSE_SMTP_ADDRESS es exactamente smtp.mandrillapp.com.
Estaba intentando configurarlo, pero me encontré con algunos problemas que pensé que valía la pena compartir por si ayudan a otros. Sé que es un caso de uso de nicho, ya que Mandrill dejó de ofrecer «solo SMTP» hace más de una década y solo ahora proporciona el servicio SMTP como un complemento del producto de correo transaccional de Mailchimp. No obstante, uno de mis clientes tenía exactamente esta configuración, ¡así que aquí estamos!
1. No está documentado en ningún lugar que pueda encontrar. El tema de VERP no lo menciona, lo cual es razonable, porque VERP no es la forma en que funciona Mandrill: la propia documentación de Mailchimp indica que gestiona los rebotes por sí mismo incluso cuando se configura un dominio Return-Path personalizado, por lo que los rebotes por mensaje nunca llegan a un receptor de correo autoalojado. Los webhooks del proveedor son el único camino, y no hay ninguna referencia obvia a ellos para quien comience desde el tema de VERP.
2. El webhook no se puede crear realmente. WebhooksController#mandrill devuelve 406 siempre que mandrill_authentication_key esté vacío. Ese comportamiento es intencional: es la corrección para CVE-2026-26077 (Discourse 2025.12.2 / 2026.1.1 / 2026.2.0), que cerró la forja no autenticada de cargas de rebotes en los puntos de finalización de SendGrid, Mailjet, Mandrill, Postmark, SparkPost y Mailpace. Por lo tanto, esto no es una solicitud para relajarlo; el problema es que la corrección dejó a Mandrill sin forma de inicializarse.
Mandrill valida un nuevo webhook con un POST (no el HEAD para el que se escribió mandrill_head), ve el 406 y se niega a guardar el webhook; por lo tanto, la clave que se necesita nunca es visible. La ruta de la API falla de la misma manera:
{"status":"error","code":-98,"name":"ValidationError","message":"Unable to validate webhook URL"}
Registro de origen para un intento desde la interfaz de usuario:
"POST /webhooks/mandrill HTTP/2.0" "Mandrill-Webhook/1.0" 406
Los otros proveedores tienen tokens a nivel de cuenta, por lo que un administrador puede establecer un secreto arbitrario antes de crear el webhook. La clave de Mandrill se emite por webhook, solo después de que el webhook se guarda; por lo tanto, es un callejón sin salida (Catch-22).
Estoy bastante seguro de que el flujo podría corregirse, quizás respondiendo con 200 a la primera verificación (que no tiene una carga de mandrill_events), permitiendo la creación en Mandrill, y luego la clave puede copiarse manualmente a Discourse, y listo. Estaré encantado de abrir una PR si eso fuera aceptable.
3. Solución temporal, por si alguien la necesita hoy. Cree el webhook contra una URL que ya devuelva 200, sin desencadenantes (las cargas de rebote contienen direcciones de destinatarios, por lo que nunca apunte un webhook con desencadenantes a un marcador), luego instale la clave y muévela:
# 1. crear contra un marcador, sin eventos
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. poner la auth_key devuelta en la configuración del sitio mandrill_authentication_key
# 3. reorientar al foro y habilitar desencadenantes - esto ahora pasa la validación
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"]}'
Probado en 2026.9.0-latest.