Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

An SPF, DKIM and DMARC audit as one API call

Mail that lands in spam is often a DNS problem: a missing DMARC record, an SPF record that uses too many lookups, no DKIM key. Checking all of that by hand with dig gets old fast. Here is the curl version, using the rea

Mail that lands in spam is often a DNS problem: a missing DMARC record, an SPF record that uses too many lookups, no DKIM key. Checking all of that by hand with dig gets old fast.

Here is the curl version, using the real gateway path:

curl --request GET \
  --url 'https://email-dns-health-spf-dkim-dmarc.p.rapidapi.com/v1/email-dns?domain=google.com' \
  --header 'x-rapidapi-host: email-dns-health-spf-dkim-dmarc.p.rapidapi.com' \
  --header 'x-rapidapi-key: YOUR_RAPIDAPI_KEY'

This endpoint does the lookups for a domain and returns MX, SPF, DMARC, DKIM, an overall grade and a list of issues ranked by severity. No mail is sent. Real capture for google.com:

{
  "domain": "google.com",
  "grade": "good",
  "mx": [
    {
      "host": "smtp.google.com",
      "priority": 10
    }
  ],
  "null_mx": false,
  "spf": {
    "present": true,
    "record": "v=spf1 include:_spf.google.com ~all",
    "multiple_records": false,
    "all": "softfail",
    "includes": [
      "_spf.google.com"
    ],
    "dns_lookups": 1
  },
  "dmarc": {
    "present": true,
    "record": "v=DMARC1; p=reject; rua=mailto:[email protected]",
    "policy": "reject",
    "subdomain_policy": null,
    "percent": 100,
    "aggregate_reports": [
      "mailto:[email protected]"
    ],
    "forensic_reports": [],
    "dkim_alignment": "r",
    "spf_alignment": "r"
  },
  "dkim": {
    "selectors_found": [],
    "checked": [
      "default",
      "google",
      "selector1",
      "selector2",
      "k1",
      "k2",
      "s1",
      "s2",
      "mail",
      "dkim",
      "mandrill",
      "smtp",
      "zoho",
      "mxvault"
    ]
  },
  "issues": [
    {
      "severity": "low",
      "message": "No DKIM key found on common selectors. This is not proof DKIM is missing: your provider may use a custom selector."
    }
  ],
  "meta": {
    "user": null
  }
}

(Trimmed: the mta_sts, tls_rpt and bimi fields are cut.)

The grade is good, fair or poor, and each entry in issues has a severity of high, medium, low or info. In the capture, SPF is present with a softfail all, DMARC has policy: reject, and the only issue is the low-severity DKIM note. The SPF object includes dns_lookups, which matters because SPF allows at most 10 lookups, and the code raises a high-severity issue when a record needs more. That check alone catches a classic silent failure. Run it before a campaign, or in a cron job across the domains you send from.

Limits worth knowing

  • DKIM is checked on a fixed list of common selectors only (see dkim.checked). As the issue message says, finding none is not proof DKIM is missing: google.com above shows selectors_found: [].
  • Everything comes from DNS, so it reports what is published, not whether your mail actually passes at a receiver.
  • If the DNS lookup itself fails you get a 502 ("DNS lookup failed. Try again later."); a missing or invalid domain is a 400.

Print the grade and any issues:

const res = await fetch(
  'https://email-dns-health-spf-dkim-dmarc.p.rapidapi.com/v1/email-dns?domain=google.com',
  {
    headers: {
      'x-rapidapi-host': 'email-dns-health-spf-dkim-dmarc.p.rapidapi.com',
      'x-rapidapi-key': process.env.RAPIDAPI_KEY,
    },
  }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data.grade);
for (const i of data.issues) console.log(i.severity, i.message);

Listing and playground: https://rapidapi.com/samaanmohammed/api/email-dns-health-spf-dkim-dmarc

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.