- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The hand-rolled DNS client only ever sent plain UDP queries with no EDNS0 OPT record, so resolvers replied within the classic 512-byte limit and silently truncated the TC-bit response instead of signaling the client to retry. Domains with many TXT records (SPF includes, verification TXTs, DKIM 2048-bit keys) lost records with no error, producing false negatives. - build_query() now appends an EDNS0 OPT RR advertising a 4096-byte UDP payload size. - parse_response() is factored out of dns_query() and reports the TC (truncated) flag. - dns_query() retries over TCP (length-prefixed) when the UDP reply comes back truncated, using the result only if it matches the original transaction ID. Verified against google.com: previously-cut-off TXT records (SPF, DMARC, ~17 verification/site-verification TXTs) now return in full. |
||
| LICENSE | ||
| mail_audit.py | ||
| README.md | ||
mail-security-auditor
A single-file, zero-dependency Python 3 tool that audits a domain's email authentication hygiene: SPF, DKIM, DMARC, and MX records.
No dnspython, no shelling out to dig/host — it implements a minimal raw
UDP DNS client (RFC 1035) in stdlib Python, so it runs anywhere Python 3 runs,
including locked-down CI runners and minimal containers.
Why this matters
Misconfigured or missing SPF/DKIM/DMARC is one of the most common — and most
overlooked — ways attackers spoof your domain for phishing. Most domains
either have no DMARC record at all, or ship one with p=none that provides
zero enforcement. This tool surfaces exactly what's wrong in under a second,
per domain, with no signup, no SaaS, no data leaving your machine (queries go
straight to public resolvers 1.1.1.1 / 8.8.8.8 / 9.9.9.9).
Usage
# Text report
python3 mail_audit.py example.com
# Multiple domains at once
python3 mail_audit.py example.com example.org example.net
# JSON output (for piping into other tooling / CI gating)
python3 mail_audit.py --json example.com
# HTML report (for sharing with non-technical stakeholders)
python3 mail_audit.py --html report.html example.com
# Try extra DKIM selectors beyond the built-in common list
python3 mail_audit.py --selectors myselector,anotherone example.com
Exit code is 1 if any audited domain has 3+ issues (useful for CI gating),
0 otherwise.
What it checks
- MX — records present and resolvable (no MX = can't receive mail, may be intentional)
- SPF — present, single record (RFC 7208 only allows one), not
+all(wide open), has a real-all/~allclosing mechanism, has at least one real authorization mechanism (include:/a/mx/ip4:/ip6:) - DMARC — present, policy strength (
nonevsquarantinevsreject),ruaaggregate-report address configured,pct=100 - DKIM — checks ~19 common selectors (Google Workspace, Microsoft 365,
Mailgun, SendGrid, Mandrill, ProtonMail, generic
default/selector1/s1, etc.) — a miss here only means the common selectors weren't found, not that DKIM is absent; check your provider's docs for the real selector name if so
Requirements
Python 3.7+, stdlib only. No pip install needed. Outbound UDP/53 to a public resolver (falls back through 1.1.1.1 → 8.8.8.8 → 9.9.9.9).
License
MIT — see LICENSE. Free to use. If it's useful to you and you want to
support future tools like it, pay-what-you-want:
https://buy.stripe.com/8x2dR9amdarB1j16xG1VK03
Built by Errant Solutions.