DMARC tells receiving servers what to do when a message claiming to be from your domain fails SPF and DKIM. For outbound, you publish one TXT record, read the reports, then tighten the policy. This guide shows the queries and the output, not the theory.
TL;DR
- Publish a
p=noneDMARC record on the domain you send from, with a reporting address. It takes about 30 minutes. - Read aggregate reports for 2 to 4 weeks, fix the senders that fail, then move to
p=quarantineandp=reject. - Pair it with a clean list. A verified-only LeadOcean pull of 25 contacts spends 25 records. The counting call spends none.
Prerequisites
- Access to DNS for your sending domain (Cloudflare, Route 53, your registrar).
- SPF and DKIM already published and passing. DMARC passes when either one passes and aligns with the From domain (RFC 7489, September 2026).
- A mailbox that can receive XML reports, or a free report parser.
digon your machine.- Optional: a LeadOcean key as
$LEADOCEAN_API_KEYfor the list-hygiene step. Get one free at app.leadocean.io.
Step 1: Check what your domain publishes today
Query the _dmarc label. Replace acme.com with your sending domain.
dig +short TXT _dmarc.acme.com
dig +short TXT acme.com | grep spf
dig +short TXT selector1._domainkey.acme.comAn empty answer on the first line means no DMARC record. Gmail requires SPF, DKIM and DMARC from bulk senders (5,000 or more messages a day). It may reject unauthenticated mail with a 5.7.26 error (Google, October 2026). Smaller cold senders should publish it anyway.
Step 2: Publish a monitoring record
Add one TXT record at _dmarc.acme.com. Start with p=none: it blocks nothing and starts the reports.
Host: _dmarc
Type: TXT
Value: v=DMARC1; p=none; rua=mailto:dmarc-reports@acme.com; adkim=r; aspf=r; pct=100What each tag does:
| Tag | Meaning |
|---|---|
p | Policy for failing mail: none, quarantine or reject |
rua | Where aggregate (daily XML) reports go |
adkim, aspf | r relaxed or s strict alignment |
pct | Share of failing mail the policy applies to |
sp | Policy for subdomains, if different |
Confirm it published:
dig +short TXT _dmarc.acme.comStep 3: Read the reports and fix failing senders
Aggregate reports arrive as zipped XML. Each <record> shows a sending IP, a count, and whether SPF and DKIM aligned.
<record>
<row>
<source_ip>203.0.113.25</source_ip>
<count>412</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers><header_from>acme.com</header_from></identifiers>
</record>Here SPF passes but DKIM fails for 412 messages. The usual causes for outbound: a sequencer sending without your DKIM key, or a new mailbox on a secondary domain with no record. Fix each IP until every legitimate source passes at least one aligned check.
Outbound tip: send from a secondary domain, not your main one. Publish DMARC on each sending domain, and keep the main domain on p=reject.
Step 4: Move to enforcement
Once the reports show only legitimate sources passing, tighten in stages. Wait a week between changes.
v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc-reports@acme.com
v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc-reports@acme.com
v=DMARC1; p=reject; rua=mailto:dmarc-reports@acme.comIf a legitimate sender starts landing in spam after a change, drop pct or go back one step. Read the reports again before you retry.
Step 5: Keep the list clean so the policy has a chance
DMARC proves who you are. It does not stop recipients from marking you as spam, and Google says frequent spam reports lower domain reputation over time (September 2026). Bounces from bad addresses hurt the same domain.
Size a verified-only audience first. A REST count with count=true in the query and limit 1 spends no records. The MCP tool leadocean_count_leads gives the same answer for free.
curl -s "https://api.leadocean.io/v1/people/search?count=true" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"emailStatus": ["verified"],
"limit": 1
}'Then pull a small first batch of 25 and send it from the new domain slowly:
curl -s https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["US"],
"emailStatus": ["verified"],
"limit": 25
}'That spends 25 records. A search status of verified is an upper bound, so confirm each address at enrichment. LeadOcean does not refund bounces, so read email_status before every send.
What you get
Step 1 on a domain with a policy returns the record as plain text. This is a sample, not a LeadOcean record.
"v=DMARC1; p=reject; rua=mailto:dmarc-reports@acme.com; adkim=r; aspf=r"The free count from leadocean_count_leads ran on 2026-10-21. Filters: jobLevel VP, jobFunction Sales & Business Development, country US, emailStatus verified only.
{
"total": 31141,
"totalIsExact": true,
"distinctCompanies": 18563,
"credits": 0
}That is a verified-only count, not the full mailable count. The default mailable count also includes catch-all addresses, so it is larger.
Response shape from the API reference (placeholder values), for the first search result:
{
"success": true,
"data": [
{
"profile_data": {
"profile_full_name": "Jane Doe",
"profile_headline": "VP Sales at Acme"
},
"contact_data": {
"has_email": true,
"email_status": "verified",
"email_type": "work",
"contact_current_experiences": [
{ "job_title": "VP Sales", "company_name": "Acme", "company_domain": "acme.com" }
]
},
"meta": { "source_ids": { "person_id": "1234567" }, "fetched_at": "2026-10-01" }
}
],
"meta": { "count": 1, "limit": 25, "credits": 1, "nextCursor": "..." }
}Troubleshooting
| Error | Cause | Fix |
|---|---|---|
dig returns nothing for _dmarc | Record at the wrong host, or DNS not propagated | Publish at _dmarc.acme.com, not the apex. Wait and retry |
| Gmail rejects with 5.7.26 | Message unauthenticated | Publish SPF, DKIM and DMARC and re-test |
| No reports arrive | rua address wrong or mailbox blocks attachments | Use a plain mailbox and check rua=mailto: spelling |
| 401 from LeadOcean | Missing or wrong x-api-key | Check $LEADOCEAN_API_KEY is exported |
| 429 from LeadOcean | Above the plan rate limit (5 a second on Free, 200 on Agency) | Slow down and honour Retry-After |
| 402 from LeadOcean | Free plan's 1,000 records spent | Counts stay free. Move to Solo at $97 a month. See pricing |
| Empty search results | Enum value spelled wrong, such as vp for jobLevel | Use VP, or check leadocean_list_enum_values |
FAQ
What DMARC policy should I use for cold email?
Start with p=none for 2 to 4 weeks. Move to quarantine, then reject, once reports show legitimate senders passing.
Does DMARC improve deliverability?
It proves your identity and is required by Gmail for bulk senders. It does not fix bad lists or spammy copy. See outbound email tools explained.
Do I need DMARC on every sending domain?
Yes. Each domain you send from needs its own record, including secondary domains.
How does list quality connect to DMARC?
Bounces and spam complaints hit the same domain reputation that DMARC protects. Filter to emailStatus: ["verified"] and see personalizing outbound emails. A worked drafting flow is in 5 unique personas.
Send to addresses that deserve your domain. Filter to verified emails.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →