Skip to main content
← All articles
engineering

Stop sending email from your VPS — I checked my own DNS and even I got it wrong

While writing this post I did the thing I was about to tell you to do — I dug up my own DNS zone — and found a small embarrassment sitting in production. My SPF record for this domain is literally v=spf1 -all. That says, in no uncertain terms, "nobody is allowed to send mail as me." And yet my newsletter goes out fine. The reason it works anyway is the whole story of self-hosted email in 2026, so let me start with my own mistake.

Why the big providers got strict

Back in February 2024, Google and Yahoo jointly drew a line: if you send in any volume, you need SPF, DKIM, and DMARC, a DMARC-aligned From:, TLS on the connection, valid reverse DNS, one-click unsubscribe on bulk mail, and a spam-complaint rate under 0.3%. Microsoft followed for Outlook.com in May 2025. For a while, failing those just meant the spam folder.

That grace period is over. Through late 2025 Gmail escalated from soft deferrals to outright SMTP rejection — the 550 5.7.26 "this mail is unauthenticated" bounce. Outlook rejects with 550 5.7.515. There's no exact "it happened on this Tuesday" announcement, more of a ramp, but the direction is unambiguous: non-compliant mail now bounces, it doesn't hide in Junk. You don't get a second chance to make a first impression on a mail filter.

Why sending straight from your VPS is a losing game

Standing up Postfix on your own box feels like the sovereign, self-hosted thing to do. In practice it's a treadmill you lose:

  • Port 25 is usually blocked. Most providers (AWS most famously, with no removals since 2020) block outbound 25 by default because it's the spam vector. You have to ask, and justify it.
  • Your IP has no reputation. A fresh VPS IP looks exactly like the disposable infrastructure spammers spin up and burn. To Gmail you're guilty until proven boring.
  • You may have inherited someone's sins. VPS IP ranges get recycled; the previous tenant's spam can leave you pre-blocklisted.
  • rDNS and reputation are continuous work. Even with everything configured perfectly, a low-volume sender never builds the consistent history needed to earn and hold a good reputation. One slip and you're back in the filter.

The pragmatic architecture: relay, but keep your identity

The setup that actually works for a self-hoster is to host everything except outbound mail, and hand the sending to an authenticated relay — Brevo, Postmark, SES, Mailgun, take your pick. Crucially, you still own and publish your own SPF, DKIM, and DMARC. The relay signs DKIM with your domain via records they hand you, so DMARC aligns to your From: and you keep your portability. You're renting their warmed-up IP reputation, not surrendering your domain. That's what I do here — the blog runs on my VPS, the newsletter goes out through Brevo. Free tiers are generous enough for a personal site (Brevo's is 300/day).

Back to my footgun

Here's what SPF, DKIM and DMARC each do, quickly, because the failure I made only makes sense once they're clear:

  • SPF is a DNS record listing who's allowed to send for your domain. Receivers check it against the envelope sender.
  • DKIM is a cryptographic signature the sending server adds, verified against a public key you publish. It proves the message is authorised and unaltered.
  • DMARC tells receivers what to do when SPF or DKIM fail to align with the visible From: domain — and it passes if either one aligns and passes.

Now my zone. SPF is v=spf1 -all — a hard "authorise nobody," with no include:spf.brevo.com. DMARC is p=none pointed at Brevo's reporting address. DKIM is correctly set up with Brevo's selectors. So every newsletter I send fails SPF — but it passes DKIM, DKIM is aligned, and DMARC only needs one of the two to pass. My mail squeaks through on DKIM alone. It works, but it's working with one engine out.

An SPF record of -all without authorising your relay isn't strict security. It's telling the world your legitimate mail is forged, and hoping DKIM covers for you.

The fix is one of two things, and I'd argue for both. Add the relay to SPF (v=spf1 include:spf.brevo.com ~all) so SPF actually passes. And note the ~all, not -all: the modern consensus is that you get your strictness from DKIM plus a DMARC p=reject, not from an SPF hardfail that's one misconfiguration away from bouncing your own mail. The upgrade path isn't ~all → -all; it's ~all + aligned DKIM + walking DMARC from p=none to quarantine to reject while you read the aggregate reports.

The takeaway

Self-hosting your website in 2026 is great and I recommend it. Self-hosting your outbound mail server is a hobby that mostly produces bounces. Relay it, own your SPF/DKIM/DMARC, and then — unlike me until this week — actually re-read your own SPF record. The footgun isn't exotic. It was sitting in my zone the whole time, quietly telling Google my newsletter was a forgery.

Links

BM
Blue Moose
The moose behind Blue Moose. Full-stack PHP developer — Drupal by day, Symfony by night, tests always.