How to troubleshoot email open rate being 0%?


  • How was Ghost installed and configured? Digital Ocean Droplet 1-click install
  • What Node version, database, OS & browser are you using? MacOS, Safari
  • What errors or information do you see in the console? I’m having trouble reading the error logs. I have them but they are gibberish to me.
  • What steps could someone else take to reproduce the issue you’re having? That I’m not sure about.

Hi there, I continue to have a 0% open rate for my emails and newsletters. Something seems to not be registering. They do send fine, I’ve tested that. And I’ve sent some tests and opened them myself but still the rate shows 0% opening. I’m not sure how to troubleshoot this though, anyone have some suggestions or issues like this?

1 Like

@brendantko have you completed your Mailgun setup by adding the tracking CNAME?

hi @Kevin,

I just double checked and the CNAME record is set right and validating alright trough mailgun, so that side of things seems to bet set up okay

Are you seeing open events in Mailgun’s UI? If you aren’t then something is wrong on the Mailgun setup side, if you are then it seems that something is going wrong when Ghost fetches the events from Mailgun.

You can check your Ghost logs for entries such as Fetched 300 events and aggregated stats for 1 emails and 240 members in 2044ms

I am seeing the open events in Mailguns UI. So seems they are getting through and opened ok.
Just some communication back to Ghost isn’t happening?

I see quite a few Fetched 0 events and aggregated stats for 0 emails in 236ms

Not sure if these logs help? Seems like there is some kind of error happening:

{"name":"Log","hostname":"ghost-travel-fodder","pid":1754,"level":50,"err":{"domain":"","statusCode":401,"message":"Invalid private key","stack":"Error: Invalid private key\n    at IncomingMessage.<anonymous> (/var/www/ghost/versions/4.1.2/node_modules/mailgun-js/lib/request.js:327:17)\n    at IncomingMessage.emit (events.js:326:22)\n    at endReadableNT (_stream_readable.js:1241:12)\n    at processTicksAndRejections (internal/process/task_queues.js:84:21)"},"msg":"Invalid private key","time":"2021-03-30T10:32:12.643Z","v":0}
{"name":"Log","hostname":"ghost-travel-fodder","pid":1754,"level":30,"msg":"Capturing error for worker during execution of job: email-analytics-fetch-latest","time":"2021-03-30T10:32:12.656Z","v":0}
{"name":"Log","hostname":"ghost-travel-fodder","pid":1754,"level":50,"err":{"domain":"","message":"Worker for job \"email-analytics-fetch-latest\" exited with code 1","stack":"Error: Worker for job \"email-analytics-fetch-latest\" exited with code 1\n    at Worker.<anonymous> (/var/www/ghost/versions/4.1.2/node_modules/bree/lib/index.js:385:40)\n    at Worker.emit (events.js:314:20)\n    at Worker.EventEmitter.emit (domain.js:483:12)\n    at Worker.[kOnExit] (internal/worker.js:231:10)\n    at Worker.<computed>.onexit (internal/worker.js:165:20)"},"msg":"Worker for job \"email-analytics-fetch-latest\" exited with code 1","time":"2021-03-30T10:32:12.657Z","v":0}

The logs show that the Mailgun API key that you’ve entered is not valid for fetching events.

Did you enter your account’s Private API key or did you create a Sending API key for a domain? A Sending API key will only work for sending email, none of the additional integration for open tracking and list management will work.


Ah, okay thanks @Kevin, I’ll have a look into that.

Thanks @kevin, yeah I had a sending API key inputed. Thanks for the help. I had to simply make sure i was using the Private API key and now I see the read/open stats just fine.

Thanks again :grimacing:


Had the same issue, same solution - thanks!

1 Like

Good to hear! I’m glad my folly is helpful to someone else! :smiley:

1 Like

I have the exact issue — I was using the Send API Key. I’ve now replaced it with my private key which I got from, but the issue persists even after a restart. Where am I going wrong? :sob:

Have you sent emails since changing the API key? How long ago was the last email sent?

The analytics are generated by periodically fetching logs from Mailgun and Mailgun only keep logs for a certain time period (5 days on the smaller plans) so historic open rate data will not/can’t be back-filled entirely.

Thanks for getting back to me, @Kevin :pray:

Yes, I’ve sent out mail since the change. It sends without an issue, but still no updates on the open rate.
Checking the logs still shows the Invalid private key error message.

Similar to above, I have the following working and/or updated:

  1. MailGun shows opens in their logs.
  2. I have replaced Send API Key with Account Private Key in the SMTP auth.pass key.
  3. I can send out both test & bulk emails.
  4. I’ve tested the key using the events call that can be found here and it returns correctly.

Where are you changing the API key? There are two different mail systems:

  1. Transactional email (member signup/signin, staff invites, etc) - config.production.json, if you’re using Mailgun for transactional email then you should use your SMTP credentials rather than API keys
  2. Bulk email and related anlaytics - “Email newsletter settings” under the “Email newsletter” section of the admin panel, uses a Mailgun domain and private API key
  1. I’ve changed the API key inside config.production.json from Sending API Key to the Private API Key — this is where I’m applying the following:
"auth": {
        "user": "",
        "pass": "private-api-key"
  1. Under the Email newsletter settings I am applying with a Sending API Key

Both of those are wrong :grimacing:

  1. Should use your SMTP password, not an API key
  2. Should use the private API key

I realised as I was typing all that out :sweat_smile: I’m surprised anything worked.

I’ve swapped everything around and I’m testing now.

@Kevin :eyes: We are in business!!! :confetti_ball:

Thanks for all the help :sweat_smile: :pray: :bowing_man:

1 Like

Hi, I have to admit Ive always got confused about this when setting up Ghost. Are there any docs around all of this?