Learn

The complete guide to transactional email for SaaS applications

Updated September 25, 2026

In short

Transactional email in a SaaS app is the set of messages your product sends because a user did something - sign-up verification, sign-in codes, password resets, invites, receipts, alerts. Get it right by sending from an authenticated subdomain of your own domain, keeping it separate from marketing mail, sending from background jobs with idempotency keys, handling bounce and complaint webhooks, and watching delivery in logs and metrics.

The emails every SaaS sends

EmailTriggered byMust arrive withinGuide
Email verificationSign-upSecondsOTP emails
Sign-in code or magic linkSign-inSecondsOTP emails
Password resetForgot passwordSecondsPassword reset
Team inviteAn admin invites someoneMinutes
Receipt / invoicePaymentMinutesInvoice emails
Security alertNew device, password changedSeconds
Usage or billing alertQuota nearly used, card failingMinutes
NotificationsActivity the user followsMinutes

What they share: the user expects them, they are about the user's own account, and a missing one is a support ticket - or a user who can't get in. That is why they deserve more engineering care than a newsletter.

1. Domain setup

Send from a subdomain of your product's domain, such as mail.yourapp.com, not from your company's main domain and never from a free mailbox. A subdomain keeps your application mail's reputation separate from your team's email, and lets you publish its records without touching the ones Google Workspace or Microsoft 365 need.

  • Publish SPF, DKIM and DMARC (starting at p=none) - all three are required by Gmail and Yahoo for bulk senders, and help at any volume.
  • Use a different subdomain for marketing (news.yourapp.com), so a bad campaign can't push password resets into spam.
  • Set a Reply-To that reaches a person, even if From is a no-reply address.

The SPF, DKIM and DMARC guide explains each record; the DNS checker shows what a domain publishes today.

2. Architecture: send from jobs, not requests

How a transactional email travels from your app to the inbox and backHTTPSqueuedSMTP + TLS250replystatus becomes an eventPOSTYour appPOST /v1/emailsgets { id } at onceEmail APIvalidate, checksuppression listQueue + signerDKIM-sign asyour domainSending serverSMTP to therecipient's MXRecipient serverSPF · DKIM · DMARCspam scoringInbox or spamGmail, Outlook,company mailSMTP reply250 · 4xx · 5xxLogs + webhooksemail.deliveredemail.bouncedYour handlerupdate yourdatabase

Swipe the diagram to see the rest

The life of one transactional email: your API call returns an id straight away, delivery happens asynchronously, and the outcome comes back as an event.

Put email sending behind a small module in your backend - one function per email type - and call it from background jobs. The request that triggers an email (sign-up, checkout) shouldn't wait on it, and a job queue gives you retries for free. Two rules keep retries safe:

  • Derive an Idempotency-Key from what the email is about - invite-{inviteId}, receipt-{paymentId} - so a retried job returns the original message instead of sending again.
  • Store the returned email id on the record, so support can look up exactly what was sent.
A retried request with an idempotency keyYour jobEmail APIPOST /v1/emailsIdempotency-Key: order-42-receiptemail sentid d67e39ed…response lost - timeoutretry, same keyIdempotency-Key: order-42-receipt200 { id: d67e39ed… }no second email

Swipe the diagram to see the rest

Why an Idempotency-Key matters. The first request succeeded but its response was lost; the retry carries the same key and gets the original id back instead of sending a second email.

3. Templates

Keep templates in your repository, next to the code that fills them, and render them to HTML before sending - React Email, MJML, Handlebars or plain template strings all work. Always send a plain-text part as well. Keep transactional emails free of promotions; a receipt that becomes an ad starts being treated like one.

4. Security

  • API keys live on the server, in a secrets manager - never in client code or the repository. Use a sending-only key for the app.
  • Codes and reset tokens are random, short-lived, single-use, and stored hashed.
  • Rate-limit every form that sends email, so it can't be used to flood someone's inbox.
  • Turn click tracking off for authentication mail: rewritten links look like phishing and security scanners pre-fetch them.
  • Verify webhook signatures; your endpoint is public.

5. Deliverability

Most of deliverability for transactional mail is not sending mail you shouldn't: to addresses that bounced, to people who complained, or mail users didn't expect. Suppression lists handle the first two automatically; product decisions handle the third. The deliverability checklist covers the rest.

6. Events and monitoring

Subscribe to email.bounced and email.complained and flag those users; alert on email.failed. Watch bounce and complaint rates over time - a sudden jump usually means a broken sign-up form or an import that shouldn't have happened. When a user says an email never arrived, search by recipient and read the message's timeline.

Sendpository email detail with its delivery timeline
The first place to look when a customer says "I never got it": the message's own timeline.

7. Choosing a provider

  • A free tier you can launch on, not just test with.
  • DNS setup that doesn't make you edit your company's existing SPF record.
  • Idempotency keys, batch sending and scheduled sends in the API.
  • Signed webhooks, searchable logs and automatic suppression.
  • Receiving, if your product handles replies or support mail.

The comparison of Resend, SendGrid, Postmark and Sendpository sets the main options side by side.

Questions

Which emails should a SaaS app send?

At minimum: email verification, password reset, sign-in codes or links if you use them, invites, receipts, and security alerts such as password changes. Add notifications and usage alerts as the product needs them.

Should transactional and marketing email use the same domain?

Use the same root domain but different subdomains - for example mail.yourapp.com and news.yourapp.com - so each has its own reputation and a marketing problem can't affect password resets.

Should I send email synchronously in the request?

No. Send from a background job with an idempotency key, so the user's request isn't slowed down and a failed send can be retried without sending twice.

Related

Send your first email in minutes

6,000 emails a month (up to 200 a day), free forever. No card needed.