Ghost + Mailgun Webhooks (or: Why the Endpoint Simply Doesn’t Exist)

“Let’s quickly enable webhooks for bounces and complaints and call it a day.”

Ghost + Mailgun Webhooks (or: Why the Endpoint Simply Doesn’t Exist)
Photo by Nadiia Ganzhyi / Unsplash

I just wanted a clean, fully working Mailgun integration in Ghost.
Newsletters were already sending fine — so I figured: “Let’s quickly enable webhooks for bounces and complaints and call it a day.”

Spoiler: it was anything but quick.


Initial Setup

Environment:

  • Ghost (self-hosted, Docker)
  • Mailgun (EU region)
  • Newsletters sending successfully ✅
  • Members enabled ✅

Environment variables looked correct:

bulkEmail__mailgun__domain=blog.michael-bohn.net
bulkEmail__mailgun__apiKey=***
bulkEmail__mailgun__webhookSigningKey=***
bulkEmail__mailgun__baseUrl=https://api.eu.mailgun.net/v3

Everything seemed in place.
And actually, it was.

There's no webhook for Mailgun anymore. Somehow, the "create webhook" option in the Mailgun configuration misled me.
What used to be done via the webhook is now handled by Ghost's active polling. That's the analytics part of Ghost.

The data is retrieved from Mailgun by Ghost like this, for example:

curl -u "api:YOUR_API_KEY"
"https://api.eu.mailgun.net/v3/your.blog.com/events?event=failed&event=complained&event=delivered&event=opened&event=clicked&limit=10"

Some old web posts and AI-hallucination led me astray. And so I ran into hours of debugging and reading forum posts until I finally got it.


Subscribe to Michels Blog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe