Show HN: Posthorn, self-hosted mail gateway (github.com)

83 points by craigmccaskill ↗ HN
Introducing Posthorn, a self hosted email gateway. One docker container (or Go binary) between every self hosted app on your VPS and your transactional email provider. Set up Posthorn once, point your apps to it, done.

I was trying to deploy Ghost on a DigitalOcean droplet and found that DO and many different VPS services have started to block the default SMTP ports to try to combat the various types of abuse they get. To actually configure my app, I had to hack together a Postfix relay.

In another project, I had a static site which had a contact form, but my free Formspree account was occasionally hitting usage limits and I desperately wanted some of the anti-spam features they had gated behind their paid accounts so I put together a caddy module to catch HTTP POSTs and bounce them to my provider.

I kept bumping into these same email issues. Many of the services I wanted to host (Gitea, Mastodon, Umami, Comentario) ran into the same limitations. This felt like a really common issue that had no good solution.

Posthorn is what I built to solve this. It's a small Go binary (or 10 MB docker image) that sits between your self hosted apps and your transactional email provider of choice (shipping with support for Postmark, Resend, Mailgun, Amazon SES or an outbound SMTP relay). It also accepts POSTs from HTML forms to support static site needs while adding security layers such as honeypot fields, origin checks and IP rate limiting. There's also a JSON HTTP API that supports Bearer auth for backend scripts or cron jobs that just want a /send endpoint.

I now use this personally in multiple scenarios and I've spent a lot of time beating this up and testing against what I can validate. I'd love to hear how this might be useful for you, what breaks and any feedback you might have. It's open source under Apache 2.0 and I'd love contributions. I'm planning to support and grow this for the long haul.

Code: https://github.com/craigmccaskill/posthorn

Docs: https://posthorn.dev/

Longer write up: https://craigmccaskill.com/introducing-posthorn/

Previous HN discussion on the exact issue I'm trying to solve: https://news.ycombinator.com/item?id=43620318

30 comments

[ 2.5 ms ] story [ 70.9 ms ] thread
Don't services like SES already operate over 443/TLS and aren't blocked?
Correct, but not all apps can talk directly to an HTTPS API. Ghost, Gitea, Mastodon, NextCloud, Authentik, Matrix to name a few all only have built in SMTP support. Posthorn listens for that connection from those apps locally and translates it into whatever your transactional mail provider needs.

If all the apps you're running can already integrate via HTTPS API, Posthorn doesn't solve anything for you in that case, unless the unified credential, single retry policy and logging meaningfully simplifies things for you.

And honestly, SES was the easiest integration for me to write (even if it ended up being the most LOC), their documentation, examples and error responses gave me a really easy time setting it up. Additionally, because it does need such a verbose implementation SES ends up being a great case study for Posthorn and not needing to maintain the same 200 line signing routine in multiple different places.

> Nobody wants to self host email server.

I do. Though I am self hosting it to have my personal email, being well... personal. Not for my company so maybe I am not the target.

Interesting project though. I always felt missing API to just send emails from some script in my mail server.

Personal mail is the one case I think where hosting your own MTA still makes sense when you want to own the addresses and the data. You still have to solve for deliverability, which is something I hope to never have to do.

Posthorn is built for the opposite end of that, you've already decided you want to use a transactional provider for app mail and you just want to stop having to deal with wiring it into all of the things. Obviously for a big production app you build your own mail service, but for gluing together a bunch of different apps you're self hosting, I think this makes sense and addresses a real issue.

If you want an API piece to augment what you already have, Posthorn might still be useful regardless of how the rest of your mail is set up. A Posthorn JSON endpoint is just a POST with Bearer auth and an idempotency key. Example from my docs:

curl -X POST https://posthorn.yourdomain.com/api/transactional \ -H "Authorization: Bearer $WORKER_KEY_PRIMARY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: reset:user-123:$(date -u +%FT%H)" \ --data '{ "to_override": "bob@example.com", "subject_line": "Reset your password", "message": "Click here: https://app.example.com/reset/abc" }'

Could run alongside your existing mail server. It's a small enough overhead that the juice might be worth the squeeze.

Any UNIX-derived operating system has some kind of command-line utility for sending email messages (named mailx or mail or Mail).

I do not remember if I have ever used the GNU mail program that is available on Linux, but my e-mail server is hosted on FreeBSD, so I have used very frequently the FreeBSD CLI utility to send e-mail messages from scripts.

Moreover, all FreeBSD servers come configured by default to send automatically a variety of e-mail reports to the administrator, to inform about incidents or statistics, so there are a lot of examples of usage from scripts.

An interesting combination of features.

Personally, I have used nullmailer in the past to provide a sendmail compatible local install that immediately forwards email to the SMTP server of my choice. Has worked flawlessly.

Obviously, that doesn't come with HTML form support, but then I am also not sure I would like the same binary to handle both a HTTP(S) endpoint and email submission :)

I really want to try this, but I'm afraid my DNS will be blacklisted if I do. Can someone guide me and others, if this is the case? E-Mail is the most complex of everything I know in sysadmin/DNS/Server stuff.

My current provider since almost two decades without any issues, except speed and storage limitations is all-inkl.com, but I really just use it for email and nothing else, therefore most likely overpriced at ~6€/month.

I would love to switch to some VPS/root or anything where I can SSH and install, compile my own services, but something where security is high and support is 24/7 available.

Nice project, nice initial subset of options.

At work I'm using Apprise (https://appriseit.com/) to deliver notifications.

Are you planning to add more services or to limit Posthorn to emails?

> Nobody wants to run a mail server in 2026.

We do, and thats why we use Postal [1].

The more SaaS applications that self-host email the better. It forces the big guys, ie Microsoft, to improve their blocklists and not lazily block entire ranges. Yes its work contacting them occasionally, but it keeps the internet open. The alternative is an internet where they control it all.

1. https://docs.postalserver.io/

Confusing title, "self-hosted mail" and "self-hosted email gateway" are two quite different things :-/
My eyes first Spoonerized the title to "Hostporn, selfhosted porn gateway". I didn't get a full night's sleep last night...
I am running a local mail server using cloudflared tunnels and brevo for sending

postfix/sendmail/dovecot/ingress setup

I am really happy with the setup. (So far)

The title is inaccurate. Its a self-hosted transactional email gateway, not self hosted email
"Not a mail server"... supports SMTP in and out
How does this differ from using protonmail-bridge? Seems like a similar concept.
Yeah, those are similar but narrower scope tools. They do one thing, sit behind a firewall, listen on port 25 and forward SMTP submissions to sendgrid/mailgun's endpoint using an API key.

Posthorn adds an HTTP form endpoint (which is safe to expose to the internet), a JSON API with Bearer auth and idempotency, and a provider abstraction so you can use a broad range of providers via config.

If you just need to forward SMTP requests behind a firewall to a single provider, those are far simpler solutions and Posthorn is overkill. The moment you need anything outside of that, I couldn't find a solution that worked and that's the gap I built Posthorn to fill.

Happy to take any feedback on my approach, either here or in GitHub issues.

This solves an issue that I really do have. Will try it out!
Awesome! Let me know how it works for you and feel free to open an issue on GitHub!
Does the SMTP relay handle DMARC aggregate reports, or do you still need something like parsedmarc set up alongside it? That's always the loose end when I put these together.
No, Posthorn is outbound only. DMARC aggregate reports come back as inbound mail to whatever address you put in your rua tag and Posthorn has no inbox or IMAP to receive them.

Parsedmarc is still the right tool if you want to self host reporting, otherwise you should look into solving this with your provider. Explicitly trying to avoid dealing with all the operational costs of running a mail server, just trying to enable email capabilities in apps that need it so it's beyond the scope of what I built here.