DMARC Record Syntax Errors and How to Fix Them
Failures that cause receivers to ignore your record or apply the wrong policy
Critical
The DMARC record contains a syntax problem that causes receivers to ignore it or apply the wrong policy. The domain may appear protected while enforcement is silently broken.
A DMARC record can contain the v=DMARC1 string and still be broken in ways that make receivers ignore it entirely or apply a different policy than you intended. These failures are quiet: nothing bounces, no alert fires, and the record looks correct in a DNS lookup.
Some parsing background helps before the individual problems. A DMARC record is a TXT record at _dmarc under the domain, made up of tag and value pairs separated by semicolons, with surrounding whitespace ignored. Tag names are case insensitive. Unknown tags are ignored rather than treated as errors, which is a meaningful difference from SPF and shapes several of the cases below. Long records may be split into multiple strings inside the TXT record at the DNS layer, and receivers concatenate those before parsing, so a split record is not itself a problem as long as the pieces join cleanly.
Missing the required p tag
Severity: Critical. Receivers treat the record as no DMARC at all. The p tag is mandatory. A record such as v=DMARC1; rua=mailto:reports@example.com is syntactically incomplete, and receivers treat it as no DMARC record at all rather than defaulting to something sensible.
This one is easy to end up with. A common path is deploying the reporting address first with the intention of adding the policy once reports start arriving, except reports never arrive, because the record is invalid and no receiver is acting on it. The domain has published something that looks like DMARC and gets neither protection nor visibility.
Add a valid policy tag: p=none, p=quarantine, or p=reject. If you are at the start of a rollout, p=none is the correct value and gives you the reporting you were after. The specification also expects p to come directly after v, and while most receivers are lenient about tag order beyond the version, putting it second costs nothing.
More than one DMARC record
Severity: Critical. Policy discovery fails; receivers apply nothing. Only one DMARC record is permitted at _dmarc.example.com. When a receiver finds more than one TXT record containing v=DMARC1 at that name, policy discovery fails and no DMARC policy is applied at all. The result is not the stricter of the two, or the first one found. It is nothing.
This usually comes from process rather than misunderstanding. A migration adds a new record without removing the old one, or two teams manage DNS and each adds a record for their own tooling. It also happens when a DMARC vendor is onboarded and publishes a record with their own reporting address alongside the one already there.
Merge the two into a single record with the correct policy and any reporting addresses combined, then delete the extras and confirm exactly one TXT record remains at the _dmarc name. Note that other TXT records at that name which do not begin with v=DMARC1 are ignored and are not part of this problem.
Invalid policy value
Severity: Critical. Receivers cannot act on the policy and the record may be discarded. The p and sp tags accept only none, quarantine, and reject. A value like p=block, p=deny, or a typo such as p=rejct is not valid. Receivers cannot act on a policy they do not recognize, so they fall back to their own default handling rather than the enforcement you intended, and the record can look strict while doing nothing.
Correct the value to exactly none, quarantine, or reject. Publish it in lowercase. Receivers are generally tolerant of case here, but there is no reason to test that, and lowercase is what every reference and every tool expects to read back.
Version tag missing or in the wrong place
Severity: Critical. The record is not recognized as DMARC and is skipped entirely. Every DMARC record must begin with the version tag, and the value must be exactly v=DMARC1. Not DMARC, not DMARC1.0, not dmarc1. If the version tag is missing, misspelled, or preceded by another tag, the record is not recognized as DMARC and is skipped entirely.
Because the version string is checked precisely, this is one of the few places in DMARC where a small transcription error causes total failure rather than partial. It shows up most often when a record is copied out of documentation or a support ticket and picks up a stray character or a line break in the process.
Make sure the record starts with v=DMARC1 before any other tag, spelled and cased correctly, and verify what is actually published rather than what you pasted.
Invalid reporting address
Severity: Warning for a bad rua (aggregate reports); Info for a bad ruf (failure reports).
The rua tag sets where aggregate reports are sent, and ruf sets where failure reports go. Each accepts a comma separated list of URIs, and each URI must be a valid mailto: or https: target. A malformed address does not stop enforcement, so the policy keeps working while you receive nothing.
Two things catch people out here beyond simple typos.
The first is external destination verification. If you send reports to an address at a different domain, that domain has to authorize it. The receiving side must publish a TXT record at example.com._report._dmarc.processor.example containing v=DMARC1. Without it, conforming receivers will not send reports to that destination. Vendors normally tell you to publish this, but it gets missed, and the symptom is identical to a malformed address: silence.
The second is the optional size limit syntax. A rua value can carry a maximum report size, written as rua=mailto:dmarc@example.com!10m. This is valid, so a size limit set too low means receivers skip sending reports that exceed it.
rua vs ruf. Aggregate reports (rua) are the ones that matter. Failure reports (ruf) contain message level detail including recipient data, and most large receivers stopped sending them over privacy concerns, so a missing or broken ruf is close to normal and not worth chasing.
Unrecognized or misspelled tag
Severity: Info. The record still works, but the intended setting is silently not in effect.
Receivers ignore tags they do not recognize, which is by design and allows the specification to add tags without breaking existing records. It also means an unknown tag never produces an error anywhere.
That is exactly why it is worth flagging. A misspelled tag such as rus= instead of rua=, or adkm= instead of adkim=, is silently discarded, and the setting you meant to apply is simply not in effect. Nothing tells you. The record parses, the policy works, and the piece you thought you had configured is missing.
Check any unrecognized tag against the defined set: v, p, sp, pct, rua, ruf, adkim, aspf, fo, rf, and ri. In practice an unknown tag is nearly always a typo of one of these rather than something exotic.
A valid, minimal record
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"All other tags are optional and default to safe values. Start here and add tags only as you need them.
Related checks
References: RFC 7489 (DMARC) · Public Suffix List
