How to improve email deliverability for the email your app sends starts with one message it already sent: open it and read the headers. If the authentication results do not say pass for SPF, DKIM and DMARC, fix that first. The other two controls, tracked transactional delivery and bounce handling, sit behind it, and each has a test.

How to improve email deliverability for an app’s own email: the three controls

Email deliverability for an app comes down to three controls: the sending domain authenticated with SPF, DKIM and DMARC and proven on a received message, every critical message sent through a dedicated provider and tracked, and bounces and complaints processed so further sending is suppressed where appropriate.

Email is one of 13 areas in production hardening, with 3 of its 123 checks, and it is one of the areas that keep the rest of the app’s fixes working over time: a login flow that works is no use if the reset link never arrives. Advice written for marketing campaigns (list hygiene, subject lines, send cadence) mostly misses an app’s own mail. For password resets, verification links and invoices, the email deliverability setup checklist is short: these three controls, in this order.

ControlWhat it isWhy it mattersWhere the fix lives
1. Sending-domain authenticationSPF, DKIM and DMARC records on the domain your app sends fromDomain-authentication problems can undermine legitimate email deliverySPF, DKIM and DMARC setup
2. Transactional delivery trackingA dedicated provider that records each account and billing messageUntracked failures make it difficult to know whether a customer received a critical messagetransactional email best practices
3. Bounce and complaint handlingProvider events that stop further mail, where appropriate, to addresses that bounced or complainedRepeated sending to invalid or complaining recipients can damage sending reputationemail bounce handling checklist

How a message travels from your app to the inbox

A message from your app makes four hops: your code calls the provider’s API, the provider hands it to the recipient’s mail server, that server checks SPF, DKIM, DMARC and the sender’s reputation, and the mailbox filter picks inbox or spam. Each hop leaves its own evidence, and only the last one is the inbox.

That is how email flow works for app-sent mail, and the table below is the path with the place to look at each step. Resend is the worked example because Resend’s event types define each event in plain words; other providers name theirs differently. The evidence column says where I’d look; the quoted event wording is Resend’s.

HopWhat happensThe evidence it leaves
1. App to providerYour code calls the provider’s APIThe API response; in Resend, email.sent: “the API request was successful”
2. Provider to the recipient’s mail serverThe provider hands the message overemail.delivered: “successfully delivered the email to the recipient’s mail server”, or email.bounced: “the recipient’s mail server permanently rejected the email”
3. Receiving server checksSPF, DKIM and DMARC results, plus the sender’s reputationThe Authentication-Results line in the received message’s headers
4. Mailbox filterInbox or spamThe inbox itself, or email.complained: “successfully delivered, but the recipient marked it as spam”

The gap that matters sits between hops 2 and 4: a delivered event closes hop 2 and says nothing about hop 4. I’d trace the verification email first, since a new user meets it before any other message; the sending side is about how to send a verification email, the content about a verification email template.

Email deliverability rate versus delivery rate: the two numbers, and what counts as healthy

Email deliverability is the share of messages that reach the inbox; delivery rate is the share the recipient’s mail server accepted. Resend’s delivered event, for one, means the message reached the recipient’s mail server, so a delivered message can still end up in spam. The line both Gmail and Yahoo publish is a spam rate below 0.3 percent.

That first definition is my working one for what email deliverability means, and “accepted” is my paraphrase of Resend’s delivered event, which is one provider’s definition, not every provider’s. The healthy line comes from the mailbox providers themselves. Gmail’s sender guidelines require all senders to “Keep spam rates reported in Postmaster Tools below 0.3%”, and their best practices go further: “Keep spam rates reported in Postmaster Tools below 0.10% and avoid ever reaching a spam rate of 0.30% or higher.” Yahoo’s sender requirements say “Keep your spam rate below 0.3%”, a rate Yahoo calculates “based on mail delivered to the inbox”. As of October 2026, Yahoo’s page says its requirements “are subject to change”, and Gmail’s keeps a table of updates to its requirements, so check both again before you lean on a figure. Neither page, as I read them, gives an inbox-placement percentage to aim for.

An app can measure two things itself. Complaints arrive as provider events, such as the complained event in the hop table. For Gmail recipients, Google Postmaster Tools has dashboards on “spam rate, reputation, message authentication, and delivery errors”, with three conditions. Its data “only applies to messages sent to personal Gmail accounts”. You add your DKIM or SPF (Return-Path) domain and verify it with a TXT or CNAME record, since “Postmaster Tools won’t display information about your email until your domain is verified”. And “Data might be missing if the total number of messages for a given day is too low.” A small app may see empty dashboards for that last reason, which Google says is there “to protect users’ privacy.”

The deliverability problems a live app actually hits, and which fix belongs to which

The table sorts five email deliverability issues by what you notice first, with the page that owns each fix. Each cause is the likely one, not a certain one, and the first-check column is my order, not a source’s.

SymptomLikely causeFirst checkPage
Password resets land in spamMail that fails DMARC for your From domain, or a weak domain reputationRead the Authentication-Results line in one received resettransactional emails landing in spam
A customer forwards a message you never sent, from your domainNo DMARC record, or one at p=noneLook up the TXT record at _dmarc on your domainhow to stop email spoofing
Signup fails with a rate-limit error on the confirmation emailA built-in auth mailer’s sending limitCheck which mailer sends your auth emailemail rate limit exceeded
Bounces pile up in the provider dashboardRepeat sends to addresses that already bouncedCount sends to addresses with an earlier bounceemail bounce handling checklist
No way to tell whether a message arrivedNo per-message events recordedFind one sent message in the provider’s loghow to test email deliverability

What goes wrong without it

Each failure below starts from what you or a user would notice, and points back to the controls table for the reason it matters.

The password reset lands in spam

A user asks for a reset, waits, and finds it in spam, or never finds it. One likely cause is mail that does not authenticate as your domain, so the receiving server has little reason to trust it (the first row of the controls table). Gmail’s requirements for senders of more than 5,000 messages a day to Gmail accounts include this line: “For direct email, the domain in the sender’s From: header must be aligned with either the SPF domain or the DKIM domain,” which Gmail says “is required to pass DMARC alignment.” Its list for all senders asks for SPF or DKIM. Take a founder whose app sends resets through a transactional provider whose log marks each one delivered. A user finds a reset in spam; in the provider’s terms, delivered meant the message reached the recipient’s mail server, and the headers show DMARC did not pass, with the From domain aligned with neither the SPF domain nor the DKIM domain. I’d put it this way: the log answers whether the message was accepted, the headers whether it authenticated, and only the inbox whether it arrived. The fix is the records themselves: SPF, DKIM and DMARC setup, the first row of the controls table.

Someone else sends mail as your domain

A customer forwards a message from your domain that you never sent. The likely cause is a DMARC record that asks for nothing, or no record at all. At p=none, RFC 9989 says “The Domain Owner offers no expression of preference.” At quarantine, the owner “considers such mail to be suspicious”, and the RFC keeps a hedge: “It is possible the mail is valid, although the failure creates a significant concern.” At reject, the owner “considers all such failures to be a clear indication that the use of the domain name is not valid.” Even then the receiver decides, since RFC 9989 tells receivers not to reject mail on that policy alone. Moving a domain that already sends mail from none to reject is its own job, in how to stop email spoofing.

The invoice never went out and nothing says so

A customer asks where their invoice is, and nobody can say whether it was sent, bounced or never left your code. With no per-message record from a provider, a failed send can look like a successful one until someone writes in (the second row of the controls table). The fix is a provider that records every account and billing message as events you can look up, set up along the lines of transactional email best practices.

Bounces pile up and your sending reputation drops

The provider dashboard shows a growing list of bounced addresses, and the same addresses keep getting mail. Each repeat send to an address that already rejected you, or to someone who marked you as spam, can count against your domain (the third row of the controls table). Gmail notes that user spam reports, over time, “can lower your domain’s reputation.” The fix is a suppression list your code reads before every send, built from the email bounce handling checklist.

The three controls, one by one

Each control below gives what it is, the check that proves it, and what to record.

1. The sending domain is authenticated, and a received message proves it

The control: verify and configure SPF, DKIM, and DMARC for the transactional sending domain. SPF records “specify the list of IPs which are allowed to send mail for that domain”, and DKIM signatures let a receiver “verify that the content of the email has not been changed during transmission”, in Yahoo’s words. SPF is checked on the envelope sender, the Return-Path domain, not the From address: RFC 9989 says “DMARC relies solely on SPF validation of the MAIL FROM identity”, and Google’s Postmaster setup calls it the “SPF (Return-Path) domain”. DMARC ties the two to the From domain: a pass needs SPF or DKIM to pass for a domain aligned with it. The three policy values are quoted in the spoofing section above. The check: inspect DNS and received message headers for the configured authentication results. In Gmail, open the message and, next to Reply, click More, then Show original. In the Authentication-Results line, dmarc=pass is the goal; dmarc=none means no DMARC record exists for the From domain, and dmarc=fail means one exists but nothing aligned. Record the date, the three DNS records and the Authentication-Results line. Record syntax per provider is in SPF, DKIM and DMARC setup, and testing tools in how to test email deliverability.

2. Every critical message goes through a dedicated provider and is tracked

The control: configure a dedicated transactional provider with delivery tracking for account and transaction messages. Resend, Postmark, SendGrid and Amazon SES are examples of such providers, in no order. Amazon SES has a condition new accounts hit, in AWS’s words: “We place all new accounts in the Amazon SES sandbox”, where “You can only send mail to verified email addresses and domains, or to the Amazon SES mailbox simulator” and “You can send a maximum of 200 messages per 24-hour period”; the sandbox status is “unique per each AWS Region”. Until production access is granted, I take that to mean a test send to your own verified inbox passes while customers get nothing. A builder’s built-in auth mailer is the other trap: Supabase calls its default SMTP server “not meant for production use”, and Supabase’s built-in email limit is the number to know before launch. The check: trigger each critical message type and confirm provider records and expected recipient delivery. Record each message type (signup, reset, invoice, receipt), the provider’s message id and its last event. The sending patterns are in transactional email best practices; a signup blocked by a sending limit is the email rate limit exceeded row above.

3. Bounces and complaints stop the next send where they should

The control: process bounces and complaints and suppress further sending where appropriate. Your app listens for the bounced and complained events from the hop table and writes the address to a suppression list it checks before each send. Yahoo’s version of the same advice: “Remove invalid recipients from your list promptly.” “Where appropriate” is a decision to write down: I’d note which message types a complaint stops, because a complaint about a digest and a reset the user just requested are different cases. A provider may also block on its side: Resend has an email.suppressed event, which “Occurs whenever the email is suppressed by Resend.” The check: simulate provider events and verify suppression and subsequent send behavior. Record the event received, the row your app wrote, and what happened to the next send. The full set of cases is in the email bounce handling checklist.

The best email deliverability checklist for an app, verified in about an hour

Verifying this area takes three tests and, as my working estimate, about an hour: read the authentication results in a received message’s headers, trigger each critical message and match the provider’s record with the inbox, and simulate a bounce and a complaint and confirm the next send is suppressed.

Run them against your real sending domain, with inboxes and test addresses you control, never real customers. Each item points back to its control, where the check is quoted; write down the date and what you saw for each.

  1. 01 Authentication (control 1): look up the SPF, DKIM and DMARC records, send one message to an inbox you control, and keep a copy of its Authentication-Results line.
  2. 02 Tracked delivery (control 2): trigger each critical message type, find each one in the provider log with its latest event, then open a test inbox and note whether it landed in the inbox or in spam. The inbox look is my addition.
  3. 03 Suppression (control 3): send to a bounce address and a complaint address, confirm your app recorded both events, then send to both again and note whether your app or the provider stopped the send.

For the third test, Resend’s test addresses include bounced@resend.dev and complained@resend.dev, and the page notes that “Test emails count against your account’s sending quota.” If your provider documents no test address, use a real bounce from an address you control, such as a mailbox at your own domain that does not exist. The rest of the app needs the same kind of list: the full production readiness checklist.

Where the sprint stops

The sprint’s three email deliverables name the transactional sending domain and account and transaction messages; none of them names marketing campaigns. The email provider account stays yours: hosting, paid tools, and API usage remain in your accounts. Formal third-party certifications and independent audit opinions are separate from these engineering deliverables.

Where the sprint does this

Area 11 of the Production Hardening Sprint is these three controls, 3 of its 123 deliverables. We deliver each one as described under its control above and check it with the test quoted there. The result for every scope item, with its verification evidence, goes into the production readiness report, which keeps failures visible until resolved. The three entries are listed in area 11 of the published scope.

Common questions about email deliverability

How to fix email deliverability issues?

Fix the control that failed: for an app’s own mail, that is the domain’s DNS records, the provider setup, or the code that handles bounce and complaint events. To find which one, match what you see to a row of the symptom table above, run that row’s first check, and open the page it names.

What is a good email deliverability rate?

Neither Gmail nor Yahoo publishes an inbox-rate target, so there is, to my knowledge, no official good number for deliverability itself. What both publish is a ceiling on spam complaints, under 0.3 percent, and Gmail’s best practices aim lower, under 0.10 percent.

Which email service has the best deliverability?

The one you finish setting up: in my view, a dedicated transactional provider with your domain authenticated and bounces handled matters more than the brand. Resend, Postmark, SendGrid and Amazon SES are all examples of that kind of provider; with SES, read the sandbox condition in the dedicated-provider control above first.

What is the best tool for testing email deliverability?

A received message’s headers come first, because they show whether SPF, DKIM and DMARC passed for that exact message. For mail to Gmail users, Google Postmaster Tools adds spam rate, reputation and authentication dashboards once your sending domain is verified, though its data covers personal Gmail accounts only and may be missing on days with too few messages. For dedicated testing tools, start from how to test email deliverability.