Mandrillのバウンス処理: コアで対応済みだが(AFAICT)、文書化されていない

Coreには機能しているMandrillバウンスエンドポイントがあり、WebhooksControllerPOST /webhooks/mandrillです。これはhard_bounceおよびsoft_bounceイベントを処理し、hard_bounce_score / soft_bounce_scoreを適用し、bounce_score_thresholdを超えたアドレスを無効にします。マッチングは、Email::SenderDISCOURSE_SMTP_ADDRESSsmtp.mandrillapp.comと完全に一致する場合に追加する、X-MC-Metadataヘッダーのmessage_idに依存しています。

私はこれを設定しようとしていましたが、他の人にも役立つかもしれないと思ったいくつかの問題に遭遇しました。Mandrillは10年以上前に「SMTPのみ」の提供を停止し、現在ではMailchimpのトランザクションメール製品へのアドオンとしてのみSMTPサービスを提供しているため、ニッチなユースケースであることは承知しています。それでも、私の顧客の一人がまさにこの設定を使用しており、そのためここに共有します。

1. 私が調べた限り、どこにもドキュメント化されていません。 VERPトピックには言及されていませんが、これは合理的です。Mandrillの動作はVERPとは異なるためです。Mailchimp自身のドキュメントでは、カスタムのReturn-Pathドメインを設定した場合でも、バウンスはMailchimp側で処理されるとされており、メッセージごとのバウンスはセルフホストされたメール受信者に到達しません。プロバイダーのWebhookが唯一の経路であり、VERPトピックから始めた人にとって、それへの明白な案内はありません。

2. Webhookは実際には作成できません。 mandrill_authentication_keyが空の場合、WebhooksController#mandrillは常に406を返します。この動作は意図的なものです。これはCVE-2026-26077(Discourse 2025.12.2 / 2026.1.1 / 2026.2.0)の修正であり、SendGrid、Mailjet、Mandrill、Postmark、SparkPost、Mailpaceのエンドポイント全体における、認証されていないバウンスペイロードの偽造を封鎖しました。したがって、これはそれを緩和する要求ではありません。修正によって、Mandrillがブートストラップする手段がなくなっているのです。

Mandrillは新しいWebhookをPOST(mandrill_headのために書かれたHEADではなく)で検証し、406を確認すると、Webhookの保存を拒否します。そのため、必要なキーは決して表示されません。APIパスでも同様に失敗します:

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

UIでの試行のオリジンログ:

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

他のプロバイダーにはアカウントレベルのトークンがあるため、管理者はWebhookを作成する前に任意のシークレットを設定できます。MandrillのキーはWebhookごとに発行され、Webhookが保存された後にのみ発行されるため、ジレンマ(Catch-22)になっています。

フローは修正できるはずで、おそらく最初の検証(mandrill_eventsペイロードがないもの)に対して200を返すことで、Mandrillでの作成を許可し、その後シークレットを手動でDiscourseにコピーし、完了です。それが受け入れられるなら、PRを開くことに問題ありません。

3. 今日必要な場合のワークアラウンド。 すでに200を返すURLに対して、トリガーなしでWebhookを作成し(バウンスペイロードには受信者のアドレスが含まれるため、トリガーされたWebhookをプレースホルダーに向けないでください)、その後キーをインストールして移動します:

# 1. プレースホルダーに対して、イベントなしで作成
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. 返されたauth_keyをmandrill_authentication_keyサイト設定に設定

# 3. フォーラムに向き直してトリガーを有効にする - これで検証を通過します
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"]}'

2026.9.0-latestでテスト済み。