Gestione dei rimbalzi di Mandrill: supportato nel core ma (AFAICT) non documentato

Il Core dispone di un endpoint di rimbalzo Mandrill funzionante - POST /webhooks/mandrill in WebhooksController - che elabora gli eventi hard_bounce e soft_bounce, applica hard_bounce_score / soft_bounce_score e disabilita gli indirizzi che superano la bounce_score_threshold. L’abbinamento si basa sull’intestazione message_id di X-MC-Metadata che Email::Sender aggiunge quando DISCOURSE_SMTP_ADDRESS è esattamente smtp.mandrillapp.com.

Stavo cercando di configurare questo sistema, ma ho riscontrato alcuni problemi che ho pensato valesse la pena condividere, nel caso possano essere utili ad altri. So che si tratta di un caso d’uso di nicchia, poiché Mandrill ha smesso di offrire ‘solo SMTP’ oltre un decennio fa e ora fornisce il servizio SMTP solo come aggiunta al prodotto di posta transazionale di Mailchimp. Tuttavia, un mio cliente aveva esattamente questa configurazione, ed eccoci qui!

1. Non è documentato in nessun luogo che io riesca a trovare. L’argomento VERP non ne menziona l’esistenza, il che è ragionevole, perché il VERP non è il modo in cui funziona Mandrill: la documentazione stessa di Mailchimp afferma che gestisce i rimbalzi in autonomia anche quando si configura un dominio Return-Path personalizzato, quindi i rimbalzi per singolo messaggio non raggiungono mai un ricevitore di posta auto-ospitato. Gli webhook del provider sono l’unico percorso, e non c’è un riferimento ovvio a loro per chi parte dall’argomento VERP.

2. L’webhook non può effettivamente essere creato. WebhooksController#mandrill restituisce 406 ogni volta che mandrill_authentication_key è vuoto. Questo comportamento è intenzionale: è la correzione per CVE-2026-26077 (Discourse 2025.12.2 / 2026.1.1 / 2026.2.0), che ha chiuso la possibilità di falsificare payload di rimbalzo non autenticati su tutti gli endpoint di SendGrid, Mailjet, Mandrill, Postmark, SparkPost e Mailpace. Quindi non si tratta di una richiesta per allentare le restrizioni; il problema è che la correzione ha lasciato Mandrill senza un modo per avviare la configurazione.

Mandrill valida un nuovo webhook con una richiesta POST (non la HEAD per cui mandrill_head era stato scritto), vede il 406 e rifiuta di salvare l’webhook: di conseguenza, la chiave di cui hai bisogno non è mai visualizzabile. Il percorso API fallisce in modo identico:

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

Log di origine per un tentativo tramite interfaccia utente:

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

Gli altri provider hanno token a livello di account, quindi un amministratore può impostare un segreto arbitrario prima di creare l’webhook. La chiave di Mandrill viene emessa per ogni webhook, solo dopo che l’webhook è stato salvato: è quindi un paradosso (Catch-22).

Sono abbastanza sicuro che il flusso potrebbe essere corretto, forse rispondendo con 200 alla prima verifica (che non ha un payload mandrill_events), consentendo la creazione su Mandrill, poi la chiave segreta può essere copiata manualmente in Discourse, e il gioco è fatto. Sono felice di aprire una PR se ciò fosse accettabile.

3. Soluzione alternativa, se qualcuno ne ha bisogno oggi. Crea l’webhook contro un URL che restituisce già 200, senza trigger (i payload di rimbalzo contengono gli indirizzi dei destinatari, quindi non puntare mai un webhook con trigger verso un segnaposto), poi installa la chiave e spostalo:

# 1. crea contro un segnaposto, nessun evento
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. inserisci la auth_key restituita nell'impostazione di sito mandrill_authentication_key

# 3. ripunta al forum e abilita i trigger - ora la validazione passa
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"]}'

Testato su 2026.9.0-latest.