DNS guide · mail policy and TLS
DNS and certificate checks are small enough for a shell script but subtle enough to cause outages when reduced to one boolean. These recipes show direct commands and a single-request API alternative. Run them against the exact hostname or domain your application uses, and record timestamps because DNS and certificates change.
PRACTICAL · COMMAND LINE READYQuery the domain’s TXT records for SPF and query `_dmarc.
dig +short TXT example.com | grep -i 'v=spf1'
dig +short TXT _dmarc.example.com | grep -i 'v=dmarc1'
# one JSON response
curl -sG https://dns.lifestep.io/domain --data name=example.com | jq '{spf:.spf_record,dmarc:.dmarc_record,has_spf,has_dmarc}'Why it works: SPF authorizes sending hosts, while DMARC applies alignment and tells receivers what to do when authentication fails. Multiple SPF TXT records are a configuration error, not two policies that combine. DMARC reporting and enforcement are separate decisions: a record with `p=none` is useful for observation but does not quarantine or reject spoofed mail. DNS TXT answers can be split into quoted chunks, so production parsers should join them according to DNS rules.
Use OpenSSL to perform a TLS handshake and print `notAfter`, or call the API and read its computed day count. Include `-servername` so virtual hosts return the certificate for the requested hostname.
host=example.com printf '' | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null | openssl x509 -noout -enddate # machine-readable days curl -sG https://dns.lifestep.io/domain --data name="$host" | jq -r .tls.days_until_expiry
Why it works: The certificate presented by a server depends on SNI, which is why `-servername` matters on shared infrastructure. `notAfter` is an expiry timestamp, not proof that the full chain, hostname policy, cipher configuration, or renewal automation is correct. In CI, parse a trusted date format and fail with a warning window—for example, 21 days—rather than waiting for the exact expiry moment.
Use the domain-info endpoint once and read all returned fields with `jq`. It combines common DNS records, SPF/DMARC presence, and TLS metadata in one JSON response.
curl -sG https://dns.lifestep.io/domain --data name=example.com | jq '{resolves,mx,ns,spf:.spf_record,dmarc:.dmarc_record,tls:.tls}'Why it works: A single HTTP request reduces shell orchestration and gives automation one response shape to log and validate. It is not the same as one DNS packet: the service performs several lookups and a TLS handshake on your behalf, so its result reflects the service’s resolver and network path. Use direct `dig` or a resolver you control when you need authoritative troubleshooting, and use the API for a compact health snapshot.
Make the command deterministic before putting it in automation. Pin the input hostname or filename, set a timeout, capture the exit status, and emit a concise error that a build log can explain. Treat an empty answer differently from a transport failure: an empty DNS record, a workbook with no matching package member, and an unavailable endpoint are different states. Test one known-good fixture and one deliberately bad fixture so a future dependency or API change cannot silently turn a failure into a pass. Prefer machine-readable JSON when an API provides it, but retain the original command for local diagnosis. If the result controls a user-facing decision, show the reason and a timestamp rather than only a green or red label. These habits keep a useful one-liner understandable when it becomes a scheduled check.