SETUP.md — Email Domain Setup Checker

From version 0.1.1 of Email Domain Setup Checker, shown publicly by its creator. 5.0 KiB · SHA-256 7cd365b62cdc192e10e8f2b85c5ef01afccbd8aadbd4d3ce5348e7635d270e37.

# Setup

## Requirements

- Python 3.10 or newer; standard library only.
- Permission to query public DNS through `dns.google` or `cloudflare-dns.com`, including recursive SPF include and redirect targets from DNS records that can be unrelated third-party domains; those target names are sent to the selected resolver.
- No account, API key, or configuration file.

Copy the complete package into an Agent Skills compatible harness, or run the script directly from the package directory. Consult the harness's documentation for its skill directory.

```bash
python3 scripts/email_domain_setup_checker.py --help
python3 scripts/email_domain_setup_checker.py check example.com
```

Replace `example.com` with the exact domain provided by the user. The domain is converted to an IDNA name and rejected if invalid. The default resolver is Google Public DNS. Set `--resolver cloudflare` for Cloudflare DNS. Add repeatable `--dkim-selector` options for known selectors. Add `--mta-sts` only when an HTTPS MTA-STS policy fetch is desired.

## Output and exit codes

The default report explains checks and severity in plain English. `--json` prints JSON with `domain`, `resolver`, `incomplete`, `skipped`, and `findings`. Status 2 takes precedence for incomplete reports unless `--allow-partial` is supplied. Otherwise status 3 means at least one error finding and status 0 means no error findings. A failed lookup, skipped SPF macro target, duplicate redirects or the 60-query ceiling makes the report incomplete. `--allow-partial` permits an incomplete result, which remains marked `incomplete` and lists skipped checks. Read that list before acting on findings. SPF output is a static lookup count following RFC 7208 processing order: include, a, mx, ptr, exists and redirect count recursively, terms after all are ignored, and redirect is ignored when all is present. The walker does not evaluate macros or match a sender IP, so it does not provide a definitive SPF pass/fail evaluation. Void lookups are not measured. Macro include/redirect targets are not followed: they produce a warning and mark the static count partial and the report incomplete. Duplicate redirect modifiers produce a warning citing RFC 7208 section 6; neither redirect is followed or counted, and the report is incomplete. An eleventh counted term stops further SPF lookups and produces a warning: "static lookup count is N, above the 10-lookup limit; evaluation can stop earlier for a matching sender". This warning alone does not cause exit 3. A present record can still be misconfigured or ineffective at receiving mail.

Invalid command-line input or fixture setup also exits 2. With `--allow-partial`, an incomplete report exits 3 if it contains error findings and 0 otherwise.

## Network access

DNS-over-HTTPS queries use exactly one selected host:

- `dns.google`: `https://dns.google/resolve?name=...&type=...` by default.
- `cloudflare-dns.com`: `https://cloudflare-dns.com/dns-query?name=...&type=...`, with `Accept: application/dns-json` when selected. Google requests omit this header.

Recursive SPF checks look up include and redirect targets named in DNS records, which can be unrelated third-party domains; those names are sent to the selected resolver.

With `--mta-sts`, the CLI additionally reads `https://mta-sts.<checked-domain>/.well-known/mta-sts.txt`. This destination is derived only from the validated domain argument. Every request and redirect must remain HTTPS and pass the destination host guard. No other remote hosts or telemetry are used.

Python urllib honors the user's `HTTPS_PROXY` or `https_proxy`, `NO_PROXY` or `no_proxy`, and macOS or Windows system proxy settings. A selected proxy can see the destination host name. TLS still terminates at the declared destination hosts and certificates are verified. The tool does not request plain HTTP.

## Test-only fixture transport

`EMAIL_DNS_FAKE_RESPONSES` points to a synthetic fixture file and `EMAIL_DNS_FAKE_TRANSPORT_TEST_ACK=1` acknowledges test mode. Both are required. Fake mode prints a warning to stderr and makes no network requests. A missing or mismatched fixture fails before any real request. Never set these variables for a live check. See [references/email-records.md](references/email-records.md) for fixture format.

Run local tests with:

```bash
python3 -m unittest discover -s tests -v
```

Tests use synthetic data and do not contact the listed hosts.

## Privacy and removal

The selected resolver sees the checked domain and query names. Recursive SPF checks look up include and redirect targets named in DNS records, which can be unrelated third-party domains; those names are sent to the selected resolver. The optional MTA-STS host sees the policy fetch. An agent harness may forward command output; share only what is needed. The tool writes no local result files. Remove the copied package to uninstall it.

Version 0.1.1. MIT license; see [LICENSE.txt](LICENSE.txt).

Google Public DNS is a Google service. Cloudflare is a trademark of Cloudflare. This product is independent and has no affiliation with either provider.

By Zero Width Lab (zerowidthlab.com)

License: MIT (read it).

MITMIT License

Copyright (c) 2026 Zero Width Lab

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Back to the listing