DKIM, SPF, DMARC and custom MAIL FROM: a practical guide for transactional email
If your password-reset emails land in spam, or don't arrive at all, the cause is often not the content. It's authentication. Mailbox providers want proof that a message really comes from the domain it claims to come from, and they get that proof from DNS.
This guide covers the four pieces you'll set up when sending with Sendonis, which is launching soon: SPF, DKIM, DMARC and a custom MAIL FROM domain. They're open standards, so almost everything here applies to any sending service, and you can get your DNS ready now. We'll explain what each one checks, how they fit together, and what the records look like. From launch, the exact values for your domain will be shown in the Sendonis dashboard when you add it. The examples below only show the format.
Two "from" addresses
Every email has two sender addresses, and most confusion about authentication comes from mixing them up.
- Header From. The address recipients see in their mail client, for example
receipts@acme.example. This is the one people care about, and the one DMARC protects. - Envelope sender (MAIL FROM, or Return-Path). The address used during delivery, where bounce messages are sent. Recipients usually never see it.
Many sending platforms use one of their own domains as the envelope sender by default. That works, but it means part of your authentication is done in the platform's name rather than yours. A custom MAIL FROM domain fixes that. More on this below.
SPF: which servers may send for this domain?
Sender Policy Framework (SPF) is a TXT record that lists the servers allowed to send mail for a domain. The receiving server looks up the SPF record of the envelope sender's domain, not the visible From, and checks whether the sending server's IP address is on the list.
An SPF record usually authorises a sending service through an include: mechanism and ends with a policy for everything else:
v=spf1 include:<your sending service's SPF domain> ~all
Things to know:
- One SPF record per name. If a domain has two
v=spf1TXT records, SPF returns an error. Merge them into one. - The 10-lookup limit. SPF allows at most 10 DNS-querying mechanisms (such as
include,a,mx) per evaluation. Every service you add withinclude:counts towards that limit. Going over it causes a permanent error. - SPF breaks on forwarding. When a message is forwarded, the forwarding server's IP usually isn't in your SPF record. That's one reason DKIM matters.
DKIM: was this message signed by the domain?
DomainKeys Identified Mail (DKIM) adds a cryptographic signature to each message. The sending service signs selected headers and the body with a private key. The receiver fetches the matching public key from DNS and checks the signature. If the message was changed in transit, or wasn't signed by someone with the key, the check fails.
The signature names a signing domain (the d= tag) and a selector (the s= tag). DMARC looks at the signing domain. The public key lives at <selector>._domainkey.<your domain>. Services publish it in one of two ways:
- a TXT record that contains the public key itself (
v=DKIM1; k=rsa; p=…), or - one or more CNAME records that point to keys the service manages, so keys can be rotated without you editing DNS.
A CNAME-based setup looks like this:
sel1._domainkey.acme.example CNAME <value from your dashboard>
sel2._domainkey.acme.example CNAME <value from your dashboard>
Copy the names and values exactly from the dashboard. Prefer 2048-bit keys where you have the choice.
Custom MAIL FROM: make SPF count for your domain
If the envelope sender is the platform's domain, SPF will pass, but for the platform's domain, not yours. For DMARC purposes, that SPF pass doesn't help you.
A custom MAIL FROM domain is a subdomain of your sending domain, for example bounce.acme.example, used as the envelope sender instead. You publish two records on it:
bounce.acme.example MX 10 <feedback host from your dashboard>
bounce.acme.example TXT "v=spf1 include:<SPF domain from your dashboard> ~all"
- The MX record tells receiving servers where to send bounce messages for your mail. With Sendonis, those bounces flow back to us, and we update your suppression list and call your webhook. This record only handles bounce feedback. It isn't a way to send mail.
- The TXT record is the SPF policy for that subdomain.
Use a subdomain that isn't used for anything else. In particular, don't use one that needs to receive normal email, because its MX record will point to the bounce-processing host.
With a custom MAIL FROM in place, SPF passes for a subdomain of your domain. That gives you a second aligned check alongside DKIM.
DMARC: tie it all to the visible From
DMARC (Domain-based Message Authentication, Reporting and Conformance) is the policy layer. It's a TXT record at _dmarc.yourdomain that tells receivers two things: how to treat mail that fails authentication, and where to send reports.
A message passes DMARC if at least one of the following is true:
- SPF passes and the envelope sender's domain aligns with the header From domain, or
- DKIM passes and the DKIM signing domain (
d=) aligns with the header From domain.
"Aligns" by default means relaxed alignment: the two domains share the same organisational domain. So bounce.acme.example aligns with receipts@acme.example. That's why a custom MAIL FROM subdomain works.
A good starting record:
_dmarc.acme.example TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@acme.example"
p=nonemeans "monitor only": receivers don't change how they handle failing mail, but they send aggregate reports to theruaaddress.- After you've reviewed the reports and confirmed that all legitimate mail passes, including mail from other services that send as your domain, move to
p=quarantineand thenp=reject.
Our Acceptable Use Policy asks every customer to publish at least a p=none DMARC record for each sending domain. Large mailbox providers have also tightened their requirements in recent years. Gmail and Yahoo, for example, now expect bulk senders to authenticate with SPF and DKIM and to publish DMARC.
Putting it together
For a sending domain acme.example with mail sent as receipts@acme.example, the complete setup is:
| Purpose | Name | Type | Value |
|---|---|---|---|
| DKIM | <selector>._domainkey.acme.example | CNAME or TXT | from your dashboard |
| MAIL FROM bounces | bounce.acme.example | MX | 10 + feedback host from your dashboard |
| MAIL FROM SPF | bounce.acme.example | TXT | v=spf1 include:… ~all |
| DMARC | _dmarc.acme.example | TXT | v=DMARC1; p=none; rua=mailto:... |
Because SPF is checked on the MAIL FROM subdomain, you usually don't need to change the SPF record on your root domain for Sendonis. Leave it for the other services that send as your domain.
Common mistakes
- Doubled domain names. Many DNS dashboards append your domain automatically. Entering
bounce.acme.examplemay createbounce.acme.example.acme.example. If yours does, enter onlybounce. - Proxied CNAMEs. If your DNS provider can proxy traffic, set the DKIM CNAMEs to DNS-only. A proxied record won't resolve to the signing key.
- Two SPF records on the same name. Merge them.
- Jumping straight to
p=reject. You may block legitimate mail from another tool you forgot about. Monitor first. - Using the MAIL FROM subdomain for something else. Keep it dedicated.
Checking your work
DNS changes can take time to propagate. Once the records resolve, the Sendonis dashboard will show when your domain is verified. To confirm end to end, send a test message to a mailbox you control and look at the authentication results in the message headers. You want spf=pass, dkim=pass and dmarc=pass, with your own domain shown for each.
Step-by-step instructions will be in our documentation at launch. Until then, join early access to hear as soon as Sendonis is live.
