Gestione dei rimbalzi di Mandrill: supportata nel core ma (AFAICT) non documentata

Il core dispone di un endpoint Mandrill per i rimbalzi 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 in cui possano essere utili ad altri. So che si tratta di un caso d’uso di nicchia, dato che Mandrill ha smesso di offrire “solo SMTP” oltre un decennio fa e ora fornisce il servizio SMTP solo come add-on al prodotto di posta transazionale di Mailchimp. Tuttavia, un mio cliente aveva esattamente questa configurazione e quindi eccoci qui!

1. Non è documentato in alcun luogo che riesca a trovare. L’argomento VERP non ne fa menzione, il che è ragionevole, perché 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 messaggio non raggiungono mai un ricevitore di posta self-hosted. Gli webhook del provider sono l’unico percorso, e non c’è un riferimento ovvio ad essi 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 i 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 la sicurezza; il problema è che la correzione ha lasciato Mandrill senza modo di avviare la configurazione.

Mandrill valida un nuovo webhook con una richiesta POST (non la HEAD per cui era stato scritto mandrill_head), vede il 406 e rifiuta di salvare l’webhook - quindi 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 dall’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 dilemma (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 il segreto può essere copiato 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 indirizzi dei destinatari, quindi non puntare mai un webhook con trigger verso un segnaposto), poi installa la chiave in Discourse e, una volta fatto, sposta l’URL dell’webhook:

# 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 l'auth_key restituito nell'impostazione di sito mandrill_authentication_key

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