← back to /blog← powrót do /blog
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
allpolicy, and an estimated DNS-lookup count afterinclude/redirectexpansion, 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
- Landing: systeam.pl/mailops
- Source: github.com/systeampl/mailops, Apache 2.0
- Same family as dnsops and certops
- Issues and pull requests welcome
- Paweł