Docs menuSender setup

Sender setup

These three DNS records prove your emails really come from you. Without them, Gmail, Outlook and Yahoo can’t tell your password reset from a phishing email pretending to be you, so they send it to spam, or drop it. Here is what each one does, how to check yours in one prompt, and exactly what to add for your email provider.

Guide

The records, in plain words

When your app sends an email, the receiving server asks your domain’s DNS three questions. The answers are records you add once, at whoever hosts your DNS (Cloudflare, Vercel, Namecheap, GoDaddy, Route 53…).

RecordThe question it answersWhat it looks like
SPFIs this server allowed to send email for this domain?v=spf1 include:amazonses.com ~all
DKIMWas this email really signed by the domain, and has nobody changed it on the way? Your provider signs every email with a private key; this record is the public half.resend._domainkey → p=MIGfMA0…
DMARCIf an email claiming to be from this domain fails those checks, what should I do with it, and where do I send reports?v=DMARC1; p=none; rua=mailto:…
Return pathWhere do bounces go? A bounce address on your own subdomain (send.yourdomain.com) lets SPF count for your domain, not your provider’s.send MX feedback-smtp…

DMARC passes when SPF or DKIM passes for the domain in your From address. That is why the provider’s own records aren’t enough: they prove the email came from Resend or SendGrid, not from you. Since 2024 Gmail and Yahoo require SPF, DKIM and a DMARC record from anyone sending in bulk.

Check your domain

Ask your agent. It reads your code to find which provider sends your email, then calls check_sender_domain, which looks your domain up in public DNS. Nothing is sent and no test run is needed.

Ask your agent
Check our sending domain with Flowproof's check_sender_domain. Work out which email provider this app sends with from the code, pass it, and tell me exactly which DNS records to add.

You get one line you can act on, then each record with exactly what to add:

What comes back
check_sender_domain   domain "acme.com", provider "resend"

2 of 4 ready: add DKIM and DMARC.

SPF          ready     SPF at send.acme.com authorises your provider (include:amazonses.com).
DKIM         missing   add  TXT  resend._domainkey.acme.com  p=<the public key Resend shows>
DMARC        missing   add  TXT  _dmarc.acme.com  v=DMARC1; p=none; rua=mailto:dmarc-reports@acme.com
Return path  ready     send.acme.com sends bounces back to Resend.
StatusMeans
readyThe record is there and says the right thing.
missingThere is no record. The result gives the type, the host and the value to add.
wrongThere is a record, but it is broken: two SPF records, an SPF record that allows every server, a revoked DKIM key, a DMARC record with no policy.
uncheckedDNS alone can’t tell. Some providers pick a random DKIM name or bounce subdomain per account (Postmark, SES, SendGrid); your agent asks you for it from the provider’s DNS page and checks again.

Values in <angle brackets> differ for every account: copy them from your provider’s dashboard. DNS changes can take up to an hour to show up, so give it a moment before you check again. The check is limited to 20 domains per 10 minutes per account.

Records for each provider

Hosts are relative to your sending domain: send means send.yourdomain.com. Each provider shows your exact values on the page named under its heading; add those, not the examples.

Resend

Where: Resend dashboard -> Domains -> your domain -> Records

Resend DNS records
ForTypeHostValueSource
DKIMTXTresend._domainkey.yourdomain.comp=<the public key Resend shows>resend.com
SPFTXTsend.yourdomain.comv=spf1 include:amazonses.com ~all "send" is the default return-path subdomain; you can choose another when you add the domain.resend.com
Return pathMXsend.yourdomain.com10 feedback-smtp.us-east-1.amazonses.com The documented value is for the us-east-1 region. For another region Resend shows its own value; copy it from the dashboard.resend.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:<a mailbox you read> Recommended once the domain is verified.resend.com

Domains added from August 2026 may be given CNAME records for the return path instead of the TXT and MX pair. Always add exactly what the Records tab shows.

Postmark

Where: Postmark -> Sender Signatures -> your domain -> DNS Settings

Postmark DNS records
ForTypeHostValueSource
DKIMTXT<date>pm._domainkey.yourdomain.comv=DKIM1; k=rsa; p=<the public key Postmark shows> Postmark picks the selector: a date-like string ending in "pm", e.g. 20230601123456pm._domainkey.postmarkapp.com
Return pathCNAMEpm-bounces.yourdomain.compm.mtasv.net pm-bounces is the default; you can pick another subdomain. This is also what makes SPF align.postmarkapp.com
SPFTXTyourdomain.comNothing to add Postmark no longer needs an include in your own SPF record: the Return-Path CNAME covers SPF.postmarkapp.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:<a mailbox you read> Postmark recommends DMARC but does not generate the record; this is the standard starting point. Unverified.rfc-editor.org

SendGrid

Where: SendGrid -> Settings -> Sender Authentication -> Authenticate Your Domain

SendGrid DNS records
ForTypeHostValueSource
Return pathCNAMEem<1234>.yourdomain.comu<1234567>.wl<123>.sendgrid.net With automated security on (the default). The em#### subdomain is random unless you set a custom return path.twilio.com
DKIMCNAMEs1._domainkey.yourdomain.coms1.domainkey.u<1234567>.wl<123>.sendgrid.nettwilio.com
DKIMCNAMEs2._domainkey.yourdomain.coms2.domainkey.u<1234567>.wl<123>.sendgrid.nettwilio.com
SPFTXTem<1234>.yourdomain.comv=spf1 include:sendgrid.net ~all Only with automated security off (then also MX em#### -> mx.sendgrid.net and a TXT DKIM key at m1._domainkey). With it on, the em#### CNAME covers SPF.twilio.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; SendGrid includes this in the records it generates.twilio.com

s1 and s2 are the default DKIM selectors; SendGrid lets you choose a custom three-character selector instead.

Amazon SES

Where: Amazon SES console -> Configuration -> Identities -> your domain

Amazon SES DNS records
ForTypeHostValueSource
DKIMCNAME<token>._domainkey.yourdomain.com (three of them)<token>.dkim.amazonses.com Easy DKIM. The tokens are random per identity, and some regions use a regional host (dkim.<region>.amazonses.com): copy all three exactly.docs.aws.amazon.com
Return pathMX<your MAIL FROM subdomain, e.g. mail>10 feedback-smtp.<region>.amazonses.com Custom MAIL FROM domain. Without it SES bounces through amazonses.com: SPF passes, but not for your domain.docs.aws.amazon.com
SPFTXT<your MAIL FROM subdomain>v=spf1 include:amazonses.com ~alldocs.aws.amazon.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:<a mailbox you read> AWS suggests moving from none to quarantine to reject once reports are clean.docs.aws.amazon.com

SES only delivers to verified addresses until you request production access.

Mailgun

Where: Mailgun -> Sending -> Domain settings -> DNS records

Mailgun DNS records
ForTypeHostValueSource
SPFTXTyourdomain.com (the domain you added to Mailgun, often mg.<your domain>)v=spf1 include:mailgun.org ~alldocumentation.mailgun.com
DKIMTXT<selector>._domainkey.yourdomain.comk=rsa; p=<the public key Mailgun shows> The selector is shown in Mailgun (and can be set through the API). With Automatic Sender Security it is two CNAMEs instead: pdk1._domainkey and pdk2._domainkey -> ...dkim1.mailgun.com.documentation.mailgun.com
Return pathMXyourdomain.com (the Mailgun domain)10 mxa.mailgun.org and 10 mxb.mailgun.org EU accounts: mxa.eu.mailgun.org and mxb.eu.mailgun.org. Never put these on a domain whose inbox you use: send from a subdomain.documentation.mailgun.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:<a mailbox you read> Mailgun offers a generated DMARC record; its exact value is not in its public docs. Unverified.rfc-editor.org

Brevo

Where: Brevo -> Senders, Domains & Dedicated IPs -> Domains

Brevo DNS records
ForTypeHostValueSource
OwnershipTXTyourdomain.combrevo-code:<the code Brevo shows>developers.brevo.com
DKIMTXTmail._domainkey.yourdomain.comk=rsa;p=<the public key Brevo shows> Newer setups use two CNAMEs instead (DKIM 1 and DKIM 2); their exact names are shown in Brevo, not in its public docs.developers.brevo.com
SPFTXTyourdomain.comNothing to add on a shared IP Brevo says SPF and MX are not required to authenticate a domain; it provides them for a dedicated IP.help.brevo.com
Return pathCNAME<branded subdomain, e.g. send><the target Brevo shows> The optional "branded" CNAME aligns SPF and the return path. Brevo shows the target; it is not in its public docs. Unverified.help.brevo.com
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:rua@dmarc.brevo.comhelp.brevo.com

If a domain is not authenticated, Brevo sends from a brevosend.com address instead of yours.

Other SMTP provider

Where: Your provider's domain or sender authentication page

Other SMTP provider DNS records
ForTypeHostValueSource
SPFTXTyourdomain.com or the provider's bounce subdomainv=spf1 include:<your provider> ~all Your provider gives you the include. Unverified.rfc-editor.org
DKIMTXT<selector>._domainkey.yourdomain.comv=DKIM1; k=rsa; p=<public key> Your provider gives you the selector and key. Unverified.rfc-editor.org
DMARCTXT_dmarc.yourdomain.comv=DMARC1; p=none; rua=mailto:<a mailbox you read>rfc-editor.org

Don’t launch on your auth provider’s built-in mailer

Supabase, Auth0, Cognito and Firebase all send sign-up and password-reset emails out of the box, from their own domain. That is fine while you build. In production it breaks in ways you won’t see:

  • Supabase’s built-in email sends only a few emails an hour; past that, sign-ups and password resets silently get no email.
  • Auth0’s built-in provider is for testing only, with a low limit and no deliverability promises.
  • Cognito’s default email sends a limited number a day for the whole user pool, then stops.
  • Firebase sends from a shared firebaseapp.com address your users don’t recognise.

And none of them can pass DMARC for your domain, because the email isn’t from your domain. Connect your own provider (custom SMTP in Supabase and Firebase, Amazon SES in Cognito, an email provider in Auth0), send from an address on your domain, add the records above, and a Flowproof run will stop flagging shared_auth_mailer.

DMARC: start at none, then tighten

Start with p=none and a rua= address: receivers deliver as normal and send you daily reports of who is sending as your domain. Once the reports show only your own services passing, move to p=quarantine (failures go to spam), and later p=reject. Moving too early sends your own misconfigured email to spam, so fix alignment first.

Have exactly one DMARC record and one SPF record per name. Two of either is an error, and receivers then ignore both.

Then test the real thing

DNS says what you published; it can’t say what a receiver made of a real email. Once the check is all ready, have your agent send each email through your provider to a Flowproof test address: the report grades SPF, DKIM and DMARC as the receiving server saw them. See how a test run works.