Mailgun proxy for ghost

Took my 2 weeks, but as you know Mailgun is the built-in feature to send Newsletters. There is another proxy (by Typetale) for Ghost which uses SES, but I used Resend. I didn’t liked the vendor lock-in too for using Mailgun. So what I did was to make another proxy but on top of Laravel features (I am primarily a Laravel dev), which already have:

  • SMTP

  • Sendmail

  • Postmark

  • Amazon SES

  • Resend

  • Mailbox* (faking a mailbox without sending it for real, great for local testing)

  • And more if you install other packages by the community

Right now for analytics (opened, clicked) I only support Resend, because I needed it but I am open for contributions for making it more extensible for other providers. You can also have failovers, for example Postmark is down, you switch to SES etc. and have retry mechanism. I will add a Dockerfile and publish images soon so it is easy to deploy.

Let me know what you think: https://github.com/eznix86/mailgun-proxy-for-ghost

2 Likes

I know AI is a good tool to use, but from looking at your code, 95% of it looks to be completely AI generated. Which model are you using?

Well, no, i write it by hand, but only some of the tests and UI has been written with AI.

I am interested in using my self-hosted SMTP for sending newspapers.
After reading your post, the forum is suggesting me this related topic:

On that discussion thread people point out some problems, when trying to send a newspaper to 1000 addresses (for example). That is, it tries to send 1000 emails at the time that it is contacted by ghost, and the connection from ghost times out. So, it does not queue the ghost requests, and does not dispatch the email later, working on background, but tries to send them immediately. How does your proxy behave on this case?

Hey, thanks for considering this project. First of all I am not a salesman. So don’t expect I would be able to convince you, but i could answer you as a developer:

When the proxy gets a newsletter request from Ghost, It immediately stores this request into the database.

Then a queue picks it up and decodes it, and prepare it for sending; reformat the email so each recipients get their email with the variables are set. Once done, it would loop over the recipient and send the email to a queue.

Then later in the queue, it would be picked up and sent one by one. If you are a laravel developer you would see ShouldQueue there: mailgun-proxy-for-ghost/app/Mail/GhostNewsletter.php at main · eznix86/mailgun-proxy-for-ghost · GitHub

In your example where you said:

when trying to send a newspaper to 1000 addresses (for example). That is, it tries to send 1000 emails at the time that it is contacted by ghost, and the connection from ghost times out.

It won’t be a problem on the proxy i’ve made because it writes to the database without an action, and its the queue which picks it up and replies to Ghost, making it under 1s (depending on the latency between the proxy and the ghost instance).

If you need any help let me know. I saw you’ve opened an issue. Support for postalserver · Issue #15 · eznix86/mailgun-proxy-for-ghost · GitHub I will try to look it up and let you know there.

1 Like

Thanks for you quick answer.
If it works as you describe it (for delivering newsletters via an SMTP server), it would be fine for me. Missing analytics is not a problem for me (at least for the time being).
Of course, supporting Postal (with analytics) would be better, but installing Postal itself requires some resources, and it may not be a good choice for everyone.

I have installed Ghost with docker-compose. For the time being, I am waiting for you to implement a Dockerfile for the mailgun-proxy, so that I can give it a try. I may also help (if you need my help), since I have some experience with Docker (but not with Laravel).

I haven’t looked into PostalServer yet, but SMTP support is already there.

I’ve also been working in parallel on something called Mailpunch (https://mailpunch.app/), a managed Mailgun proxy with failover and load balancing for multiple providers, including SMTP. Instead of self-hosting everything yourself, it’s a managed service built on top of the open-source project I originally built for myself.

Feel free to sign up if you’re interested. It would help me make it a reality, add support for more providers, and further refine the open-source version.

Meanwhile, I’ll get back to work and publish a Dockerfile along with a container image on the GitHub Container Registry.

I had a look at PostalServer and I found it difficult to install in my docker environment. I gave up (at least for the time being).

But I have already a simple SMTP (postfix) server, in a container, that I am using to send notifications from other containers (on the localhost). If I can use this one for sending Ghost newsletters, it would be great.

I am not interested on Mailpunch, sorry. For me it would just add more unneccessary complexity. I already hate having to setup a Mailgun account, why should I want to setup multiple accounts on multiple service providers?

If nothing else works for sending newsletters, as a last resort I am going to use just a plain mailing list to distribute them, and the latest articles, to the subscribed members.

Makes sense. If you’ve already got Postfix running locally, you probably don’t need Mailpunch right now.

For your setup, I think the open-source proxy should do the job just fine. I’ve added Docker support, so you can spin it up easily with:

docker pull ghcr.io/eznix86/mailgun-proxy-for-ghost:0.1.0

The main idea is that when Ghost sends a newsletter request, the proxy quickly acknowledges it, stores the job, and then handles the actual sending in the background. That should prevent those annoying timeouts and potential duplicate sends.

Mailpunch is more geared toward people who want a simple hosted solution, so you just drop in an API key and go. It is also useful if you want flexibility and failover, since you can route emails through SES, Resend, Postmark, Postal, SMTP, or whatever else works best for you at the time. That makes it easier to optimize for price, deliverability, or reliability without being stuck.

One quick note though: sending everything directly through your own SMTP/Postfix setup can get tricky as volume grows. Deliverability depends a lot on DNS setup, IP reputation, bounce handling, spam complaints, and monitoring. That is one reason people often prefer going through an email provider, since they handle a lot of that infrastructure for you.

If you give a try with your Postfix setup, Any feedback would be super helpful.

As far as I know, docker pull does not spin up a container. Your instructions on the README file suggest using docker compose, but your docker-compose.yml has a postgres service, while .env.example suggests either sqlite or mariadb/mysql. The Dockerfile is soo complex, and it does not correspond to the installation instructions on README. I have never seen such a complex Dockerfile.

I don’t want to hurt you, but I think that either you don’t know what you are doing, or your AI agent doesn’t know what he is doing. I give up trying to use this proxy (at least for the time being).

By the way, I realized that using a mailing list (actually I am using a Google Group) is much better than I thought initially. I can add subscribers manually to the mailing list, and that is fine for me. I can also limit the number of addresses where Ghost tries to send newsletters, so that it is not send more than 100 emails per day (the mailgun limit). I can send the newsletters to the mailing list manually. I don’t get detailed analytics (provided by mailgun), but that is fine for me. On the other hand, subscribers can get the newsletters in digest, if they want, instead of one by one. It seems to me that mailgun is just a mailing list with more analytics.

Glad you found a workaround that works for you.

Quick note for anyone else who comes across this: docker pull was just meant to show the image is ready to use, actual deployment is via docker compose. The Dockerfile complexity is standard for a Laravel app that bundles a frontend build and a queue worker together. The .env.example covers multiple database options because Laravel supports swapping databases easily, just pick the one that fits your setup.

See more on how to configure your database of choice: Database: Getting Started | Laravel 12.x - The clean stack for Artisans and agents

Hey @eznix86 thanks for the mention.

Here is the github repo incase anyone what to checkout: typetale-app/mailgun-ses-proxy
We have made significant progess towards improving the proxy:

  • We now use queues with rate-limiting to respect the SES sending rate-limit.
  • [NEW] Dashboard for monitoring the newsletter batches and mail status.
  • Improved DX and background processing logic.

Welcome @tilak999 :) You are the reason i’ve built my own but for another provider. Maybe we could work on something together :) hit me up at hello@mailpunch.app

I’m trying to avoid Mailgun for sovereignty reasons. I’m evaluating AhaSend and Sweego. I noticed you’re moving toward a provider abstraction rather than a Resend-specific proxy. How difficult would adding a new provider transport be? Is that an intended extension point, or are providers still tightly coupled to the implementation?

Hey thanks @thatwoman Actually I try my best to not be coupled to the provider, the idea is to be as transparent as possible and forward it to the provider.

That’s why I have an OSS version of the project so you can open issues and we look it up together.

Oh, that’s great. Would I send it directly to AhaSend to see if they’re willing to play?