DKIM, SPF, DMARC
Email authentication is three protocols working together. DKIM signs your messages so recipients know they came from you. SPF tells recipients which servers are allowed to send for your domain. DMARC tells recipients what to do when the other two disagree.
ScaiSend handles DKIM signing automatically. SPF and DMARC are DNS records you publish. Both are generated for you when you add a sender domain — this page explains what they do so you know what you're publishing.
DKIM#
What it is#
DKIM (DomainKeys Identified Mail, RFC 6376) is a cryptographic signature over the message body and selected headers. The signer has a private key; the verifier fetches the public key from DNS and checks the signature.
If the signature verifies, the receiver knows:
- The message body wasn't modified in transit.
- The sender genuinely has control of the private key.
The DNS record#
ScaiSend generates an RSA-2048 keypair per sender domain. The public key is published as a TXT record at:
1 | |
Value:
1 | |
scaisend is the selector — the first label of the record path. Multiple keys can coexist under different selectors (e.g., during rotation, scaisend and scaisend2 can both be valid).
Signing#
When the SMTP service is about to deliver a message, it:
- Canonicalizes the headers and body (simple or relaxed canonicalization; ScaiSend uses relaxed).
- Computes an SHA-256 hash of the canonical body.
- Signs the hash plus a selected set of headers (From, To, Subject, Date, Message-ID, MIME-Version, Content-Type) with the private key.
- Adds the signature as a
DKIM-Signature:header.
A typical header looks like:
1 2 3 4 | |
Verifying on the receiving side#
When a recipient MX gets the message, it:
- Parses the
DKIM-Signatureheader. - Fetches
s._domainkey.d(the selector at the domain). - Decodes the public key.
- Recomputes the canonicalization and hash.
- Verifies the signature.
If any of these fail, the DKIM check fails. The receiver won't bounce just for that (typically; depends on DMARC policy) but your deliverability takes a hit.
Rotation#
Rotate keys annually or whenever compromise is suspected. ScaiSend generates a new keypair under a new selector, publishes the new public key, and switches signing over once DNS has propagated:
1 2 | |
The old selector stays live until you explicitly remove it. Leaves a window where in-flight mail signed with the old key can still be verified.
SPF#
What it is#
SPF (Sender Policy Framework, RFC 7208) is a TXT record at the sending domain listing which mail servers are authorized to send for it. It's a simple IP/hostname allowlist.
The DNS record#
ScaiSend uses include: to delegate:
1 | |
Or, for a subdomain sender:
1 | |
Meaning:
v=spf1— this is an SPF record (version 1).include:scaisend.scailabs.ai— trust the SPF rules published atscaisend.scailabs.aifor the ScaiSend-operated outbound IPs.~all— soft-fail anything else. Most receivers treat soft-fail as a quarantine signal.
If you already have an SPF record#
You can't have two SPF records. Merge:
Existing:
1 | |
After adding ScaiSend:
1 | |
SPF alignment#
DMARC requires the SPF-authenticated domain to align with the From: header domain. If your From: is hello@mail.example.com and SPF authorizes mail.example.com, they align. If From: is hello@example.com but SPF is on mail.example.com, relaxed DMARC still counts that as aligned (shared organizational domain).
DMARC#
What it is#
DMARC (Domain-based Message Authentication, Reporting, and Conformance, RFC 7489) tells receivers what to do when both SPF and DKIM fail to align with the From: domain. It's the policy that gives SPF and DKIM teeth.
The DNS record#
ScaiSend generates a DMARC TXT record when you add a domain:
1 | |
Meaning:
v=DMARC1— this is a DMARC record.p=quarantine— if a message fails both SPF and DKIM, put it in spam. (Alternatives:nonefor no action,rejectfor bounce.)rua=mailto:...— send aggregate reports here.
Policies: which to use#
| Policy | When |
|---|---|
none |
Starting out. Monitoring-only. Reports flow in; nothing is blocked. |
quarantine |
Confirmed clean setup. Failures go to spam. Reasonable default. |
reject |
Established reputation. Failures are outright rejected. |
Start with none. Watch the rua reports for a couple of weeks. Look for:
- Mail from your domain that you didn't send (spoofing).
- Mail that you did send but fails DKIM or SPF (misconfigured service).
Once the only things failing are actual spoofs, graduate to quarantine. Later, if you're confident, to reject.
Subdomain policy#
sp= specifies a policy for subdomains. If you want strict enforcement on mail.example.com but no policy on login.example.com, publish the DMARC record at _dmarc.example.com with sp=none:
1 | |
DMARC alignment#
DMARC considers SPF-aligned OR DKIM-aligned as a pass. Either authentication getting the From: domain right is sufficient. Since ScaiSend always DKIM-signs, alignment is straightforward as long as your DKIM record is published for the same domain that appears in From:.
How they fit together#
A message arrives at a recipient MX:
- SPF check. The connecting IP is compared against the SPF record at the envelope-sender domain. Result: pass, neutral, softfail, fail.
- DKIM check. The
DKIM-Signatureheader is validated against the public key ats._domainkey.d. Result: pass or fail. - DMARC alignment. The
From:header domain is compared against the domains that SPF and DKIM authenticated. If either aligns AND that check passed, DMARC passes. Otherwise DMARC fails. - DMARC policy. If DMARC fails, the receiver consults the DMARC policy (
p=).quarantine→ spam folder;reject→ bounce.
For a well-configured ScaiSend deployment sending from hello@mail.example.com:
- SPF: the connecting IP is one of ScaiSend's outbound IPs → listed via
include:scaisend.scailabs.ai→ pass. - DKIM: signed with the key at
scaisend._domainkey.mail.example.com→ verifies → pass. - Alignment: both SPF and DKIM identify
mail.example.com, same asFrom:. → aligned. - DMARC pass.
Verifying#
Use a mail-test service or send a test message to a Gmail account and check Show original. You should see:
1 2 3 | |
If any fails, the errors[] on POST /api/admin/domains/{id}/verify tells you which DNS record is missing or wrong.
Common failure modes#
"DKIM: PASS with domain scaisend.scailabs.ai, but DMARC fails."
Your DKIM is publishing under the wrong domain — most likely because you didn't publish the key at scaisend._domainkey.<your-domain> and the verifier is falling back to something generic. Republish.
"SPF: PERMERROR / too many DNS lookups."
SPF has a 10-lookup limit. If you have a deep chain of include: directives, you hit the cap. Flatten the SPF record — replace includes with explicit IPs if necessary.
"DMARC: FAIL (policy: none)."
The message failed alignment but your policy is none so nothing happens. Check the rua report to diagnose why alignment failed. Fix SPF/DKIM, then graduate policy.
Related#
- Sender Domains — adding and verifying domains.
- Admin Reference — domain endpoints.
- Bounce Handling — what happens when mail fails.