SaaS & delivery
If you are searching for transactional email and DNS, or for why email hits spam, you are usually here: password reset, invoice or magic link does not arrive. Someone changes the template colour. Someone changes provider. Someone asks the customer to 'check spam' and calls that a process.
The billing and auth post is about Stripe, organisations and who may do what in the product. This one is about the mail the product sends afterwards — and whether it lands at all. Transactional email is not marketing. It is part of login, payment and the agreement the customer thinks you kept when they press 'send link'.
TL;DR
The main points
- Reset, invoice, receipt and magic link are product. They must not share reputation with a newsletter.
- SPF, DKIM and DMARC are identity. Without them the inbox guesses — and often guesses spam.
- The From domain you show must be a domain you can sign as. A shared ESP domain is not yours.
- The template is the last thing you change. Headers and DNS are the first thing you read.
- You must be able to say who sends, who sees bounces, and what Stripe already sends for you.
- An afternoon with a fresh address beats a new tool you buy to get the old mail back.
Why this matters at all
A transactional mail that does not land is not a design problem. It is a broken product. The customer cannot get in. They cannot see the receipt. They think you never answered the booking. Support gets the same case you already 'sent'. You do not have a mail problem. You have a trust problem you measure as tickets.
Teams react the wrong way. They rewrite the subject. They add a logo. They switch from one 'smart' provider to another with the same missing DNS. They turn a marketing tool on for the same From because 'then we have everything in one place'. Inboxes do not look up your Figma. They look up whether you may send as the name you claim.
It is also an auth and billing question. Magic link and reset are the door in. Invoice and receipt are the door to 'you owe' and 'you paid'. If Stripe sends one and you send the other from a domain you cannot sign, the customer has two senders and one doubt. The billing model can be right, and the mail can still be the lie in the chain.
We write this because 'email hits spam' has become a tool purchase on top of the same zone. An honest setup is boring: you know which domain sits in From, which keys sign, what happens on bounce, and which mails you should not send because Stripe or the auth provider already does. Without that sentence you have a template. You do not have delivery you can defend.
What transactional email actually is — and what it is not
Transactional email is mail the product owes the user because they did something, or because you owe them a state: reset, confirmation, receipt, 'your link', 'the payment failed', 'the invite is waiting'. It is expected. It is time-critical. It must not be a newsletter you put another badge on.
Marketing mail is mail you would like them to open. Different purpose, different consent, different reputation. When you mix them on the same From and the same IP pool, the reset inherits the reputation your campaign built. That is the common reason 'it worked in staging' and dies in production after the first blast.
DNS is not decoration. SPF says who may send as the domain. DKIM says the body was not tampered with on the way. DMARC says what the receiver should do when those two do not match — and whether From may look like you when the signature sits somewhere else. Alignment is the word most teams skip: the visible From and the signing identity must belong together. Otherwise pretty records do not help.
Ownership is the part the template debate hides. Who can change From? Who has DNS? Who sees that a reset bounced? Who is allowed to send 'a quick newsletter' from the same domain? If the answer is 'marketing has the tool, engineering has the code, nobody has bounces', you do not have a mail setup. You have three assumptions.
DNS first — the template last
Start in the zone's records, not in the HTML. Find the From the user sees. Find which service actually sends. Check that SPF points at that service — and not at five historical ones you forgot. Check that the DKIM key matches what the provider shows now, not what you set two years ago. Check DMARC: p=none is a mirror, not a policy. Fine while you look. It is not 'we have DMARC' if you never move on, and never read the reports.
Then headers in a real inbox. Not your own, which already knows you. A fresh address at a large provider. Read Authentication-Results. Read whether SPF and DKIM match, and whether DMARC passed. Read which domain signed. If you cannot explain a fail, the template change is guesswork.
Only then copy and layout. Yes, 'RE: invoice' and large images without text can hurt. Yes, a URL that does not match the sender looks like phishing. But a pretty letter on a domain you may not send as is still a letter the filter is allowed to doubt. Conversely, a dull, short reset on an aligned domain can land even if it is ugly.
List-unsubscribe, open pixels and tracking domains belong to marketing. On a reset they are noise, and often a signal you do not want to send. Keep transactional mail short: why it came, what the user should do, a path that does not require them to log in to read the warning itself. Save the campaign for the pipe you have consent for.
What teams typically try — and what actually moves delivery
What typically gets tried first
Same identity, new shell, same doubt in the inbox.
- New template, new logo, new subject line
- A provider change without touching DNS
- The same From for newsletter and password reset
- 'Check spam' as the standing support sentence
What typically moves something
An identity you own, and a pipe you can explain.
- From on a domain you own, aligned with DKIM
- SPF that only names who actually sends
- Reset and campaign on separate reputation
- Bounces and complaints somewhere engineering actually sees
An afternoon check before you change provider
Without this order you change the badge and keep the fail.
- 01
Write every mail the product owes
Reset, magic link, invite, receipt, failed payment, 'your case changed'. One row per type: who sends, which From, which tool, whether Stripe or the auth provider already does it. Double-send is also a delivery problem.
- 02
Read DNS as if you did not trust the panel
SPF, DKIM, DMARC, and whether MX and what you think is 'our mail' even belong to the same story. A pretty dashboard tick is not a record. Look it up from outside.
- 03
Send to a fresh inbox and read headers
Not 'it arrived for us'. A new address, preferably two providers. Authentication-Results first. The spam folder is a symptom. A fail in the headers is the diagnosis.
- 04
Split campaign and product — in From or in a subdomain
mail.yourdomain.com for product and hello.yourdomain.com for the newsletter is an honest start if both are aligned. The same From for both is how reset inherits a campaign you sent yesterday.
- 05
Give bounces an owner in engineering
A reset that never lands must be visible as a failed action, not as a marketing unsubscribe. If only an ESP dashboard has the number, you discover it when support does.
“Delivery is not a theme. It is that you can sign as the name the customer sees — and turn off the pipe you do not own.”
Stripe, auth and Next.js — the same duty, different places you fool yourselves
Stripe can send receipt, invoice and 'update your card'. That is often the right call. Then you should not also send a homemade 'thanks for your purchase' from a domain you have not put DNS on. Two mails about the same payment are not better service. They are two chances for one to hit spam and the other to confuse. Decide who owns each type. Write it down. Turn off the one you do not want to own.
Auth providers send reset and invite unless you have asked to do it yourselves. 'Taking over' those mails without taking over DNS and bounce handling is how you get a prettier letter that does not land. If you send the magic link from Next.js yourselves, the route and the secret are yours — and so are From and DKIM. A fetch to an ESP in a Route Handler is not a setup. It is a call, until the zone's records match.
On Next.js the usual lie is that you have control because you own the repo. A server action sends via an SDK, env points at a test domain, and production inherits a From someone set in a dashboard. Or you render an HTML string in React and forget the text part exists. Inboxes and accessibility want a text body. Controlled HTML is fine. HTML alone is a signal spam filters know.
WordPress shops and 'a plugin that sends' fail in the same place with another face: WooCommerce or an SMTP plugin with a shared key, no DKIM, and a sender that looks like webmaster@hosting. The check is the same. Inventory first. DNS next. Template last. A new plugin on top of a zone you do not own is a fourth pipe.
What you should typically do in the situation you are in
The left is what you typically say. The right is the next step we typically recommend.
Situation
Reset hits spam, and someone wants to change the template or the provider
Next step
Read headers and DNS first. Do not change pipes until you know whether identity fails
Situation
Stripe sends the receipt, and you also send a 'welcome'
Next step
One mail per event. Turn off the one you cannot sign — or the one you will not support
Situation
Newsletter and password reset share From
Next step
Split reputation. Product must not inherit a campaign you sent yesterday
Situation
Marketing owns the tool, engineering owns the code, nobody sees bounces
Next step
One inventory list. One bounce owner in engineering. Transaction is product, not a newsletter
Situation
You are considering a new ESP without having sent to a fresh inbox
Next step
Send first. Read Authentication-Results. Do not buy a fifth pipe for a fail you have not read
Checklist before you say 'we send transactional email'
If you are missing several of these, the sentence is a slide — not delivery.
- Every product event has one sender you can name without opening three dashboards
- From sits on a domain you own, and DKIM/SPF/DMARC match when you look up from outside
- Reset and campaign do not share reputation — in practice, not only on a slide
- A fresh inbox shows pass in the headers, not only 'it arrived for us'
- Bounces have an owner in engineering, not only a number in a marketing UI
- You know which mails Stripe or the auth provider already send — and you have turned off duplicates
Questions we get again and again
Why does our password reset hit spam when the template looks fine?
Because the filter does not buy your layout. It buys whether you may send as the name you show, and whether other mail from the same identity has behaved like spam. Read SPF, DKIM, DMARC and alignment on a fresh address. If they fail, the colour of the button does not matter. If they pass, then look at whether you mixed campaign and reset, or sent from a shared ESP domain you do not own.
Are SPF, DKIM and DMARC enough?
They are the minimum for having an identity the inbox can judge. They are not a free pass. Volume, complaints, links that do not match, and a From you only just started using still count. DMARC at p=none without reports you read is a mirror you turned off. Set the records correctly. Read them from outside. Move the policy when you dare — not as theatre on day one, and not as something you never touch.
May we send transactional mail from the same tool as the newsletter?
You may. You should only if you can split reputation and consent — another From or subdomain, another pool, another unsubscribe. A shared 'campaigns plus password reset' is how a sloppy blast takes the door in with it. Two pipes cost more in setup and less in support. One pipe costs the opposite.
Should we send receipts ourselves when we use Stripe?
Only if you have a reason the Stripe mail does not cover — and only if you then turn the other off. Two receipts are not clearer. They are two senders and an extra DNS job. Many products take Stripe's receipt and use their own pipe for reset and invite. That is an honest split. 'We also send a nice thanks' is what typically hits spam.
When is a new ESP the right next step?
When identity already matches, and you still have a pipe problem: you cannot see bounces, you cannot split transaction from campaign, or the vendor you have cannot sign your domain honestly. It is not the right next step when you have not read headers. Change tool after the diagnosis. Do not change because a slide promised 'inbox placement' without you knowing what fails now.
If the most important mail is the one the customer never gets
Let us separate identity, product and campaign.
An afternoon with DNS and a fresh inbox beats a new ESP you buy to make reset land.
