Le cœur du système dispose d’un point de terminaison Mandrill fonctionnel pour les rebonds - POST /webhooks/mandrill dans WebhooksController - qui traite les événements hard_bounce et soft_bounce, applique hard_bounce_score / soft_bounce_score et désactive les adresses ayant dépassé bounce_score_threshold. L’identification repose sur l’en-tête message_id de X-MC-Metadata que Email::Sender ajoute lorsque DISCOURSE_SMTP_ADDRESS est exactement smtp.mandrillapp.com.
J’essayais de configurer cela, mais j’ai rencontré quelques problèmes que je jugeais utile de partager au cas où cela aiderait d’autres personnes. Je sais qu’il s’agit d’un cas d’usage de niche, car Mandrill a cessé de proposer « juste du SMTP » il y a plus de dix ans, et ne propose désormais le service SMTP que comme add-on au produit d’e-mails transactionnels de Mailchimp. Néanmoins, l’un de mes clients avait exactement cette configuration, et nous en sommes là !
1. Ce n’est documenté nulle part que je puisse trouver. Le sujet sur le VERP n’en mentionne pas, ce qui est compréhensible, car le VERP n’est pas la façon dont Mandrill fonctionne : la documentation de Mailchimp elle-même indique qu’il gère les rebonds lui-même, même si vous configurez un domaine Return-Path personnalisé, de sorte que les rebonds par message n’atteignent jamais un récepteur d’e-mails auto-hébergé. Les webhooks du fournisseur sont le seul chemin, et il n’y a pas de référence évidente vers eux pour quiconque commence par le sujet sur le VERP.
2. Le webhook ne peut pas réellement être créé. WebhooksController#mandrill renvoie 406 chaque fois que mandrill_authentication_key est vide. Ce comportement est intentionnel - c’est le correctif pour CVE-2026-26077 (Discourse 2025.12.2 / 2026.1.1 / 2026.2.0), qui a fermé la porte à la falsification non authentifiée de charges utiles de rebond sur les points de terminaison SendGrid, Mailjet, Mandrill, Postmark, SparkPost et Mailpace. Il ne s’agit donc pas d’une demande de relâchement de la sécurité ; c’est que le correctif a laissé Mandrill sans moyen de démarrage.
Mandrill valide un nouveau webhook avec un POST (et non le HEAD pour lequel mandrill_head avait été écrit), voit le 406 et refuse d’enregistrer le webhook - de sorte que la clé dont vous avez besoin n’est jamais visible. Le chemin API échoue de la même manière :
{"status":"error","code":-98,"name":"ValidationError","message":"Unable to validate webhook URL"}
Journal d’origine pour une tentative via l’interface utilisateur :
"POST /webhooks/mandrill HTTP/2.0" "Mandrill-Webhook/1.0" 406
Les autres fournisseurs ont des jetons au niveau du compte, de sorte qu’un administrateur peut définir un secret arbitraire avant de créer le webhook. La clé de Mandrill est émise par webhook, uniquement après l’enregistrement du webhook - c’est donc un dilemme.
Je suis presque sûr que le flux pourrait être corrigé, peut-être en répondant 200 à la première vérification (qui n’a pas de charge utile mandrill_events), en permettant la création sur Mandrill, puis le secret peut être copié manuellement dans Discourse, et nous sommes parés. Je serais ravi d’ouvrir une PR si cela était acceptable.
3. Contournement, si quelqu’en a besoin aujourd’hui. Créez le webhook contre une URL qui renvoie déjà 200, sans déclencheurs (les charges utiles de rebond contiennent des adresses de destinataires, ne pointez donc jamais un webhook déclenché vers un espace réservé), puis installez la clé dans Discourse, et une fois cela fait, déplacez l’URL du webhook :
# 1. créer contre un espace réservé, sans événements
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. mettre la clé d'authentification retournée dans le paramètre de site mandrill_authentication_key
# 3. rediriger vers le forum et activer les déclencheurs - cela passe maintenant la validation
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"]}'
Testé sur 2026.9.0-latest.