Ghost + Mailgun Configuration Guide: The Two Email Systems You Need to Know About

If you're setting up Ghost with Mailgun for email, you might run into some confusion. That's because Ghost actually uses two completely separate email systems — and they need different credentials configured in different places.

Here's everything I learned getting this working.

The Two Email Systems

Type Purpose Protocol Where to Configure
Transactional Password resets, staff invites, login links SMTP Environment variables or config.production.json
Bulk/Newsletter Sending posts to subscribers, analytics Mailgun API Ghost Admin UI

This distinction tripped me up at first. You can have SMTP working perfectly for password resets, but newsletters won't send because that's a completely different system using the Mailgun API directly.


1. Transactional Email (SMTP)

What it's for

  • Staff invitation emails
  • Password reset emails
  • Login magic links
  • Member signup confirmations

Credentials needed

From Mailgun → Domain → SMTP credentials tab:

  • Username: postmaster@your-domain.com or a custom SMTP user
  • Password: The SMTP password (looks like a long hex string)

Configuration via environment variables

mail__transport=SMTP
mail__options__service=Mailgun
mail__options__host=smtp.mailgun.org          # US region
# mail__options__host=smtp.eu.mailgun.org     # EU region
mail__options__port=587                        # or 465 for SSL, 2525 as fallback
mail__options__secure=false                    # true if using port 465
mail__options__auth__user=<YOUR_SMTP_USERNAME>
mail__options__auth__pass=<YOUR_SMTP_PASSWORD>

Or in config.production.json

{
  "mail": {
    "transport": "SMTP",
    "options": {
      "service": "Mailgun",
      "host": "smtp.mailgun.org",
      "port": 587,
      "secure": false,
      "auth": {
        "user": "<YOUR_SMTP_USERNAME>",
        "pass": "<YOUR_SMTP_PASSWORD>"
      }
    }
  }
}

2. Bulk Email / Newsletters (Mailgun API)

What it's for

  • Sending newsletter posts to all subscribers
  • Email open/click analytics
  • Delivery tracking

Credentials needed

From Mailgun → API Security (Account Settings) or Domain → Sending Keys:

Two types of API keys exist:

Key Type Can Send Can Read Analytics Scope
Primary Account API Key All domains
Domain Sending Key Single domain only

Recommendation: Use the Primary Account API Key for Ghost so analytics work too.

Where to configure: Ghost Admin UI

⚠️ This is NOT in environment variables or config files — it's in Ghost's web interface!

  1. Go to https://yoursite.com/ghost/
  2. Click Settings (gear icon, bottom left)
  3. Click Email newsletter
  4. Scroll to Mailgun section
  5. Enter:
    • Mailgun region: United States (or EU if your domain is in EU)
    • Mailgun domain: your-sending-domain.com ← YOUR SENDING DOMAIN, not the API URL!
    • Mailgun private API key: Your API key from Mailgun

Common mistake ❌

WRONG: Mailgun domain = api.mailgun.net
RIGHT: Mailgun domain = your-sending-domain.com

The domain field is your sending domain, not the Mailgun API endpoint!

Environment variables (optional, but Admin UI takes precedence)

bulk_email__mailgun__apiKey=<YOUR_API_KEY>
bulk_email__mailgun__domain=your-sending-domain.com
bulk_email__mailgun__baseUrl=https://api.mailgun.net/v3      # US region
# bulk_email__mailgun__baseUrl=https://api.eu.mailgun.net/v3  # EU region

3. Region Matters!

Your Mailgun domain is created in either US or EU region. You must use the matching endpoints:

Region SMTP Host API Base URL
US smtp.mailgun.org https://api.mailgun.net/v3
EU smtp.eu.mailgun.org https://api.eu.mailgun.net/v3

How to check your region: Look at the URL when logged into Mailgun:

  • app.mailgun.com = US
  • app.eu.mailgun.com = EU

4. Where to Find Credentials in Mailgun

SMTP Password

  1. Mailgun Dashboard → SendingDomains
  2. Click your domain
  3. SMTP credentials tab
  4. Click Reset Password next to your user (password is only shown once!)

Domain Sending API Key

  1. Mailgun Dashboard → SendingDomains
  2. Click your domain
  3. Sending keys tab
  4. Click Add sending key (key is only shown once!)

Primary Account API Key

  1. Mailgun Dashboard → Settings (top right) → API Keys
  2. Click eye icon next to your key to reveal it

5. Testing

Test SMTP (transactional)

If Ghost can send password reset emails, SMTP is working.

Test API (bulk)

curl -s --user "api:<YOUR_API_KEY>" \
  "https://api.mailgun.net/v3/<YOUR_DOMAIN>/messages" \
  -F from="test@<YOUR_DOMAIN>" \
  -F to="your@email.com" \
  -F subject="Test" \
  -F text="Test message"

Should return: {"id":"<...>","message":"Queued. Thank you."}


6. Troubleshooting

Error Cause Fix
Mailgun Error 401: Forbidden Wrong API key or region mismatch Check key and region match
404 page not found Wrong domain or using Domain Sending Key for non-send operations Use Primary Account API Key
Analytics errors on boot Using Domain Sending Key (can't fetch events) Use Primary Account API Key
Emails send via curl but not Ghost Ghost Admin has wrong settings Check Ghost Admin → Settings → Email newsletter → Mailgun

Summary

┌─────────────────────────────────────────────────────────────┐
│                         MAILGUN                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  SMTP Credentials          API Keys                         │
│  (for transactional)       (for bulk/newsletters)           │
│                                                              │
│  ┌─────────────────┐       ┌─────────────────────────────┐  │
│  │ Username        │       │ Primary Account Key         │  │
│  │ SMTP Password   │       │ (full access)               │  │
│  └────────┬────────┘       │         OR                  │  │
│           │                │ Domain Sending Key          │  │
│           │                │ (send only, no analytics)   │  │
│           │                └──────────────┬──────────────┘  │
│           │                               │                  │
└───────────┼───────────────────────────────┼──────────────────┘
            │                               │
            ▼                               ▼
┌───────────────────────┐     ┌───────────────────────────────┐
│ Environment vars /    │     │ Ghost Admin UI                │
│ config.production.json│     │ Settings → Email newsletter   │
│                       │     │ → Mailgun section             │
│ mail__options__*      │     │                               │
└───────────────────────┘     └───────────────────────────────┘
            │                               │
            ▼                               ▼
    Password resets              Newsletter sending
    Staff invites                Open/click analytics
    Login links                  Delivery tracking

The key insight: two systems, two sets of credentials, two different configuration locations. Once you understand that, the setup becomes much clearer.