Looking for the overview — what this API returns, what it costs, and a call you can run without a key? See the Email Preflight API page →
Developer Tools

Email Preflight API & Scraper

The Email Preflight API returns pre-send QA for HTML email as clean JSON.

7 actionsLive JSON1,000 free credits$0.67–$1.50 / 1,000 creditsMCP-ready
Get a free keyOpen in playground

🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.

The primary audit_html endpoint returns HTML validity and warnings, message size with Gmail-clip risk and accessibility issues such as missing alt text — everything you would check before hitting send. You can also test CSS support across clients, compute a spam score, check links and images, verify DNS auth and render a basic preview. It is built for ESPs, marketing tools and QA pipelines that need to catch broken email before it ships. One ReefAPI key, one shared credit pool, the standard envelope.

Reference

Three email engines, three different questions

email-preflight, email-health and validate look adjacent and answer different things: the message, the sending domain, and one recipient address. The overlap is real and narrow, and it is worth knowing exactly where it is. Every figure below is from live calls made against the same test template, github.com and [email protected].

What you are askingEngine and actionMeasured
Is this HTML broken before I send itemail-preflight audit_html4 images, 3 missing alt, one table at width=700 flagged for mobile, one tracking pixel, score 74 grade C
Which CSS will break in Outlookemail-preflight css_supportposition, display:flex and border-radius all high_risk across 12 clients, from a bundled Can-I-Email snapshot v1.0.4 dated 2026-05-19
Does the copy read as spamemail-preflight spam_score7.3 verdict likely_spam over 7 rules; a plain rewrite of the same message scored 0.0 clean_signal
Do the links and images resolveemail-preflight check_links / check_images4 links: 1 ok, 1 broken (real 404), 2 unverifiable; 4 images: 3 missing alt, 1 over http, 2 without dimensions
Is my sending domain authenticated, fastemail-preflight dns_authgithub.com scored 90.0 grade A; returns 9 keys (domain, score, spf, dkim, dmarc, mx, summary, issues, source)
Is my sending domain authenticated, in fullemail-health checkidentical score object, 90.0 grade A, but 14 keys adding bimi, mta_sts, tls_rpt, dnssec, dane and the blacklist detail
Is this one address deliverablevalidate email[email protected] returned valid true, deliverable true, score 95, has_mx true and the MX exchange itself
What will it look likeemail-preflight preview_basicreturned available:false with reason "web-capture engine is not reachable for rendering"; the other actions are unaffected

dns_auth is a documented wrapper, not a second implementation: its own payload names source "email-health inner-call" and reused_engine "email-health". It drops the six standalone section objects but keeps their scores in score.breakdown (mx 20, spf 22, dmarc 22, dkim 16, blacklist 10, mta_sts 4, dnssec 3, tls_rpt 2, bimi 1, totalling 100) and their booleans in summary. Call dns_auth for a pre-send go/no-go, email-health when you need the records themselves.

Live example

Real request and response JSON

Captured from the indexed primary action, audit_html, on .

Captured request
{
  "method": "POST",
  "url": "https://api.reefapi.com/email-preflight/v1/audit_html",
  "headers": {
    "x-api-key": "$REEF_KEY",
    "content-type": "application/json"
  },
  "body": {
    "html": "<html><body><img src='https://x.test/a.png'><a href='https://x.test'>hi</a></body></html>"
  }
}
Captured response
{
  "ok": true,
  "meta": {
    "api": "email-preflight",
    "endpoint": "audit_html",
    "mode": "live",
    "latency_ms": 3.4,
    "record_count": 5,
    "bytes": 0,
    "cache_hit": false,
    "proxy_tier_note": "none"
  },
  "data": {
    "html_validity": {
      "parse_ok": true,
      "warnings": []
    },
    "size": {
      "bytes": 89,
      "gmail_clip_risk": false,
      "limit_bytes": 102000
    },
    "accessibility": {
      "images_total": 1,
      "missing_alt": 1,
      "missing_alt_srcs": [
        "https://x.test/a.png"
      ],
      "issues": [
        "1 image(s) without alt text",
        "no lang attribute on the document (screen-reader language hint)"
      ]
    },
    "structure": {
      "has_doctype": false,
      "has_table_layout": false,
      "uses_div_layout": false,
      "heading_count": 0,
      "script_tags": 0,
      "link_count": 1,
      "image_count": 1
    },
    "mobile_width_risks": [
      "[redacted-phone]"
    ],
    "dark_mode": {
      "has_meta_color_scheme": false,
      "hints": [
        "no <meta name=color-scheme> — clients may auto-invert your colors"
      ]
    },
    "tracking_pixels": [],
    "external_assets": [],
    "unsubscribe": {
      "list_unsubscribe_header_present": false,
      "has_unsubscribe_link": false,
      "has_unsubscribe_text": false
    },
    "text_part": {
      "present": false,
      "recommended": true
    },
    "recommendations": [
      {
        "severity": "error",
        "code": "MISSING_ALT",
        "message": "1 image(s) lack alt text — add descriptive alt for accessibility + when images are blocked."
      },
      {
        "severity": "error",
        "code": "NO_UNSUB",
        "message": "No unsubscribe link/text found — required by CAN-SPAM/CASL and critical for deliverability."
      },
      {
        "severity": "warning",
        "code": "NO_DOCTYPE",
        "message": "No <!DOCTYPE> — declare one (XHTML 1.0 Transitional is the email-safe default) for predictable rendering."
      }
    ],
    "score": {
      "value": 46,
      "grade": "F"
    }
  }
}
Actions

What the Email Preflight API does

ActionDescriptionConcrete use caseKey params
audit_htmlFull pre-send structure + accessibility + deliverability lint of an HTML email: missing alt text, broken structure, mobile-width risks, dark-mode hints, tracking pixels, external assets, List-Unsubscribe check, Gmail-clip size budget, and prioritized recommendations. Pure local compute (no network).Platform and DevOps teams call audit_html to get full pre-send structure + accessibility + deliverability lint of an HTML email.html, text_part, base_url, subject, check_links
css_supportEmail-client CSS/HTML compatibility map for the template (Can-I-Email data, MIT): which CSS features used in the HTML break or degrade in Outlook/Gmail/Apple Mail/Yahoo and friends. Pure local compute (offline snapshot).Security and supply-chain teams call css_support to get email-client CSS/HTML compatibility map for the template (Can-I-Email data, MIT).html
spam_scoreDeterministic spam-SIGNAL score for the email content (caps ratio, image-to-text ratio, spam phrases, missing unsubscribe, raw-IP links…). HONEST: a content signal score, NOT an inbox-placement prediction; SpamAssassin/Rspamd sidecar = the calibrated upgrade (see docs). Pure local compute.Developer-tool builders call spam_score to get deterministic spam-SIGNAL score for the email content (caps ratio, image-to-text ratio, spam….html, subject, text_part
check_linksResolve every link in the email through url-resolver (SSRF-guarded): final URL, redirect chain, status, final domain. Bot-403/429 = `unverifiable` (honest — not marked broken). Inner-calls url-resolver per link.AI-agent developers call check_links to resolve every link in the email through url-resolver (SSRF-guarded).html, base_url
check_imagesAudit every <img> in the email: alt text presence, dimensions declared, src scheme/format, http-vs-https, and (best-effort) reachability via url-resolver. Pure-compute by default; reachability adds sub-calls.Platform and DevOps teams call check_images to get audit every <img> in the email.html, base_url, check_reachable
dns_authSender-domain email-authentication summary (SPF/DKIM/DMARC/MX + deliverability grade) via an inner-call to the email-health engine — REUSE, not re-implemented here (email-health owns DNS auth; this is a thin preflight wrapper).Security and supply-chain teams call dns_auth to get sender-domain email-authentication summary (SPF/DKIM/DMARC/MX + deliverability grade) via an….domain, dkim_selector, include_blacklist
preview_basicBasic visual preview: render the HTML to a PNG via web-capture's browser sandbox. HONEST: a browser render, NOT a real email-client render (no Outlook/Word engine). Degrades gracefully if web-capture is not deployed.Developer-tool builders call preview_basic to get basic visual preview.html, width
Code samples

Call audit_html from your stack

curl -X POST https://api.reefapi.com/email-preflight/v1/audit_html \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"html":"<html><body><img src='https://x.test/a.png'><a href='https://x.test'>hi</a></body></html>"}'
MCP one-liner
Ask your MCP-connected assistant: call reefapi.email-preflight.audit_html with {"html":"<html><body><img src='https://x.test/a.png'><a href='https://x.test'>hi</a></body></html>"}.
Use cases

Who uses this API and why

  • ESPs and marketing tools call audit_html to catch broken markup and clipping risk before a send.
  • QA pipelines use spam_score and check_links to flag deliverability and broken-link problems.
  • Accessibility checks use audit_html to ensure images have alt text and the email is readable.
FAQ

Questions developers ask before integrating

Should I call dns_auth or email-health?

dns_auth when you want one pre-send verdict, email-health when you want the evidence. Measured on github.com they produced the identical score object, 90.0 grade A with the same nine-section breakdown, but email-health returned 14 top-level keys and dns_auth returned 9. What dns_auth drops is the standalone bimi, mta_sts, tls_rpt, dnssec, dane and blacklist objects; their contribution is still visible in score.breakdown and their booleans in summary. If you need the SPF mechanism tree, the DKIM key bits or the DNSBL zone list, go to email-health.

Why did the same domain grade A on one call and B on the next?

Because include_blacklist defaults to false and the skipped section is still scored. With the default, github.com returned blacklist 10 out of 10 with the note "clean across 15 DNSBLs", summary.blacklisted false, and a total of 90.0 grade A. With include_blacklist true the same domain returned blacklist 6 out of 10 with the note "1 listing(s)", summary.blacklisted true, and 86.0 grade B. The fast default therefore awards a full clean blacklist score without having run the lookup. Pass include_blacklist true before you report a reputation result to anyone.

How is this different from validate?

Different object entirely. validate's email action takes one address and answers whether that mailbox is worth sending to: a measured [email protected] returned syntax_valid true, has_mx true with the exchange github-com.mail.protection.outlook.com, is_disposable false, is_role_account false, is_free_provider false, deliverable true and score 95. email-preflight never looks at a recipient. It takes the message body, or the sending domain, and answers whether the thing you are about to send is well formed. A typical pipeline uses validate on the list, dns_auth once on the sender, and audit_html once per template.

I used alt="" on a decorative image and it was still counted as missing.

Yes, an empty alt attribute counts as missing in both audit_html and check_images. In a measured run the image carrying alt="" appeared in accessibility.missing_alt_srcs and came back from check_images as alt "" with has_alt false. That is stricter than the HTML specification, where an empty alt is the correct marking for a decorative image. If you use that convention, subtract those images from missing_alt yourself before acting on the MISSING_ALT recommendation.

unsubscribe.list_unsubscribe_header_present is always false. Why?

Because List-Unsubscribe is an SMTP header and audit_html only ever sees the HTML body, so there is nowhere for it to be true. In our runs it was false while has_unsubscribe_link and has_unsubscribe_text were both true from an in-body link. Treat that field as a checklist reminder for your sending code rather than a finding about the template, and read the two has_unsubscribe_* fields for what the HTML actually contains.

What does verdict "unverifiable" mean on a link?

That we could not prove the link is dead, so we refuse to call it broken. Of four links in a measured template, one returned verdict ok, one returned verdict broken with a real HTTP 404, and two returned unverifiable: one with reason "host does not resolve" and error_code NOT_FOUND, the other reporting a resolution timeout against a slow target, with the response spelling out that a timeout is not proof the link is broken, and error_code INTERNAL. The response note spells out the rule: broken means a real status of 400 or above from the target, while anti-bot responses, timeouts and transport failures all land in unverifiable. Do not fail a campaign on unverifiable.

check_links reported status 206 for a link that works. Is that right?

Yes. Reachability checks use a ranged request, so a healthy target commonly answers 206 Partial Content rather than 200. A measured github.com link returned status 206 with verdict ok and redirect_count 0, and a measured image returned reachable true with http_status 206. Key on verdict for links and on reachable for images rather than testing status == 200 yourself. Images that were never attempted come back with reachable null, which is not the same as false.

Is the spam score a prediction that I will land in spam?

No, and the response says so in threshold_note: "score >= 5.0 ~ likely spam (SpamAssassin convention); this is a deterministic content SIGNAL, not an inbox-placement prediction." It is rule-based and repeatable. A deliberately awful test message scored 7.3 with verdict likely_spam over 7 rules including FREE_MONEY 1.5, CAPS_HEAVY 1.5 at a measured 36 percent all-caps words, URGENCY 1.0, MANY_EXCLAIM 1.0 and IMG_RATIO 1.0 for 4 images against 25 words; a plain rewrite scored 0.0 with verdict clean_signal and zero rules. Note that audit_html does not include this block, so spam_score is a separate call.

What is the Email Preflight API?

Email Preflight API is a ReefAPI endpoint group for email preflight It returns live JSON through POST requests under /email-preflight/v1.

Is the Email Preflight API free to try?

Yes. ReefAPI starts with 1,000 free credits, no card required. Email Preflight calls use the same shared credit balance as every other ReefAPI engine.

Do I need an Email Preflight login or account?

No login to Email Preflight is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the Email Preflight data?

The page example is captured from a live audit_html call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the Email Preflight API use?

Email Preflight actions currently cost 1-3 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call Email Preflight from an AI assistant or MCP client?

Yes. Connect ReefAPI once through MCP and your assistant can call email-preflight actions with the same key, credit pool and JSON envelope used by normal REST requests.

docs / email-preflight

Email Preflight

Email Preflight

base /email-preflight/v17 endpoints
post/email-preflight/v1/audit_html2 credits

Full pre-send structure + accessibility + deliverability lint of an HTML email: missing alt text, broken structure, mobile-width risks, dark-mode hints, tracking pixels, external assets, List-Unsubscribe check, Gmail-clip size budget, and prioritized recommendations. Pure local compute (no network).

ParameterAllowed / rangeDescription
htmlrequiredThe full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
text_partoptionalOptional plain-text alternative of the email. If omitted, the audit flags the missing multipart/alternative text part.
base_urloptionalOptional base URL: relative links/images in the HTML are resolved against it before checking.
subjectoptionalOptional subject line — included in the spam-signal analysis.
check_links = falseoptionalIf true, audit_html ALSO resolves every link via url-resolver (adds latency + a sub-call per link). Default false = static lint only.
Try in playground →
post/email-preflight/v1/css_support1 credit

Email-client CSS/HTML compatibility map for the template (Can-I-Email data, MIT): which CSS features used in the HTML break or degrade in Outlook/Gmail/Apple Mail/Yahoo and friends. Pure local compute (offline snapshot).

ParameterAllowed / rangeDescription
htmlrequiredThe full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
Try in playground →
post/email-preflight/v1/spam_score1 credit

Deterministic spam-SIGNAL score for the email content (caps ratio, image-to-text ratio, spam phrases, missing unsubscribe, raw-IP links…). HONEST: a content signal score, NOT an inbox-placement prediction; SpamAssassin/Rspamd sidecar = the calibrated upgrade (see docs). Pure local compute.

ParameterAllowed / rangeDescription
htmlrequiredThe full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
subjectoptionalOptional subject line — included in the spam-signal analysis.
text_partoptionalOptional plain-text alternative of the email. If omitted, the audit flags the missing multipart/alternative text part.
Try in playground →
post/email-preflight/v1/check_images1 credit

Audit every <img> in the email: alt text presence, dimensions declared, src scheme/format, http-vs-https, and (best-effort) reachability via url-resolver. Pure-compute by default; reachability adds sub-calls.

ParameterAllowed / rangeDescription
htmlrequiredThe full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
base_urloptionalOptional base URL: relative links/images in the HTML are resolved against it before checking.
check_reachable = falseoptionalIf true, HEAD/GET each image via url-resolver to confirm it loads (adds latency + sub-calls).
Try in playground →
post/email-preflight/v1/dns_auth1 credit

Sender-domain email-authentication summary (SPF/DKIM/DMARC/MX + deliverability grade) via an inner-call to the email-health engine — REUSE, not re-implemented here (email-health owns DNS auth; this is a thin preflight wrapper).

ParameterAllowed / rangeDescription
domainrequiredThe sending domain (the From: address domain). Its email authentication (SPF/DKIM/DMARC/MX) is summarized via email-health.
dkim_selectoroptionalOptional DKIM selector to look up (e.g. 'google', 's1'). If omitted, email-health autoscans common selectors.
include_blacklist = falseoptionalAlso run the slower DNSBL reputation pass (email-health blacklist). Default false = auth-only (SPF/DKIM/DMARC/MX), the fast pre-send check.
Try in playground →
post/email-preflight/v1/preview_basic3 credits

Basic visual preview: render the HTML to a PNG via web-capture's browser sandbox. HONEST: a browser render, NOT a real email-client render (no Outlook/Word engine). Degrades gracefully if web-capture is not deployed.

ParameterAllowed / rangeDescription
htmlrequiredThe full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
width = 600optional320–1200Viewport width in px (typical email width = 600).
Try in playground →