# Email Preflight API — pre-send QA for HTML email: structure and accessibility lint, client CSS compatibility, spam-signal score, link and image checks, sender DNS auth and preview

> 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).
> ReefAPI engine `email-preflight` · 7 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/email-preflight/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed or blocked calls are free.
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http, `Authorization: Bearer <key>`) and your assistant can call these actions directly.

## Endpoints

### POST /email-preflight/v1/audit_html — 2 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).

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
- `text_part` (string, optional) — Optional plain-text alternative of the email. If omitted, the audit flags the missing multipart/alternative text part.
- `base_url` (string, optional) — Optional base URL: relative links/images in the HTML are resolved against it before checking.
- `subject` (string, optional) — Optional subject line — included in the spam-signal analysis.
- `check_links` (boolean, optional, default false) — If true, audit_html ALSO resolves every link via url-resolver (adds latency + a sub-call per link). Default false = static lint only.

**Returns:** html_validity{parse_ok,warnings[]}, size{bytes,gmail_clip_risk,limit}, accessibility{missing_alt,images_total,issues[]}, structure{has_doctype,has_table_layout,uses_div_layout,heading_count}, mobile_width_risks[], dark_mode{has_meta_color_scheme,hints[]}, tracking_pixels[], external_assets[], unsubscribe{list_unsubscribe_header_present,has_unsubscribe_link,has_unsubscribe_text}, text_part{present,recommended}, recommendations[{severity,code,message}], score{0-100,grade}

**Example request body:**
```json
{
  "html": "<html><body><img src='https://x.test/a.png'><a href='https://x.test'>hi</a></body></html>"
}
```

### POST /email-preflight/v1/css_support — 1 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).

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.

**Returns:** features_detected[{feature,title,category,unsupported_in[],partial_in[],high_risk,support_map{}}], high_risk_count, clients_considered[], data_source (bundled-snapshot|curated-fallback), data_version, summary

**Example request body:**
```json
{
  "html": "<div style='display:flex'>x</div>"
}
```

### POST /email-preflight/v1/spam_score — 1 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.

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
- `subject` (string, optional) — Optional subject line — included in the spam-signal analysis.
- `text_part` (string, optional) — Optional plain-text alternative of the email. If omitted, the audit flags the missing multipart/alternative text part.

**Returns:** score (>=5 ~ likely spam), verdict (clean_signal|suspicious|likely_spam), triggered_rules[{rule,score,description}], rule_count, metrics{words,caps_ratio,image_count,link_count,has_unsubscribe_text}, threshold_note, engine

**Example request body:**
```json
{
  "html": "<p>100% FREE!!! ACT NOW — WIN CASH PRIZE</p>",
  "subject": "FREE MONEY"
}
```

### POST /email-preflight/v1/check_links — 2 credits
Resolve 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.

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
- `base_url` (string, optional) — Optional base URL: relative links/images in the HTML are resolved against it before checking.

**Returns:** links[{url,final_url,final_domain,status,redirect_count,verdict: ok|broken|redirect|unverifiable|blocked|skipped}], counts{total,checked,ok,broken,redirect,unverifiable}, unique_domains[]

**Example request body:**
```json
{
  "html": "<a href='https://github.com'>a</a><a href='https://example.com'>b</a>"
}
```

### POST /email-preflight/v1/check_images — 1 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.

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
- `base_url` (string, optional) — Optional base URL: relative links/images in the HTML are resolved against it before checking.
- `check_reachable` (boolean, optional, default false) — If true, HEAD/GET each image via url-resolver to confirm it loads (adds latency + sub-calls).

**Returns:** images[{src,alt,has_alt,width,height,dimensions_declared,scheme,format,is_https,reachable}], counts{total,missing_alt,insecure_http,no_dimensions}, issues[]

**Example request body:**
```json
{
  "html": "<img src='https://x.test/a.png'><img src='b.png' alt='ok'>"
}
```

### POST /email-preflight/v1/dns_auth — 1 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).

**Parameters:**
- `domain` (string, required) — The sending domain (the From: address domain). Its email authentication (SPF/DKIM/DMARC/MX) is summarized via email-health.
- `dkim_selector` (string, optional) — Optional DKIM selector to look up (e.g. 'google', 's1'). If omitted, email-health autoscans common selectors.
- `include_blacklist` (boolean, optional, default false) — Also run the slower DNSBL reputation pass (email-health blacklist). Default false = auth-only (SPF/DKIM/DMARC/MX), the fast pre-send check.

**Returns:** domain, score{score,grade}, spf{found,policy}, dkim{found,selectors_found}, dmarc{found,policy,enforced}, mx{found,provider}, summary, source ('email-health inner-call'), reused_engine

**Example request body:**
```json
{
  "domain": "github.com"
}
```

### POST /email-preflight/v1/preview_basic — 3 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.

**Parameters:**
- `html` (string, required) — The full HTML of the email you are about to send (paste the source). Parsed read-only in a no-network, no-script sandbox.
- `width` (integer, optional, default 600) — Viewport width in px (typical email width = 600).

**Returns:** image_b64 (PNG) or unavailable status, width, rendered_by ('web-capture'), disclaimer (browser != email-client render)

**Example request body:**
```json
{
  "html": "<h1>hi</h1>"
}
```

## More
- Try it live, no code: https://reefapi.com/playground?engine=email-preflight
- Human docs page: https://reefapi.com/docs/email-preflight
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
