SPF, DKIM and DMARC set up for better deliverability
Setting up SPF, DKIM and DMARC for better deliverability
Since February 2024, Google and Yahoo require bulk senders — more than 5,000 messages per day to Gmail addresses — to have DKIM and DMARC configured. They are not suggestions. Recipients who cannot authenticate your domain will reject the mail or put it in spam. This article explains how to set up the three protocols, in the right order, without breaking your own mail traffic.
Requirements
- Access to the DNS settings of your domain.
- Root access to your mail server (Postfix, Exim, or another platform that supports DKIM signing).
- A valid TLS certificate for your mail server — not strictly needed for authentication, but without encryption your mail will not reach the inbox of major providers.
- Knowledge of the systems that send mail on behalf of your domain. Make a list before you start: your own server, marketing platform, ticketing system, everything.
Step 1: Inventory all sending systems
Every service that sends email with your domain in the `From:` header must be included in the authentication. Do not forget the transactional messages: password resets, invoices, notifications. Those are often overlooked, and they are exactly the ones that providers check strictly.Create an overview of:
- IP addresses of your own mail server(s)
- External services (Mailchimp, SendGrid, Google Workspace, Microsoft 365)
- Any subdomains that send mail separately
Step 2: Set up SPF
Sender Policy Framework is a TXT record in your DNS that indicates which IP addresses and services are allowed to send on behalf of your domain. One record per domain — multiple records lead to a permanent error.Create a record like this, replacing the values with your own:
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com include:sendgrid.net ~all
`ip4` specifies an IP range, `include` refers to an external domain that is also allowed to send, `~all` means that other sources should be quarantined, `-all` that they should be hard rejected.
SPF has a hard limit of 10 DNS lookups per check. Each `include` counts, and some includes from major providers count multiple times. If you exceed the limit, the SPF check fails automatically — even for legitimate senders. Therefore, keep the record as short as possible. Remove services you no longer use. Use one `include` for a provider instead of multiple separate IP addresses.
Step 3: Configure DKIM
DKIM adds a cryptographic signature to the header of each message. The recipient retrieves the corresponding public key from your DNS and uses it to validate both the sender and the integrity of the content. If the mail has been altered in transit, the signature fails.Generate a key pair on your mail server. On a system with OpenDKIM:
opendkim-genkey -s default -d example.com -b 2048
This creates two files: `default.private` and `default.txt`. You place the public key from `default.txt` as a TXT record in your DNS under the selector `default._domainkey.example.com`.
Configure your mail server to sign with the private key. For Postfix with OpenDKIM, add to `/etc/opendkim.conf`:
Mode sv
KeyFile /etc/opendkim/keys/example.com/default.private
Selector default
Canonicalization relaxed/simpleThen restart the services:
systemctl restart opendkim postfix
Use 2048-bit keys. Shorter ones are increasingly considered insufficiently secure by more providers. Rotate your selectors periodically — if a key leaks, you limit the damage that way.
It is important that DKIM is on all outgoing mail, not just your newsletters. Transactional messages must be signed just as well.
Step 4: Publish a DMARC record with p=none
DMARC builds on SPF and DKIM and adds two things: a policy for messages that fail the checks, and a requirement for alignment. The domain in the `From:` header must match the domain validated by SPF (via `Return-Path`) or by DKIM (via the `d=` tag). Without alignment, DMARC fails, even if SPF and DKIM pass individually.You write DMARC as a TXT record on `_dmarc.example.com`. Always start with `p=none`:
v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-failures@example.com; fo=1`p=none` means that nothing happens yet with failing messages — you only receive reports. `rua` receives summaries from providers, `ruf` individual failure reports.
Without a DMARC record, recipients handle unrecognized mail on their own. With a record — even with `p=none` — you indicate that you manage the domain and you gain visibility into who sends on your behalf.
Step 5: Analyze the reports
Leave `p=none` in place for two to four weeks. The reports that come in via `rua` and `ruf` show which systems send mail on behalf of your domain — including sources you do not recognize. You must either add those to SPF and DKIM, or consider them as abuse.Check per source:
- Does the IP address match a system that you manage?
- Is the DKIM signature valid?
- Is there SPF alignment?
Step 6: Tighten to p=quarantine and p=reject
When all legitimate sources are correctly configured, move to `p=quarantine`:v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-failures@example.com; fo=1Failing messages now end up in the spam folder instead of the inbox. Leave this in place for a few more weeks and check whether complaints come in about missed messages.
The final step is `p=reject`:
v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-failures@example.com; fo=1Failing messages are now fully rejected. This step is irreversible in practice: a system you overlooked immediately loses its ability to deliver mail. The switch to `p=reject` may only happen after you have seen in the reports for weeks that only unauthorized sources are failing.
Verification
Check your records with `dig`:dig TXT example.com
dig TXT default._domainkey.example.com
dig TXT _dmarc.example.comThen send a test message to an address you created at Google and Yahoo and examine the headers:
grep -E "spf|dkim|dmarc" /path/to/raw-message.txt
You are looking for `spf=pass`, `dkim=pass` and `dmarc=pass`. Any other outcome means one of the steps was not performed correctly.
Common mistakes
Multiple SPF records. DNS allows only one SPF record per domain. Multiple records cause the check to fail. Combine everything into one TXT record.SPF lookup limit exceeded. Each `include` counts toward the limit of 10 lookups. Check with:
dig TXT example.com | grep -o "include:" | wc -l
Stay below the limit, otherwise SPF fails structurally.
DKIM only on marketing mail. Transactional messages without a DKIM signature fail DMARC as soon as you move to `p=reject`. Sign all outgoing mail, not just campaigns.
What it depends on
The three protocols each do something different. SPF checks which server is allowed to send, DKIM whether the content was altered along the way, and DMARC determines what happens if either fails. It is a chain: remove one link and the rest means less.The biggest mistake is haste. Anyone who goes from nothing to `p=reject` in one night will discover within a week which third party was still secretly sending on behalf of the domain. The phased approach — `none`, then `quarantine`, then `reject` — exists for a reason. The reports in the `none` phase are half the work; skipping them means configuring blind.
Providers are making requirements increasingly strict. What applied in 2024 to bulk senders to Google and Yahoo is becoming the norm for everyone. Those who set up the protocols now will already have the reports in place before the next requirement arrives. Those who wait until things go wrong have no reports — only an empty inbox.