DMARC np= Explained: Policy for Subdomains That Don't Exist
The DMARC np tag sets the policy for subdomains of your domain that don't exist in DNS. If someone sends mail as ceo@payroll.example.com and payroll.example.com returns NXDOMAIN, receivers apply your np policy instead of sp or p. Legitimate mail almost never comes from a name that doesn't exist, so np=reject is one of the few DMARC changes you can make before your main domain is anywhere near enforcement.
What counts as a non-existent subdomain
RFC 9989 §4.7 defines np as the policy "for non-existent subdomains of the given Organizational Domain." The tag started life in RFC 9091 (the experimental PSD DMARC spec) and is now part of the core standard.
"Non-existent" has a precise meaning. §3.2.13 ties it to RFC 8020: "if the response code received for a query for a domain name is NXDOMAIN, then the domain name and any possible subdomains do not exist."
So the test is the DNS response code, not whether the name has an A or MX record. A few consequences:
- A name with any record exists. If
mail.example.comhas only a TXT record, a query for its A record returns NOERROR with no answers. That is not NXDOMAIN, sonpdoesn't apply. - Names with children exist. If you publish
s1._domainkey.news.example.com, thennews.example.comis an empty non-terminal. It returns NOERROR, not NXDOMAIN. - Wildcards make everything exist. With
*.example.comin your zone, every subdomain resolves, nothing returns NXDOMAIN, andnpnever fires. Yoursp(orp) covers all of it.
Precedence: np, sp, and p
np only matters when a receiver falls back to your Organizational Domain's record. If the From domain has its own _dmarc record, that record's p applies. A non-existent name can't have one.
When the policy comes from the Organizational Domain (or a public suffix domain) and the From domain is a subdomain, §4.10.1 decides: the policy "is taken from the "sp" tag (if any) if the Author Domain exists or the "np" tag (if any) if the Author Domain does not exist." The fallbacks are in §4.7: "If the "np" tag is absent, the policy specified by the "sp" tag (if the "sp" tag is present) or the policy specified by the "p" tag (if the "sp" tag is not present) MUST be applied for non-existent subdomains."
| From domain | Tags published | Policy applied |
|---|---|---|
example.com |
any | p |
app.example.com (exists) |
sp present |
sp |
app.example.com (exists) |
no sp |
p |
zzz.example.com (NXDOMAIN) |
np present |
np |
zzz.example.com (NXDOMAIN) |
no np, sp present |
sp |
zzz.example.com (NXDOMAIN) |
no np, no sp |
p |
The order is np, then sp, then p. If you set sp=none to protect a messy set of subdomains and skip np, non-existent subdomains inherit that none.
Why np=reject is a cheap win
Spoofing a subdomain is attractive because it looks plausible. security@alerts.example.com reads like something your company would send, and most domains at p=none do nothing to stop it.
np=reject closes that for every name that isn't in your zone, and it costs you almost nothing:
- It doesn't touch mail from
example.com. That still getsp. - It doesn't touch mail from any subdomain that exists. That still gets
sporp. - Subdomains you actually send from almost always exist. Setting one up with an ESP usually means publishing SPF, DKIM, or bounce records at or below that name.
That last point is where to check before you publish. Like p, np only applies to mail that fails DMARC, so aligned mail is unaffected. The one real risk is legitimate mail that uses a From subdomain with no DNS records at all and doesn't pass DMARC. Under p=none it's delivered today. With np=reject it gets rejected. Your aggregate reports show every From domain receivers saw. Resolve each subdomain in them before you add the tag.
A useful consequence: you can reject spoofed made-up subdomains while your real mail is still under p=none or p=quarantine. The work on the main domain (getting every sender aligned) takes weeks. This part doesn't have to wait for it.
Example records
Monitoring the main domain, rejecting made-up subdomains:
v=DMARC1; p=none; np=reject; rua=mailto:reports@example.com
Quarantine on real mail, reject on non-existent subdomains:
v=DMARC1; p=quarantine; np=reject; rua=mailto:reports@example.com
Loose policy on existing subdomains, strict on the rest:
v=DMARC1; p=reject; sp=none; np=reject; rua=mailto:reports@example.com
Here np=reject is doing real work. Without it, non-existent subdomains inherit sp=none.
Full enforcement:
v=DMARC1; p=reject; rua=mailto:reports@example.com
With no sp and no np, non-existent subdomains fall back to p=reject. Adding np=reject changes nothing at a DMARCbis receiver, though it documents intent.
Watch out for t=y
If you're using DMARCbis test mode during a rollout, it softens np too. RFC 9989 §4.7 says the t tag covers the policy "declared in the "p", "sp", and/or "np" tags." With p=none; np=reject; t=y, the p=none is untouched, but np=reject is treated as quarantine. See how t=y works for the full mapping.
Receivers that don't implement np
np is new to many receivers. A receiver still running RFC 7489 logic treats np as an unknown tag and ignores it (RFC 7489 §6.3). It then applies sp, or p if sp is absent, to all subdomains, existing or not.
That means np can't make anything worse at an older receiver. At worst it has no effect, and you get the same behavior as before you added it. At a DMARCbis receiver, it does exactly what you asked. RFC 9990 aggregate reports also include an np element in policy_published, so you can see which reporters picked it up.
Check your record
Run your domain through the DMARC record checker to see your current p, sp, and np, and what a spoofed non-existent subdomain would inherit.
