When an agent's mail lands in spam, authentication is the first thing to check, but it is not the only cause. SPF, DKIM and DMARC decide whether a receiver can confirm that mail using your domain really came from you. Content, sending history and complaint rates decide what happens after that. Gmail's sender guidelines make the baseline explicit: every sender to Gmail needs SPF or DKIM, and senders of more than 5,000 messages a day need SPF, DKIM and DMARC, with the From domain aligned to one of the first two.

The three mechanisms are easy to blur together because they are all TXT records in DNS. They check three different things.

SPF checks the envelope, not the From line

SPF (RFC 7208) lets a domain publish which servers may use it in the SMTP MAIL FROM command, the envelope sender that ends up in the Return-Path header. Receivers are also encouraged to check the HELO name. SPF does not look at the From header the reader sees, which is the most common misunderstanding about it.

example.com.  TXT  "v=spf1 include:_spf.google.com include:amazonses.com ~all"

The rules that break real records:

  • One record per domain. If a lookup finds two v=spf1 records, the result is permerror. Adding a new provider means editing the existing record, not publishing a second one.
  • Ten DNS-querying terms. include, a, mx, ptr, exists and redirect each count, including the ones nested inside the records you include. Exceeding ten is a permerror. ip4, ip6 and all do not count.
  • Two void lookups. The RFC recommends that verifiers stop with permerror after more than two lookups that return nothing, which is what a stale include for a provider you left turns into.

The ending decides what a non-matching server gets: ~all is a softfail, -all a fail. SPF also breaks on plain forwarding, because the forwarding server is not in your record.

DKIM signs the message

DKIM (RFC 6376) has the sending system sign selected headers and the body, and put the result in a DKIM-Signature header. Two tags in that header matter: d=, the signing domain, and s=, the selector. The receiver fetches the public key from <selector>._domainkey.<d> and checks the signature.

DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=mail2026; h=from:to:subject:date; ...
mail2026._domainkey.example.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBg..."

The selector is not optional. A key published at plain _domainkey.example.com is never looked up. Selectors let one domain hold several keys at once, one per sending service, which is how you rotate keys and add providers without coordinating a single shared key. A DKIM pass shows that the signed parts were not changed after signing and that the d= domain vouched for them. It survives forwarding as long as nobody rewrites the signed content.

DMARC ties both to the From domain

DMARC is the piece that looks at the address the reader sees. It was updated in May 2026: RFC 9989 is the new core specification and replaces RFC 7489, with aggregate and failure reporting split into RFC 9990 and RFC 9991. The core rule did not change. A message gets a DMARC pass when SPF or DKIM passes and the domain that passed is aligned with the From domain. In relaxed mode, the default, aligned means sharing the same organizational domain, so bounce.example.com aligns with example.com. In strict mode the two must be identical. The aspf and adkim tags choose the mode.

_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"

p is the policy you ask receivers to apply to failing mail: none, quarantine or reject. rua is where receivers send daily aggregate reports. Two changes in RFC 9989 are worth knowing if you copy older examples: the pct tag is gone because receivers applied it inconsistently, and a new t=y tag marks a policy as being in testing. A report address on a different domain from the one being reported on only works if that other domain publishes an authorization record for it, such as example.com._report._dmarc.reports.example.net.

A worked example: why DKIM usually carries DMARC

Say an agent sends as billing@agents.example.com through Amazon SES. By default, SES uses a subdomain of amazonses.com as the MAIL FROM domain. SPF is checked against that subdomain and passes, but amazonses.com is not aligned with agents.example.com, so SPF contributes nothing to DMARC. If SES signs with DKIM as d=agents.example.com, the DKIM pass is aligned and DMARC passes on that alone. The receiver's result looks roughly like this:

Authentication-Results: mx.receiver.example;
  spf=pass smtp.mailfrom=...amazonses.com;
  dkim=pass header.d=agents.example.com;
  dmarc=pass header.from=agents.example.com

This is why the DKIM records matter more than the SPF record for most sending services. To get SPF alignment as well, SES needs a custom MAIL FROM domain on your domain, with its own MX and SPF records.

What this means on Lumbox

On the shared trylumbox.com domain, there is nothing for you to publish. Lumbox runs that domain's DNS, and you share its sending reputation with everyone else on it.

On your own domain, POST /v1/domains returns every record to add: a lumbox-verify= TXT record that proves ownership, the MX records for receiving, an SPF record, a DKIM record, a suggested DMARC record, and, when Lumbox registers your domain with Amazon SES for sending, three DKIM CNAMEs ending in dkim.amazonses.com. Publish all of them exactly as returned. Those three CNAMEs are what let SES sign mail as your domain, which, per the example above, is what DMARC will lean on.

A few things specific to how this works today:

  • Merge the SPF include. The returned record is v=spf1 include:spf.lumbox.co ~all. If your domain already has SPF, add the include to that record instead of creating a second one. spf.lumbox.co itself contains include:amazonses.com, so it uses two of your ten lookups (checked on 2026-09-29).
  • ACTIVE is not the same as fully authenticated. POST /v1/domains/{id}/verify marks a domain ACTIVE once the verification TXT, an MX and the SPF include are present. It also reports dkim, dmarc and ses_verified, but does not wait for them. Check those fields before the agent starts sending.
  • Point DMARC reports at yourself. The suggested record sends aggregate reports to a Lumbox address. Those reports are how you find every service sending as your domain, so change rua to a mailbox on your own domain, which also avoids the cross-domain authorization requirement above.
  • Your own provider means its records. If you configure your own outbound service for the domain, mail is authenticated by that provider's SPF include and DKIM keys, and you publish those instead.

Rolling out a policy

Start at p=none. It changes nothing about delivery and gets the reports flowing. Read them for a few weeks and list every source sending as your domain: the agent, your helpdesk, your billing system, the CRM someone connected last year. Fix each one's DKIM until it passes aligned, then move to quarantine, and later reject. Put agent traffic on a subdomain such as agents.example.com and you can run that subdomain's policy on its own schedule without touching the main domain's mail.

To check a single message, send one to a Gmail account you control, open it, and use "Show original". The top of that page shows the SPF, DKIM and DMARC results, and the headers show which domains they were evaluated for.

Passing all three says the message is authorized to use your domain. RFC 9989 is explicit that a DMARC pass carries no judgment about the message itself, so content and complaint rates still decide the inbox. The spam checklist covers those, the domain warm-up post covers the first weeks on a new domain, and the custom domain setup guide walks through adding the domain to Lumbox.