← back to /blog← powrót do /blog

→ czytaj po polsku

mailops: SPF, DKIM, DMARC and the rest of mail, from one terminal

Email breaks quietly. SPF still resolves, but you crossed the ten-lookup limit last week. DKIM is fine on the old selector and missing on the new one. DMARC says p=reject, except half your senders were never aligned. MTA-STS is published — but the policy doesn't actually cover the MX host you migrated to. None of it throws an error. Mail just starts landing in spam, and you find out from a customer.

So I built mailops — a small Go CLI that checks the whole mail posture of a domain in one pass, from the terminal or CI.

What it does

One subcommand, mailops check example.com, and it looks at:

  • SPF — presence, multiple records, the all policy, and an estimated DNS-lookup count after include / redirect expansion, so you see the ten-lookup limit coming.
  • DKIM — selector discovery across common and provider selectors, plus public-key parsing and key size.
  • DMARC — policy, pct, report destinations, and external-report authorization hints.
  • MTA-STS & TLS-RPT — the TXT record, the HTTPS policy file, and whether your real MX hosts are actually covered by the policy mx: patterns.
  • BIMI — record syntax, the SVG logo and VMC authority-evidence URIs, and DMARC-enforcement compatibility.
  • Reputation — DNSBL checks for MX IPs out of the box, plus optional domain DBL / SURBL / URIBL zones.

With --smtp it goes active: connect to the MX or submission hosts, read the banner, EHLO, STARTTLS on 25/587, implicit TLS on 465, check the negotiated TLS version and certificate expiry, list the advertised AUTH mechanisms, and run an unauthenticated open-relay RCPT probe that never sends DATA. --mda does the same posture check for IMAP/POP on 143/993/110/995 — availability and TLS only, no login, no mailbox reads.

Provider profiles

Most domains sit behind a known platform, so --profile google-workspace (or microsoft-365, amazonses, sendgrid, mailgun, postmark, zoho, …) pre-fills the right DKIM selectors and endpoints. Anything you pass explicitly wins over the profile.

In CI

Output is human-readable text by default, or --json / --yaml / --prom, and --otel-endpoint POSTs OTLP/HTTP metrics straight to a collector. Exit codes mean what they say — --fail-on warn and --strict decide exactly which findings break the build. Drop it in a scheduled job and you catch the broken SPF, the expiring MX cert, or a fresh DNSBL listing before your customers do.

Where it lives

— Paweł


← back to /blog← powrót do /blog

→ czytaj po polsku