You launch your app. The signup form works. Stripe works. The welcome email says it was sent.

Then the first customer writes: “I never got the password reset email.”

That’s not a small bug. If customers can’t confirm accounts, reset passwords, or get their invoice, they lose trust before they’ve used the product once. For a small SaaS, one broken email setup can look like the whole app is broken.

One common cause is boring and fixable: DKIM was never verified before launch.

DKIM in plain language

When your app sends email through a provider (Resend, Postmark, Amazon SES, SendGrid, Google Workspace, and so on), that provider is sending mail on your domain’s behalf. Gmail and Outlook don’t just take its word for it. They check for proof.

DKIM is that proof: a digital signature your provider attaches to every email, tied to your domain by a DNS record you publish once. Two related terms show up alongside it: SPF (a DNS list of servers allowed to send for your domain) and DMARC (the rule that tells inboxes what to do when neither SPF nor DKIM checks out). If you want the fuller picture of all three, this plain-English walkthrough covers it end to end.

This post is just about DKIM, because it’s the one step that fails silently and the one your email provider hands you as a copy-paste DNS record.

Why this hurts founders specifically

  1. Your app says the email was sent.
  2. Your provider’s dashboard may even show it as delivered.
  3. The customer never sees it, or it lands in spam.
  4. You find out only when someone complains, or doesn’t, and just leaves.

A user who can’t log in doesn’t convert. A customer who misses an invoice reminder doesn’t pay on time. A lead who never gets the magic-link email assumes your app is broken.

The 15-minute pre-launch DKIM check

Do this before you post your launch link anywhere.

Step 1: Open your provider’s domain settings

Go to the service your app uses to send transactional email. Look for a section called Domains, Sender authentication, DNS records, or Domain verification. You’ll see one or more DNS records to add, looking like this:

Type: CNAME
Name: selector1._domainkey.example.com
Value: selector1-example._domainkey.provider.example

or this:

Type: TXT
Name: selector1._domainkey.example.com
Value: v=DKIM1; k=rsa; p=MIIBIjANBgkqh...

You don’t need to understand every character. Your job is to copy the exact name and value into your DNS panel. That selector1 piece is a selector: the standard uses selectors so a domain can run more than one DKIM key at once, which is also how a provider rotates keys later without downtime.

Step 2: Watch for the doubled-domain trap

This is the single most common mistake, and it looks fine at a glance.

Some DNS panels want the full name:

selector1._domainkey.example.com

Others already know your domain and only want the left side:

selector1._domainkey

Paste the full name into a panel that appends your domain automatically, and you silently get this:

selector1._domainkey.example.com.example.com

That record sits in the wrong place, so DKIM will fail, but nothing in your DNS panel warns you. Before saving, check the preview if your panel shows one. The final record should end with your domain exactly once.

Step 3: Wait for DNS, then click verify

After adding the records, wait a few minutes. Some DNS changes propagate fast, some take longer. Then go back to your provider and click Verify or Check DNS.

Don’t continue while the domain is still marked unverified. “I added the record” isn’t the same as “the provider confirmed it can see the record.”

Step 4: Send a real test email to Gmail

Send the exact kind of email your customers will get (welcome, magic-link, password reset, invoice) to a Gmail address you control. Open it, click the three dots, choose Show original, and look for the Authentication-Results line:

Authentication-Results: mx.google.com;
  dkim=pass header.d=example.com;
  spf=pass ...;
  dmarc=pass header.from=example.com

You’re looking for dkim=pass header.d=example.com (or a matching organizational domain) — that’s the format the standard defines for reporting a DKIM result in this header. If you see dkim=fail, dkim=neutral, or no DKIM line at all, go back to your DNS records. Don’t panic: DKIM failing alone isn’t automatically a launch blocker, because DMARC can still pass if SPF is set up correctly for the same domain, a related check called alignment (a separate post covers it in plain terms). Fix DKIM soon anyway, because forwarding and provider changes tend to break the SPF side first.

Step 5: Check the From address matches your domain

Your email should come from something like hello@example.com, not a personal Gmail address or a raw provider domain. If your app shows noreply@example.com but the real sending domain underneath is different, that can still work, but only if DMARC passes. The Gmail Show original screen is your proof either way.

If DKIM fails, it’s almost always one of five things

1. The DNS name is doubled: selector1._domainkey.example.com.example.com instead of selector1._domainkey.example.com. Fix the name field, save, wait, verify again.

2. The value got mangled on copy: extra quotes, a trailing space, a line break your DNS panel doesn’t like. Copy it fresh from your provider and replace the whole field instead of hand-editing it.

3. You added a TXT record where the provider asked for CNAME (or vice versa). Use the exact type shown in your provider’s dashboard.

4. You verified the wrong subdomain. If your app sends from app.example.com but you only verified example.com, check your provider: some require each sending domain to be verified separately. Alignment itself usually still works, unless your DMARC record was set to demand an exact domain match (the adkim=s setting). Your provider’s setup page or your DNS admin can confirm.

5. Production is using a different sender than you tested. This happens constantly in AI-assisted and vibe-coded apps: the local test script sends from one address, the deployed environment variable points somewhere else, and nobody notices until a customer does. Check your production email settings directly, not your local .env file.

The launch bar to clear

Before you launch, you want one real customer-style email showing dkim=pass and dmarc=pass. If DKIM fails and aligned SPF is carrying DMARC instead, that’s a workable but temporary state. Fix DKIM soon, because forwarding and provider changes tend to break SPF alignment first. If neither mechanism aligns, treat it like a broken checkout button: don’t launch that flow yet.

After launch: this can break again

Adding a new email tool, changing DNS, or moving registrars can all quietly break what you just verified. DMARC aggregate reports are how you’d normally catch that: they show which senders are passing or failing for your domain, though reading your first one takes some getting used to.

Watching that by hand means opening a mailbox of DMARC reports every so often and cross-checking it against every tool you’ve connected. DMARC Guardian does that comparison for you: when your aggregate reports show a sender without a passing signature, it’s flagged on the Senders tab, which shows sources needing attention by default, instead of sitting buried in an XML attachment nobody opens.

If you already ran the 30-minute SPF/DKIM/DMARC bootstrap, this checklist is the narrower, launch-day version of step 3, worth running again right before you actually ship.

Copy-paste launch checklist

[ ] My email provider says the domain is verified
[ ] DKIM records are published in DNS
[ ] The DKIM record name is not doubled
[ ] A real app email was sent to Gmail
[ ] Gmail "Show original" says dkim=pass
[ ] Gmail "Show original" says dmarc=pass
[ ] The From address uses my product domain
[ ] Production uses the same sender I tested

Fifteen minutes now, or a launch day where customers can’t log in and your first support thread is “your app is broken.” Run a free check on your domain, no signup required.