domain-health · v1.0.0 · 2026-09-22 · sha256 158d46c26e2d3fa4
domain-health v1.0.0A
Immutable. This exact content never changes and is served at /api/v1/blob/158d46c26e2d3fa4.
--- name: domain-health description: When the user wants to check email deliverability posture, domain authentication, or sending reputation for a domain. Use when the user mentions "domain health," "inbox health," "deliverability," "SPF," "DKIM," "DMARC," "email authentication," "are my emails landing in spam," "can I send from this domain," "is my domain spoofable," "warm up a domain," "check this sending domain," "DMARC rollout," "p=quarantine," "p=reject," "blacklisted," or "email going to spam." Also use before starting cold outbound from any domain, and to score prospect domains for deliverability gaps worth opening a cold email with. For writing the outbound emails themselves, see cold-email. For building the prospect list, see clay-gtm-outbound. metadata: version: 1.0.0 --- # Domain Health Email authentication and deliverability posture for any domain, using only `dig` and the standard library. No API key, no paid tool, no per-check cost. The same DNS primitives serve two opposite jobs, which is why they live in one skill: **Defensive.** Audit a domain you own before you send from it, and before you tighten a DMARC policy. Getting this wrong silently sends your own invoices and password resets to spam. **Offensive.** Score a prospect's domain to find a real, specific gap worth opening a cold email with. ## When to run it Before starting outbound from any domain. Before changing a DMARC policy. When email is landing in spam and nobody knows why. When enriching a prospect list with a technical hook. After adding any new sending tool, because that is when sender inventory drifts. ## Modes **Audit** (default) runs against domains you own. ```bash python3 scripts/domain_health.py --domain example.com python3 scripts/domain_health.py --domain example.com --json python3 scripts/domain_health.py domains.txt ``` **Prospect** produces a CSV for list enrichment, with a `gap` column that is true when the domain's DMARC is missing or monitoring-only. ```bash python3 scripts/domain_health.py --mode prospect domains.txt > signals.csv ``` **Blacklist** is opt-in via `--blacklist`. See the warning below before using it. **Mailbox verification** is separate, in `scripts/verify_email.py`. It does MX plus an SMTP probe for a single address. Most networks block outbound port 25, in which case it returns `unknown` rather than guessing. ## What it checks **MX**, establishing who receives mail for the domain. **SPF**, including whether more than one record exists (which is a PermError and means SPF fails entirely), the qualifier the record ends in, and the count of DNS-lookup-triggering mechanisms against the limit of ten. Exceeding ten is a common and invisible failure. **DKIM**, by sweeping a maintained list of per-provider selectors in `scripts/selectors.json`. **DMARC**, covering policy, the separate subdomain policy, percentage, reporting addresses, and whether those reports go somewhere a human will actually read. **Sender inventory**, which is the check that matters most and the reason this skill exists. It reads apex verification tokens and sending-subdomain CNAMEs to infer which providers are attached to the domain, then cross-checks each against SPF. This catches a provider verified two years ago, still able to send, never added to SPF, and invisible until the day the policy tightens. **Maturity signals**, meaning MTA-STS, TLS-RPT and BIMI. ## Honesty constraints These are load-bearing. Do not relax them, and do not let output phrasing drift past them. **DKIM absence is never claimed.** Selectors are arbitrary strings and some providers use per-account random ones that cannot be guessed. A sweep that finds nothing means "no key on the selectors tried." **Verification tokens prove a relationship, not sending.** A token proves the domain was verified with a provider at some point. Treat every inferred sender as a lead to confirm, never a fact. The tool separates mail-relevant signals from non-mail ones (site verification, custom web domains) precisely so the gap list stays worth reading. **A prospect's primary domain is a proxy.** Teams running cold outbound properly send from a separate domain to protect the primary. Never state a finding about a prospect's primary domain as a confirmed claim about their outbound. **Blacklist results describe the provider.** For any domain on hosted email, the MX addresses belong to the provider, so a listing reflects their shared infrastructure, not this domain's reputation. This is why the check is gated behind a flag and labelled in the output. Do not report it as the domain's own reputation. ## The DMARC rollout Never raise a DMARC policy without first completing a sender inventory and reading real aggregate reports. The staged sequence, including how to make reports readable and what to fix before each step, is in `references/dmarc-rollout.md`. The short version: make reports readable, wait and read them, fix every legitimate sender that is failing, then tighten policy one step at a time. The cost of waiting a month is zero. The cost of guessing wrong is business mail silently going to spam. ## Remediation Per-provider fixes for each failure mode, covering the records to add and where to find them in each provider's dashboard, are in `references/remediation.md`. ## Turning gaps into outbound How to convert a prospect's missing or monitoring-only DMARC into a specific, non-generic cold email opener, and the framing rules that keep it honest, are in `references/prospect-scoring.md`. ## Scoring The audit returns a 0 to 100 readiness score weighted toward what actually blocks a rollout. Treat it as a triage signal for comparing domains, not a precise measurement. The numbered findings beneath it are the real output. ## Related skills `cold-email` for writing the outbound itself. `clay-gtm-outbound` for building and enriching the prospect list. `seo-audit` for the equivalent audit on the web side.