--- name: pre-send-qa description: Pre-flight QA for an email campaign — merge tags, broken links, spam triggers, compliance, mobile rendering — before you hit send version: "1.0.0" author: Cogny AI requires: cogny-mcp platforms: [klaviyo, mailchimp, rule, get-a-newsletter] user-invocable: true argument-hint: "[campaign ID | paste HTML]" allowed-tools: # Cogny Cloud (aggregated) namespace - mcp__cogny__klaviyo__* - mcp__cogny__mailchimp__* - mcp__cogny__rule__* - mcp__cogny__get_a_newsletter__* - mcp__cogny__create_finding # Cogny Solo / Lite (per-ESP direct) namespace - mcp__klaviyo__* - mcp__mailchimp__* - mcp__rule__* - mcp__get_a_newsletter__* - WebFetch - Bash - Read - Write --- # Pre-Send QA Catch the embarrassing stuff before it ships to your list. Runs a full pre-flight check on an email: merge tag fallbacks, broken links, spam triggers, CAN-SPAM / GDPR footers, mobile rendering, size limits, accessibility. **Requires:** Cogny MCP for campaign-ID mode. Paste-HTML mode works without MCP (but without send-context checks). ## Usage `/pre-send-qa ` — QA a specific campaign (or draft, for Get a Newsletter) in your ESP `/pre-send-qa` — then paste the email HTML/MJML/text when prompted ## Steps ### 1. Load the email **Mode A — Campaign ID (MCP).** Detect which ESP is connected (check both namespaces: `mcp__cogny____*` and `mcp____*`) and use the right tool: | ESP | Fetch tool | What the ID refers to | |-----|------------|----------------------| | Klaviyo | `get_campaign` | Campaign object | | Mailchimp | `tool_get_campaign` | Campaign object | | Rule | `tool_get_campaign` | Campaign object | | Get a Newsletter — pre-send | `tool_get_draft` | A draft that hasn't been sent yet | | Get a Newsletter — post-send forensics | `tool_get_sent` + `tool_get_report` | A sent item | For every ESP extract: subject, preheader, from name, from email, reply-to, HTML body, text body, target segment/list, scheduled send time. Also fetch the associated list/audience size so Section 2.8 has recipient count. **Get a Newsletter has no single "campaign" object.** If the user passes an ID, try `tool_get_draft` first (pre-send QA is the common use), fall back to `tool_get_sent` if that 404s. If they want to QA a *scheduled* send, use `tool_list_scheduled` to find it. **Mode B — Paste:** - Ask for subject line, preheader, from name/email, and body HTML. Accept multi-line paste. - Section 2.8 (send context) is skipped in paste mode — no recipient count, no segment, no schedule. ### 2. Run the checklist Walk through every category. For each item, mark `[PASS]`, `[WARN]`, or `[FAIL]` and include the specific offending content. #### 2.1 Headers & routing - [ ] **Subject line present** — not empty - [ ] **Subject length ≤ 55 chars** (mobile truncation threshold) - [ ] **Preheader present** — not empty, not a duplicate of subject - [ ] **Preheader length 85–100 chars** (too short = wasted real estate; too long = truncated) - [ ] **From name is branded** — not "noreply", not "info" - [ ] **From email uses sending subdomain** — flag `@gmail.com`/`@outlook.com` from addresses (deliverability killer for bulk) - [ ] **Reply-to is monitored** — warn if it's a noreply@ #### 2.2 Merge tags / personalization Scan body + subject + preheader for: - `{{ ... }}`, `{% ... %}`, `*|...|*`, `[[...]]`, `%%...%%`, `{...}` — depending on ESP syntax - [ ] **All merge tags well-formed** — balanced brackets, closed blocks - [ ] **All merge tags have fallbacks** — e.g., `{{ first_name|default:"there" }}` (Klaviyo), `*|IFNOT:FNAME|*there*|ELSE:*|FNAME|**|END:IF|*` (Mailchimp). Flag any token without a fallback as FAIL. - [ ] **"Hi ," or "Hello ," anti-pattern** — substring search for bare punctuation after a greeting. This is the #1 embarrassing merge-tag failure. - [ ] **Dynamic content blocks closed** — open `{% if %}` must have `{% endif %}`; same for loops - [ ] **No raw tokens in subject line** — e.g., subject reading literally "Hi {{ first_name }}" #### 2.3 Links Extract all `` from the HTML. For each: - [ ] **URL is absolute** — no `href="/path"` without domain; no `href="#"` unless intentional anchor - [ ] **URL resolves** — HEAD-check each unique URL (cap at 30 requests, dedupe). Flag non-200s. - [ ] **No `localhost` / `127.0.0.1` / `.local`** — dev leak - [ ] **No staging/dev domains** — flag `*.staging.*`, `*.dev.*`, `stage.`, `preprod.` - [ ] **UTM parameters present on all outbound links** — warn on links missing `utm_source`/`utm_medium`/`utm_campaign` - [ ] **UTM consistency** — all links should share `utm_campaign`; flag divergence - [ ] **Link count** — report total. Warn if >20 (clutter). Warn if <1 (no CTA). - [ ] **CTA destination consistency** — multiple buttons labeled "Shop now" should generally point to the same URL #### 2.4 Images - [ ] **All `` have `alt` text** — non-empty, descriptive - [ ] **No pure-image email** — flag if text-to-image ratio is <40% text. Hero-image-only emails trigger spam filters. - [ ] **Image URLs are absolute + HTTPS** - [ ] **Image URLs aren't hotlinked from sketchy hosts** — flag if images are on `imgur`, `cloudinary demo`, etc. instead of a brand CDN #### 2.5 Compliance - [ ] **Unsubscribe link present** — regex for `unsubscribe`, `preferences`, `opt out` - [ ] **Unsubscribe link is visible** — not `display:none` or font-size:1px - [ ] **Physical postal address in footer** — CAN-SPAM requirement. Regex for a street/city pattern or flag if missing. - [ ] **List-Unsubscribe header** — flag if ESP allows setting it but it's not configured (one-click unsubscribe is required by Gmail/Yahoo for bulk senders) - [ ] **Preference center link** — nice-to-have; warn if only unsubscribe exists #### 2.6 Spam triggers Scan subject + preheader + body for classic triggers and report offenders: - **Word-level:** free, winner, congratulations, guaranteed, risk-free, act now, click here, limited time, no obligation, viagra (lol), make money, earn extra, $$$ - **Punctuation:** more than one `!` in subject, `!!!`, `???` - **Casing:** ALL CAPS WORDS longer than 3 chars in subject - **Symbols:** `$$$`, `★`, excessive emoji (>3) - **HTML:** hidden text (color matches background), tiny font, embedded JavaScript, background images on `` Output each offender with context: ``` 🔴 Subject contains "!!!" 🟡 Body has 4 instances of ALL CAPS words: "LIMITED", "TODAY", "ACT NOW", "DON'T" ``` #### 2.7 Rendering & size - [ ] **HTML size < 102 KB** — Gmail clips at 102 KB. Report actual size. - [ ] **Single root `` layout** (desktop email standard) OR uses MJML — flag flex/grid as a deliverability risk - [ ] **Inline CSS** — style attributes vs `