Mandrill Bounce-Handling: im Kern unterstützt, aber (soweit ich das beurteilen kann) nicht dokumentiert

Core verfügt über einen funktionierenden Mandrill-Bounce-Endpunkt – POST /webhooks/mandrill in WebhooksController –, der hard_bounce- und soft_bounce-Ereignisse verarbeitet, hard_bounce_score / soft_bounce_score anwendet und Adressen deaktiviert, die den bounce_score_threshold überschreiten. Die Zuordnung erfolgt über den message_id-Header in X-MC-Metadata, den Email::Sender hinzfügt, wenn DISCOURSE_SMTP_ADDRESS exakt smtp.mandrillapp.com ist.

Ich habe versucht, dies einzurichten, bin aber auf einige Probleme gestoßen, die ich teilen wollte, falls es anderen hilft. Ich weiß, dass es sich um eine Nischenanwendung handelt, da Mandrill seit über einem Jahrzehnt keinen „reinen SMTP“-Dienst mehr anbietet und den SMTP-Dienst erst jetzt als Add-on zum transaktionalen E-Mail-Produkt von Mailchimp bereitstellt. Dennoch hatte einer meiner Kunden genau dieses Setup, und daher sind wir hier!

1. Es ist nirgends dokumentiert, wo ich es finden konnte. Das VERP-Thema erwähnt es nicht, was nachvollziehbar ist, da VERP nicht die Art und Weise ist, wie Mandrill funktioniert: Die eigenen Doku von Mailchimp besagt, dass es Bounces selbst behandelt, selbst wenn man eine benutzerdefinierte Return-Path-Domain konfiguriert, sodass Bounces pro Nachricht nie einen selbst gehosteten E-Mail-Empfänger erreichen. Die Provider-Webhooks sind der einzige Weg, und für jemanden, der vom VERP-Thema ausgeht, gibt es keinen offensichtlichen Hinweis darauf.

2. Der Webhook kann tatsächlich nicht erstellt werden. WebhooksController#mandrill gibt 406 zurück, wann immer mandrill_authentication_key leer ist. Dieses Verhalten ist absichtlich – es ist die Behebung von CVE-2026-26077 (Discourse 2025.12.2 / 2026.1.1 / 2026.2.0), die das unautorisierte Fälschen von Bounce-Payloads über die Endpunkte von SendGrid, Mailjet, Mandrill, Postmark, SparkPost und Mailpace unterband. Es geht also nicht darum, dies zu lockern; das Problem ist, dass die Behebung Mandrill ohne Möglichkeit zum Starten (Bootstrap) zurückgelassen hat.

Mandrill validiert einen neuen Webhook mit einem POST (nicht dem HEAD, für den mandrill_head geschrieben wurde), sieht die 406 und verweigert das Speichern des Webhooks – daher ist der benötigte Schlüssel nie einsehbar. Der API-Pfad schlägt identisch fehl:

{"status":"error","code":-98,"name":"ValidationError","message":"Unable to validate webhook URL"}

Ursprungsprotokoll für einen Versuch über die UI:

"POST /webhooks/mandrill HTTP/2.0" "Mandrill-Webhook/1.0" 406

Die anderen Anbieter haben kontostufenbasierte Tokens, sodass ein Administrator ein beliebiges Geheimnis vor der Erstellung des Webhooks setzen kann. Mandrills Schlüssel wird pro Webhook ausgestellt, erst nachdem der Webhook gespeichert wurde – es ist also ein Dilemma (Catch-22).

Ich bin mir ziemlich sicher, dass der Ablauf behoben werden könnte, vielleicht indem man auf die erste Validierung (die kein mandrill_events-Payload enthält) mit 200 antwortet, die Erstellung auf Mandrill erlaubt, dann kann das Geheimnis manuell in Discourse kopiert werden, und wir sind durch. Ich bin gerne bereit, einen PR zu eröffnen, wenn das akzeptabel wäre.

3. Workaround, falls es jemanden heute braucht. Erstelle den Webhook gegen eine URL, die bereits 200 zurückgibt, mit keinen Triggern (Bounce-Payloads enthalten Empfängeradressen, daher niemals einen getriggerten Webhook auf einen Platzhalter zeigen), installiere dann den Schlüssel und verschiebe ihn:

# 1. gegen einen Platzhalter erstellen, keine Ereignisse
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. den zurückgegebenen auth_key in die Site-Einstellung mandrill_authentication_key eintragen

# 3. auf das Forum umleiten und Trigger aktivieren – dies besteht nun die Validierung
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"]}'

Getestet mit 2026.9.0-latest.