Email Security Inspector API

Base URL: https://email.netray.info

DNS-only email security posture analysis. Checks 12 categories — SPF, DKIM, DMARC, MTA-STS, TLS-RPT, DANE, DNSSEC, BIMI, FCrDNS, DNSBL, MX, and cross-validation — and streams results as Server-Sent Events with an aggregate A–F grade.

See also: interactive API reference (auto-generated OpenAPI)

Endpoints

GET /inspect/{domain}

Inspect a domain's email security configuration. Returns an SSE stream.

curl -N https://email.netray.info/inspect/example.com

POST /inspect

Same inspection via POST body. Omit dkim_selectors to use default provider-mapped selector lookup.

curl -N -X POST https://email.netray.info/inspect \
  -H 'Content-Type: application/json' \
  -d '{"domain": "example.com"}'

With explicit DKIM selectors:

curl -N -X POST https://email.netray.info/inspect \
  -H 'Content-Type: application/json' \
  -d '{"domain": "example.com", "dkim_selectors": ["selector1", "google"]}'

Response Format (SSE)

Results stream as Server-Sent Events. Each event has a data field containing a JSON object. Three event types arrive in sequence:

category events

One per check category (up to 11), streamed as each check completes:

data: {"type": "category", "name": "spf", "verdict": "pass", "checks": [
  {"name": "spf_record_exists", "status": "pass", "message": "SPF record found"},
  {"name": "spf_mechanism_count", "status": "pass", "message": "6 mechanisms (under limit of 10)"},
  ...
]}

cross_validation event

Arrives after all categories, containing cross-category consistency checks:

data: {"type": "cross_validation", "checks": [
  {"name": "dmarc_alignment", "status": "pass", "message": "DMARC alignment matches SPF and DKIM"},
  ...
]}

summary event

Final event with the aggregate grade:

data: {"type": "summary", "grade": "B", "categories": {
  "mx": "pass", "spf": "pass", "dkim": "warn", "dmarc": "pass",
  "mta_sts": "fail", "tls_rpt": "fail", "dane": "skip",
  "dnssec": "pass", "bimi": "skip", "fcrdns": "pass", "dnsbl": "pass"
}}

Check Categories

CategoryWhat It Checks
mxMX records exist and are valid hostnames
spfSPF record syntax, mechanism count, lookup limits
dkimDKIM key records for known and specified selectors
dmarcDMARC policy, alignment mode, reporting URIs
mta_stsMTA-STS DNS record and policy file
tls_rptTLS-RPT DNS record for SMTP TLS reporting
daneDANE/TLSA records for MX hosts
dnssecDNSSEC validation for the domain
bimiBIMI DNS record and logo URL
fcrdnsForward-confirmed reverse DNS for MX IPs
dnsblMX IPs checked against DNS blocklists
cross_validationCross-category consistency (DMARC alignment, etc.)

Grade Values

The aggregate grade reflects overall email security posture:

GradeMeaning
AExcellent — all critical checks pass
BGood — minor issues or missing optional records
CFair — some important checks warn or fail
DPoor — significant security gaps
FFailing — critical authentication missing

Useful One-Liners

# Stream all results (SSE)
curl -N https://email.netray.info/inspect/example.com

# Get just the summary grade (wait for stream to complete)
curl -N -s https://email.netray.info/inspect/example.com \
  | grep '"type":"summary"' | sed 's/^data: //' | jq '.grade'

# CI gate: check email security for a domain
curl -N -s https://email.netray.info/inspect/example.com \
  | grep '"type":"summary"' | sed 's/^data: //' \
  | jq -e '.grade == "A" or .grade == "B"'

Rate Limits

Per-IP GCRA rate limiting. Each inspection triggers multiple DNS lookups across all 12 check categories, so the effective cost per request is high.

When rate-limited, you receive a 429 response with a Retry-After header.

Errors

{
  "error": {
    "code": "bad_request",
    "message": "Missing required parameter: domain"
  }
}

Common error codes:

CodeMeaning
bad_requestMissing or invalid domain parameter
rate_limitedToo many requests; check Retry-After
internal_errorServer error; include X-Request-Id in reports