15 April 2026 · 11 min read
If a receiver looks up your DMARC policy and finds two TXT records at _dmarc.yourdomain.com, it does not pick the stricter one, the newer one or the first one. It throws both away and treats your domain as having no DMARC policy at all. Every bit of work you did to get from p=none to p=quarantine or p=reject is silently undone, and you will not see an error message anywhere. Your mail keeps flowing, your dashboards look fine, and your domain quietly becomes spoofable again.
This is one of the most damaging configuration mistakes in email authentication precisely because it is invisible. A broken DMARC record fails loudly: validators flag it, aggregate reports stop arriving, you notice. Two valid DMARC records fail quietly. This article explains exactly why the standard mandates this behaviour, the specific ways a second record sneaks into a zone, how to detect the problem, and how to consolidate down to a single authoritative record without losing any of your settings.
The rule: exactly one DMARC record, or none
DMARC is defined in RFC 7489. The relevant text is in the section on record discovery, and it is unusually blunt for an RFC. When a receiver queries _dmarc.<domain> for TXT records, it must discard any record that does not begin with v=DMARC1, and then:
Records that do not start with a "v=" tag that identifies the current version of DMARC are discarded... If the remaining set contains multiple records, or no records, processing is aborted and the Mail Receiver takes no DMARC-related action.
Read that last clause carefully. "Multiple records" and "no records" are placed in the same sentence and trigger the same outcome: no DMARC action. So two perfectly valid, well-formed DMARC records produce exactly the same result as having no record whatsoever. The receiver cannot resolve the ambiguity, so it refuses to guess.
This is deliberate. The designers of DMARC decided that an ambiguous policy is more dangerous than no policy, because a domain owner who thinks they are at p=reject will not be watching for spoofing. Rather than apply one record arbitrarily and give a false sense of security, the standard forces the receiver to do nothing. The fix has to come from you, in DNS.
A few important clarifications about what "multiple records" actually means here, because the nuance is where people get caught out:
- The count is of TXT records that begin with
v=DMARC1at the exact name_dmarc.<domain>. Other TXT records at that name (for example a stray verification token someone parked there) are discarded first and do not count towards the total. - It applies per name. A DMARC record at
_dmarc.example.comand a separate one at_dmarc.mail.example.comare not duplicates. They are the org-level policy and a subdomain policy, which is completely legitimate. The conflict only exists when twov=DMARC1records sit at the same name. - A single TXT record that has been split into multiple character-strings inside one set of quotes (because it exceeds 255 characters) is still one record. That is fine. DMARC records are short enough that this is rare, but it is worth knowing it is not the same failure.
What a correct single record looks like
For reference, here is what the receiver wants to find: one TXT record, at _dmarc.yourdomain.com, holding a single DMARC policy string.
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=reject; rua=mailto:reports@yourdomain.com; ruf=mailto:forensics@yourdomain.com; adkim=s; aspf=s; pct=100"
That is the entire policy. Everything you want DMARC to do, the enforcement level, where reports go, how strictly alignment is checked, lives inside that one quoted string. There is never a reason to publish a second v=DMARC1 record to "add" more settings. You edit the existing string instead. This is the single most useful mental model for avoiding the problem: the DMARC record is one field you edit, not a list you append to.
If you want to see your current record exactly as a receiver parses it, run your domain through the DMARC checker. It will tell you how many v=DMARC1 records it found, which is the fastest way to confirm or rule out a duplicate.
How a second DMARC record actually gets into your zone
Nobody sets out to publish two DMARC policies. Duplicates arrive through a handful of recurring, very human routes. Recognising which one happened to you usually points straight at the fix.
1. The onboarding-tool overlap
You sign up for a DMARC monitoring or reporting service. Its setup wizard tells you to "add this DMARC record" and gives you a value with its own rua address baked in. You paste it. But you already had a DMARC record from an earlier attempt, or from a different vendor you trialled last year, or from your email provider's setup checklist. Now there are two. This is by far the most common cause, and it is made worse by the fact that many vendors say "add" when they mean "replace".
2. The DNS interface that appends instead of replaces
Some DNS panels treat TXT records as an additive set. You think you are editing the DMARC record, but the interface creates a new entry alongside the old one, especially if the name field is left as @ or the host is entered inconsistently (for example _dmarc in one entry and _dmarc.yourdomain.com in another, which some panels store as distinct names that nonetheless resolve to the same place). You save, the panel shows a tidy new record, and the old one is still sitting there a few rows up.
3. Apex versus subdomain confusion at the registrar
Registrar UIs differ wildly in how they expect the host portion. Enter _dmarc when the panel auto-appends the domain and you get _dmarc.yourdomain.com, which is right. Enter _dmarc.yourdomain.com into the same auto-appending field and you get _dmarc.yourdomain.com.yourdomain.com, which is wrong but harmless (no receiver queries it). The dangerous variant is entering the host two different ways across two attempts so both land on the real name. You end up with two records at the genuine _dmarc name.
4. Migration leftovers
You move DNS hosting from one provider to another. The zone import brings across the old DMARC record. Then you, or your new provider's onboarding flow, add a fresh one. Both survive the migration. The same thing happens when a managed email platform "helpfully" writes a DMARC record into a delegated zone while you have already written your own.
5. Copy-paste with a trailing newline or split string
Occasionally a paste introduces a line break in the middle of the value, and a panel interprets the two halves as two records, or as one record plus orphaned text. This is rarer but does happen, particularly when copying from documentation that wraps the record across lines.
How to detect a duplicate before it bites you
You cannot rely on your mail still working, because broken DMARC does not stop mail. You have to look at the DNS directly. There are three reliable ways.
Query DNS yourself. From a terminal, ask specifically for the TXT records at the DMARC name:
dig +short TXT _dmarc.yourdomain.com
If you see more than one line beginning with "v=DMARC1, you have a duplicate. On Windows use nslookup -type=TXT _dmarc.yourdomain.com. Count the v=DMARC1 strings, not the total number of lines, because a single long record can wrap.
Use a validator that counts records. The DMARC checker reports the number of DMARC records it found and warns explicitly when there is more than one. Because it queries authoritative DNS the same way a receiver does, it sees exactly what Gmail, Microsoft and Yahoo see. The general-purpose TXT record checker and DNS record checker are useful companions when you want to see every TXT record sitting at _dmarc, including the non-DMARC strays that are cluttering the name.
Watch your aggregate reports. This is the indirect tell. If you genuinely had an enforcing policy and reports flowing into your DMARC report analyzer, and then the reports dry up across all reporting sources at once, a duplicated or invalidated DMARC record is a prime suspect. Receivers that find two records take no DMARC action, and no DMARC action means no aggregate report is generated for your domain.
One subtlety: DNS caching. If you just added or removed a record, what dig returns can lag behind reality by the length of the record's TTL. Query an authoritative nameserver directly, or wait out the TTL, before concluding the duplicate is gone. A propagation check across multiple resolvers helps here.
Consolidating to one record, step by step
The goal is a single v=DMARC1 record that carries every setting you actually want. Do not delete first and rebuild from memory, because you will lose the reporting addresses and policy tuning you painstakingly set up. Merge, then prune.
Step 1: Capture both records exactly
List everything at the name so you can see both strings in full:
dig +short TXT _dmarc.yourdomain.com
You might see something like:
"v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"
"v=DMARC1; p=none; rua=mailto:reports@vendor-xyz.com; pct=100"
Two records. One is your real enforcing policy with strict alignment. The other is a vendor's p=none monitoring record with a different rua. Right now, because both exist, receivers ignore both and your domain has no effective policy. That second record did not soften your policy to none; it nullified it entirely.
Step 2: Decide on the one true policy
Pick the enforcement level you actually want. If you have been running at p=reject and it was working before the duplicate appeared, keep p=reject. If you are mid-rollout, choose where you legitimately are in the journey. Do not let the accidental presence of a p=none vendor record talk you into downgrading. For a refresher on choosing the right level and the safe order to escalate, see the DMARC requirements explainer.
Step 3: Merge the reporting addresses
This is the one part of two records you usually do want to keep from both. DMARC lets you send aggregate reports to several destinations by comma-separating the rua URIs. So if your own analyser and a vendor both need the data, combine them:
v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com,mailto:reports@vendor-xyz.com; adkim=s; aspf=s; pct=100
A caveat that trips people up: if a report destination is on a different domain from the one publishing the policy (here, vendor-xyz.com differs from yourdomain.com), that external destination must publish an authorisation record of its own, at yourdomain.com._report._dmarc.vendor-xyz.com, or many receivers will refuse to send it your reports. Reputable vendors set this up for you. It is worth knowing it exists, because a report address that silently receives nothing is often an external-destination authorisation that was never published, not a duplicate record.
Step 4: Build the single merged record
Fold every tag you care about into one string. A clean, strict, enforcing record might read:
v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc@yourdomain.com,mailto:reports@vendor-xyz.com; ruf=mailto:forensics@yourdomain.com; adkim=s; aspf=s; fo=1; pct=100
If you are not certain you have every tag right, generate the record from your chosen settings with the DMARC generator and compare it against what you assembled by hand. The generator will not produce a duplicate; it produces one correct string for you to publish.
Step 5: Delete every DMARC record at the name, then add exactly one
In your DNS panel, find the _dmarc host. Delete all TXT records at that name that begin with v=DMARC1. Then add your single merged record. Do not edit one and leave the other; explicitly remove both and create one fresh entry, because in-place editing is exactly how some panels left you with two records in the first place.
While you are there, clear out any non-DMARC junk parked at _dmarc, such as an old verification token that no longer means anything. It does not cause the multiple-record failure, but it is clutter at a name that should hold one thing only.
Step 6: Verify against authoritative DNS
After the TTL has elapsed, query again:
dig +short TXT _dmarc.yourdomain.com
You want to see exactly one line, your merged record, and nothing else. Re-run the DMARC checker to confirm it reports a single record and parses your policy as intended. Then watch for aggregate reports to resume over the following day or two; their return is the proof that receivers are once again taking DMARC action on your domain.
Edge cases worth understanding
Subdomains are not duplicates. As noted earlier, a policy at _dmarc.yourdomain.com and one at _dmarc.shop.yourdomain.com coexist happily. The org-level record can even steer subdomain behaviour with the sp tag, so in many cases you do not need a per-subdomain record at all. Add one only when a subdomain genuinely needs a different policy.
CNAME at _dmarc can hide a second record. Some managed setups point _dmarc at a vendor-hosted record via CNAME. That is a valid pattern, but a name cannot hold both a CNAME and a local TXT record. If you have a CNAME at _dmarc and also tried to add your own TXT there, the zone is malformed. Resolve to one approach: either delegate via CNAME and let the vendor host the single record, or host the TXT yourself and drop the CNAME.
Wildcards do not create DMARC records. A * TXT wildcard in your zone does not apply at _dmarc, because DMARC lookups are for an explicit name. So a wildcard will not accidentally manufacture a duplicate, but it also will not give you a policy. You need the explicit _dmarc record.
Two records that look different still both lose. It does not matter that one says p=reject and the other says p=none. The receiver does not compare them and pick a winner. The presence of two valid records, regardless of content, aborts DMARC processing. There is no "stricter wins" rule.
The practical takeaway
One name, one DMARC record. Treat the record at _dmarc.<yourdomain> as a single field you edit in place, never a list you append to. When you onboard a new reporting vendor, add their rua to your existing record rather than publishing theirs alongside yours. When you migrate DNS, check the imported zone for a leftover DMARC record before you add a fresh one. And whenever anything in your authentication setup changes, query the name directly and count the v=DMARC1 strings; one is correct, two is the same as zero.
Because this failure is silent, the only durable defence is to keep watching the record rather than checking it once. Run your domain through the DMARC checker now to confirm you publish exactly one record, and if you want to be told the moment a second record reappears or your policy changes, point continuous monitoring at the domain with DMARC Engine monitoring. If you would rather not manage the consolidation and the ongoing watch yourself, our done-for-you DMARC service keeps a single, correct, enforcing record in place and alerts on any drift, so a stray duplicate never gets the chance to quietly switch your protection off.