The usual story goes like this. Onboarding emails get low opens and almost no replies, so you rewrite the subject lines. Then rewrite them again. Then one user mentions in a support thread, "btw your welcome email was in my spam, and the password reset too."
The copy was never the problem. The mail wasn't arriving.
If you run a small SaaS, this is easy to miss because nothing breaks loudly. Signups still happen. Stripe still charges. Your app logs say "email sent". Nobody tells you the welcome email, the magic link or the reset link went to spam, they just quietly give up and you read it as churn.
This is the setup I'd do on day one now. It's maybe an hour of DNS work and it's the most boring hour you'll spend on the product, but it protects every email that actually matters.
Why this got stricter
Since February 2024 Gmail has had written rules for anyone sending to personal Gmail accounts, and Yahoo rolled out similar ones at the same time. The short version from Google's sender guidelines:
- Every sender needs SPF or DKIM set up for the sending domain, valid DNS for the sending IP, and TLS.
- Keep your spam rate (as shown in Google Postmaster Tools) under 0.3%. Google actually says aim for under 0.1%.
- If you send 5,000+ messages a day to Gmail, you need SPF and DKIM, a DMARC record (p=none is ok), a From domain that aligns with one of them, and one-click unsubscribe on marketing mail.
Most of us are nowhere near 5,000 a day. Doesn't matter. Do the bulk-sender version anyway. It costs nothing extra and you never have to think about it again when you grow.
The one-hour setup
1. Send from your own domain, not a free address. hello@yourapp.com, not yourapp.team@gmail.com. I'd also split it: one subdomain for product mail (mail.yourapp.com or whatever your provider suggests) and keep newsletters/marketing on a different one or a different provider. If your launch-week newsletter annoys people and gets marked spam, it shouldn't drag your password resets down with it.
2. Use a real transactional provider. Postmark, Resend, SES, Mailgun, SendGrid, whichever. Don't send from your app server with raw SMTP on a VPS IP. Shared IPs from a decent provider have a reputation you can't build alone at 40 emails a day.
3. SPF. One TXT record on the sending domain that lists who's allowed to send. The trap people hit all the time: you can only have one SPF record per domain. If you add a second one for your new provider instead of merging it into the first, both break. Also SPF has a 10 DNS lookup limit, so don't pile every tool you've ever tried into it.
4. DKIM. Your provider gives you a key (usually CNAME or TXT records). Paste them in, wait, hit "verify" in the provider dashboard. This is the one that most often stays half-done because the dashboard shows a yellow "pending" and you go back to coding.
5. DMARC. Start with something like this on _dmarc.yourapp.com:
v=DMARC1; p=none; rua=mailto:dmarc@yourapp.com
p=none means "don't block anything yet, just send me reports". Leave it a few weeks, read the reports (they're ugly XML, a free parser helps), check that only your real senders show up, then move to p=quarantine. I wouldn't jump to p=reject until you're sure every tool that sends as your domain (support desk, billing, CRM) is passing.
6. Alignment. This one confused me the most. DMARC passes only if the domain in your visible From address matches the domain that passed SPF or DKIM. If your From says yourapp.com but DKIM is signed by provider-mail.net, you pass DKIM and still fail DMARC. Most providers fix this once you verify your own domain, but check a real email's headers, don't trust the green tick.
How I actually test it
Send yourself a reset email to a personal Gmail address. Open it, three-dot menu, "Show original". You want to see SPF: PASS, DKIM: PASS and DMARC: PASS at the top. That takes two minutes and tells you more than any dashboard.
Then do the same with an Outlook address and an iCloud one if you can. A lot of B2B users sit on Microsoft 365, and Microsoft has its own stricter rules for high-volume senders now too.
Last thing, sign up for Google Postmaster Tools for your domain. At low volume it often shows nothing (it needs a minimum amount of traffic), and that's fine. When it starts showing data, you'll be glad you set it up early.
Stuff that quietly hurts deliverability
- Sending the welcome email and a "how's it going?" email 20 minutes apart. New users mark things as spam when they feel spammed. Fewer, triggered emails beat a long drip. I wrote about why calendar drips don't work for small products, and it applies here too: every email nobody wanted is a spam-report risk for the ones they did.
- Noreply addresses. Use a reply-to that goes to a real inbox. Replies are a good signal and you learn stuff from them.
- Link shorteners and tracking domains you don't own. A shared tracking domain that some spammer also used is not your friend. Many providers let you set a custom tracking domain, or just turn click tracking off on transactional mail.
- Marketing content inside transactional emails. A password reset with three promo banners is not a transactional email anymore, at least not to a spam filter.
- No unsubscribe on anything that isn't strictly transactional. If it's a newsletter, product update or "we launched X" email, give one-click unsubscribe and honour it fast (Google says within 48 hours for bulk senders).
If you want a starting point for what the onboarding sequence itself should look like once the mail actually lands, here's the onboarding email setup I'd copy. Short, triggered by what the user did, and skips itself once they're activated.
The emails I'd check first
If you only have time to test a few today, check these, in this order:
- Password reset / magic link (if this fails, the user is locked out, full stop)
- Email verification on signup
- Payment receipts and failed-payment emails (money is on the line here)
- Welcome / first onboarding email
Everything else can wait a week.
What I'd do this week
- Monday: add SPF, DKIM and DMARC (
p=none) for the sending domain. Merge SPF, don't duplicate it. - Same day: send a reset email to Gmail and Outlook, check "Show original" for three passes.
- Next week: read the first DMARC reports. Anything sending as your domain that you don't recognise? Find out what it is.
- In a month: if reports look clean, move DMARC to
p=quarantine.
None of this is clever. But I'd rather lose an hour to DNS than lose users who never got the link to log in. If you've had a weird deliverability issue that none of this covers, I'd like to hear it in the comments, especially the Outlook ones, those still confuse me.
Top comments (0)