A DMARC record at p=none is monitoring mode only — it generates aggregate reports but does not instruct receiving mail servers to reject or quarantine spoofed email. Attackers can send phishing email appearing to come from your domain and it will land in inboxes unchallenged. RFC7489 requires p=quarantine or p=reject before DMARC provides any actual protection. Google's bulk sender guidelines for 2024 mandate DMARC enforcement for domains sending more than 5,000 messages per day; senders without enforcement face increasingly aggressive filtering at Gmail.
Critical because `p=none` provides zero spoofing protection — your domain can be impersonated in phishing campaigns with no technical barrier, and Gmail's bulk sender requirements mandate enforcement-level DMARC for high-volume senders.
Publish a DMARC record at _dmarc.yourdomain.com with p=quarantine or p=reject. Graduate from p=none only after reviewing aggregate reports to confirm SPF and DKIM are passing. Add programmatic validation to your health check or CI pipeline:
export async function validateDmarcRecord(sendingDomain: string): Promise<void> {
const records = await dns.resolveTxt(`_dmarc.${sendingDomain}`)
const rec = records.flat().find(r => r.startsWith('v=DMARC1'))
if (!rec) throw new Error(`No DMARC record at _dmarc.${sendingDomain}`)
if (rec.includes('p=none')) {
throw new Error(`DMARC for ${sendingDomain} is monitor-only — not enforcing`)
}
}
A production-ready record: v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourdomain.com; pct=100; adkim=s; aspf=s. Include both rua (aggregate) and ruf (forensic) reporting addresses and track these in infrastructure-as-code.
ID: deliverability-engineering.dns-auth.dmarc-policy
Severity: critical
What to look for: Count all DMARC record definitions found in the codebase, infrastructure-as-code, DNS configuration scripts, or documentation. Look for v=DMARC1 strings. Check the p= tag value — acceptable values are quarantine or reject. A p=none policy means DMARC is in monitor-only mode and provides no protection. Also check for DNS validation code that verifies the DMARC record is published. Check if the DMARC RUA (reporting URI) is configured to receive aggregate reports.
Pass criteria: At least 1 DMARC record specifies p=quarantine or p=reject for production sending domains. A p=none policy does not count as pass. The record includes an rua= tag pointing to an address for aggregate reports. The policy is version-controlled or validated programmatically.
Fail criteria: DMARC record specifies p=none, no DMARC record is defined, or no mechanism validates that DMARC is published correctly for production domains.
Skip (N/A) when: The project does not send email.
Detail on fail: Describe the gap. Example: "DMARC policy is 'p=none' — email is not protected against spoofing, only monitored" or "No DMARC record defined or validated in codebase or infrastructure-as-code"
Remediation: Publish a DMARC record at _dmarc.yourdomain.com:
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@yourdomain.com; ruf=mailto:dmarc-forensic@yourdomain.com; pct=100; adkim=s; aspf=s
Graduate from p=none → p=quarantine → p=reject only after monitoring aggregate reports to confirm SPF and DKIM alignment. Validate DMARC publication programmatically:
export async function validateDmarcRecord(sendingDomain: string): Promise<void> {
const dmarcDomain = `_dmarc.${sendingDomain}`
const records = await dns.resolveTxt(dmarcDomain)
const dmarcRecord = records.flat().find(r => r.startsWith('v=DMARC1'))
if (!dmarcRecord) {
throw new Error(`No DMARC record found at ${dmarcDomain}`)
}
if (dmarcRecord.includes('p=none')) {
console.warn(`DMARC for ${sendingDomain} is in monitor-only mode (p=none) — not enforcing`)
}
}