Self-Hosting Email: Why I Did It (And Why You Probably Shouldn't)
I run my own mail server. Postfix on a VPS, DKIM keys I generated, SPF records I wrote, DMARC policies I set. It delivers transactional emails for my applications and handles the occasional notification pipeline. It works.
It took about three full days to get to "works." It has taken periodic maintenance ever since. And if I were starting over today with what I know now, I would probably use Postmark instead.
That's the honest version. Here's the longer one.
Why I Did It
The motivation was straightforward. I had a service running on a Mac Mini behind a Cloudflare tunnel, and it needed to send email: password resets, form submissions, status notifications. Maybe 50-100 messages a day. The kind of transactional email that every web application needs and nobody thinks about until it stops working.
Third-party email services wanted $15-$25/month for that volume. Not unreasonable. But I already had a VPS with a static IP, I already ran Postfix for local system mail, and I had the specific kind of stubbornness that makes a person think "how hard can it be" about a protocol that's been running since 1982.
The real motivation, if I'm being honest, was that I wanted to understand how email actually works. Not the abstraction that Sendgrid sells you, where you POST to an API and mail appears. The actual mechanics: MX records, relay chains, authentication headers, the whole trust architecture that determines whether your message lands in an inbox or a spam folder. I figured running my own server was the fastest way to learn.
I was right about that part. I learned a tremendous amount. I also learned why the entire industry has moved toward managed email services, and it's not because developers are lazy.
The Four Things That Matter
Email authentication has four components. Get any of them wrong and your mail goes to spam. Get all of them right and your mail still might go to spam, but at least you've done everything the protocol asks of you.
SPF (Sender Policy Framework) is a DNS TXT record that tells receiving servers which IP addresses are authorized to send mail for your domain. It looks like this:
v=spf1 ip4:203.0.113.42 -all
That record says: mail from this domain should only come from 203.0.113.42, and reject everything else. The -all is a hard fail — it tells receivers to treat unauthorized senders as illegitimate. Some guides recommend ~all (soft fail) while you're testing. I used hard fail from day one because I wanted to see exactly what broke.
DKIM (DomainKeys Identified Mail) adds a cryptographic signature to every outgoing message. Your server signs the message with a private key; receiving servers verify it with a public key published in your DNS. Setting it up means generating a key pair, configuring Postfix to use OpenDKIM as a milter, and adding the public key as another DNS TXT record.
opendkim-genkey -s mail -d yourdomain.com
# Produces mail.private and mail.txt
# mail.txt contains the DNS record you need to publish
The configuration is fiddly. OpenDKIM needs its own socket, signing table, key table, and trusted hosts file. Each one is a potential point of failure, and the error messages when something is misconfigured are not helpful. I spent about four hours on DKIM alone, mostly because a permissions issue on the key file produced a silent failure — messages went out unsigned with no log entry explaining why.
DMARC (Domain-based Message Authentication, Reporting, and Conformance) ties SPF and DKIM together and tells receiving servers what to do when authentication fails. It also gives you reporting, which is the actually useful part.
_dmarc.yourdomain.com TXT "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com"
The p=reject policy tells receivers to reject messages that fail both SPF and DKIM. The rua address receives aggregate reports — XML files that show you who's sending mail as your domain, whether it's passing authentication, and which receivers are seeing failures. These reports are dense and ugly, but they're the only way to know if your setup is actually working across different mail providers.
Reverse DNS (PTR record) is the fourth piece, and the one most guides mention as an afterthought. Your server's IP address needs a PTR record that resolves back to your mail domain. Without it, Gmail and Microsoft will reject or spam-folder your messages regardless of how perfect your SPF, DKIM, and DMARC are. Setting a PTR record requires your VPS provider to configure it — you can't do it through your domain registrar. Most providers have a control panel option for it, but some require a support ticket.
The Real Gatekeeper
You can configure all four of those things perfectly and still have your mail land in spam. The reason is IP reputation, and it's the part of self-hosted email that no amount of technical competence can fully solve.
Every IP address has a reputation score with the major email providers. Gmail, Microsoft, Yahoo — they all maintain their own scoring systems. A brand-new IP address starts with no reputation, which is treated roughly the same as bad reputation. You're guilty until proven innocent, and proving innocence takes weeks of consistent, low-volume, legitimate sending.
This is where the math stops working for most solo builders. If you're sending 50-100 transactional emails a day, it can take two to four weeks of clean sending before Gmail stops flagging your messages. During that period, some of your mail will go to spam. Some will be silently dropped. You won't always know which messages made it and which didn't, because email doesn't have delivery receipts in any reliable sense.
Managed services like Postmark and Resend have already done this work. They send millions of messages a day from IP pools with established reputations. When you send through their API, your message rides on that reputation. That's what you're paying for — not the API, not the templates, not the analytics dashboard. The reputation.
I got through the warm-up period, but it wasn't painless. I had a contact form that silently failed for about ten days because Gmail was spam-foldering the notifications. I didn't know until someone mentioned they'd filled out the form and never heard back. That's the kind of failure mode that makes self-hosted email genuinely risky for anything client-facing.
When Self-Hosting Makes Sense
After running my own mail server for over a year, I can describe the narrow window where it's the right call.
- Internal notifications only: Server alerts, cron job reports, deployment notifications — messages where you're both the sender and the recipient. Spam filtering doesn't matter because you control both ends.
- You already have a VPS with a clean IP: If you're on a reputable provider and the IP hasn't been used for spam, you're starting from a better position than a random new allocation.
- Volume is low and consistent: 20-50 messages a day, every day, with no spikes. Reputation systems reward consistency and punish bursts.
- You want to learn: This is a legitimate reason. Running a mail server taught me more about DNS, cryptography, and internet trust systems than any course or book could have. The knowledge is genuinely useful even if you end up using a managed service afterward.
If any of those conditions aren't met — if you're sending client-facing email, if your volume is variable, if deliverability is business-critical — use a managed service. The cost is $15-$25/month for most solo builders. The cost of a missed client email is higher.
When You Should Use a Service
Transactional email services exist because email deliverability is an ongoing operational problem, not a one-time configuration task. The landscape shifts. IP reputations change. Gmail updates its filtering algorithms quarterly. Microsoft's spam filters behave differently from Gmail's, and both behave differently from Apple Mail's server-side filtering.
Keeping up with this is a part-time job. For a solo builder, that time has a direct opportunity cost measured in billable hours or product development time. At $150/hour, a single afternoon spent debugging a deliverability issue costs more than a year of Postmark.
Here's how the options break down for most solo builders:
| Service | Best For | Cost at ~3K msgs/mo | Note |
|---|---|---|---|
| Postmark | Transactional email | ~$15/mo | Strict anti-spam policy keeps IP reputation high |
| Resend | Developer-friendly transactional | Free tier covers it | Modern API, good DX, newer reputation pool |
| Amazon SES | High volume, low cost | ~$3/mo | Cheapest per-message, but more configuration |
| Self-hosted Postfix | Internal/learning | $0 (already have VPS) | Full control, full responsibility |
For client-facing applications, Postmark is what I'd recommend. Their entire business model depends on maintaining deliverability, which means they actively police their platform against spammers. That protectiveness is a feature, not a bug — it means your messages benefit from a sender pool that receivers trust.
Resend is a solid choice if you're already in a modern stack and want an API that doesn't feel like it was designed in 2008. SES is the right call if you're sending tens of thousands of messages and every penny matters, but you'll spend time configuring it that you wouldn't spend with Postmark or Resend.
The Third-Party Host Trap
One more thing worth mentioning, because I've seen it happen. There's a category of small email hosting providers — MXroute, Migadu, and similar — that offer cheap mailboxes for custom domains. They work fine until they don't.
I know of a case where a six-year customer lost every inbox on their account because a single employee used one of the mailboxes for cold outreach. The provider deleted the entire account — all mailboxes, all domains, including ones completely unrelated to the violation. No warning, no appeal process, no data export window. Six years of email, gone overnight.
For anything that matters — especially if you're running a business — your email hosting should be with a provider large enough that account termination involves a process, not a single person's judgment call. Google Workspace at $7/user/month is the boring, reliable answer. For solo builders who want more control, running Mailcow on a VPS gives you full ownership of the data while still handling the IMAP/SMTP stack for you.
Self-hosting your mailboxes is a different beast from self-hosting outbound transactional email. It's the difference between running a post office and running a mailbox. I run my own outbound delivery. My actual mailboxes are on Google Workspace. That split is deliberate.
What I Actually Learned
The technical knowledge was worth the effort. I understand email infrastructure at a level that makes me better at debugging deliverability issues for the services I build, even when those services use managed providers for actual sending. When Postmark tells me a message bounced, I can read the headers and understand why. When a client says their emails aren't arriving, I can check their SPF and DMARC records and diagnose the problem in minutes instead of hours.
But the operational lesson was more important: the right tool for a job isn't always the one you can build yourself. Self-hosted email is the infrastructure project that teaches you the most and rewards you the least. The knowledge compounds. The maintenance doesn't.
A solo builder's most constrained resource is attention. Every hour spent monitoring mail queues and checking blacklists is an hour not spent on the work that generates revenue. The services that handle email delivery for $15/month are buying you back dozens of hours per year. That trade is worth making.
Run your own mail server once. Learn how SMTP actually works. Read the RFCs, generate the DKIM keys, watch your messages traverse the authentication chain. Then set up Postmark and get back to building the thing that matters.