Pre-send QA

Deliverability

Pre-send QA

A live audit that lints the design for the mistakes that hurt deliverability and rendering, before it's sent. The toolbar's Audit button carries a live badge with the current error/warning count, and opens a docked, non-blocking panel you can keep open while you fix issues, each finding jumps straight to the offending block.

Audit is a paid feature, the button appears only when the plan grants qa.audit (part of the Deliverability suite with Inbox previews; see Plans & entitlements).

What it checks#

PropertyControlsDefault
LinksEmpty/placeholder (#, example.com) and unsafe javascript: URLserror / warning
Alt textImages & GIFs missing alt textwarning
Heading orderA heading that skips a level (h1 straight to h3)warning
Link textLinks that say only click here or read moreinfo
Button labelA button with no labelwarning
Small textText, headings and buttons under 12pxwarning
Table headerA table with the header row turned offinfo
LanguageNo document language set in Body settingsinfo
ContrastButton text vs background below WCAG 4.5:1warning
Subject lineMissing, or longer than ~70 characterswarning / info
PreheaderNo preheader text setinfo
UnsubscribeNo unsubscribe link / {{unsubscribe_url}} foundwarning
Spam wordsClassic spam-filter trigger phrases in subject/contentinfo
Gmail clippingHTML over about 102 KB (Gmail hides the rest), or over 90 KB (close). Linked images do not count. The toolbar shows a Gmail size badge from 90 KBwarning / info

Programmatic#

The same audit is exported from the renderer, so you can gate your own send flow:

tsqa.ts
import { auditDesign } from "email-craft-sdk";

const findings = auditDesign(design);
// [{ id, severity: "error"|"warning"|"info", category, message, blockId?, hint? }]
const blockers = findings.filter((f) => f.severity === "error");
if (blockers.length) throw new Error("Fix QA errors before sending");

Custom validators#

Register your own rules with config.qa.validators (or pass them to auditDesign(design, { validators })). They run alongside the built-in checks and their findings merge into the same live panel. A validator that throws is skipped, one bad rule never breaks the audit.

tscustomValidators.ts
const config = {
  qa: {
    validators: [
      {
        id: "brand", run: (design) => {
          const hasLogo = design.body.rows.some((r) =>
            r.columns.some((c) => c.blocks.some((b) => b.type === "image")));
          return hasLogo ? [] : [{ severity: "error", message: "Add your logo before sending." }];
        }
      }
    ]
  }
};