/pre-send-qa
Pre-flight QA for an email campaign — merge tags, broken links, spam triggers, compliance, mobile rendering — before you hit send
$ npx -y skills add cognyai/claude-code-marketing-skills --skill pre-send-qa --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/pre-send-qa
Context preview
The summary Claude sees to decide when to auto-load this skill.
Pre-flight QA for an email campaign — merge tags, broken links, spam triggers, compliance, mobile rendering — before you hit send
SKILL.md
pre-send-qa.SKILL.mdname: 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 <campaign-or-draft-id>` — 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__<svc>__*` and `mcp__<svc>__*`) 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 `<a href="...">` 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 `<img>` 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 obli
Read more
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 <campaign-or-draft-id>` — 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__<svc>__*` and `mcp__<svc>__*`) 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 `<a href="...">` 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 `<img>` 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 obli
AI marketing skills for Claude Code, Cursor, Windsurf, and other AI coding tools. Audit SEO, analyze ads, research competitors, qualify leads — all from your terminal. Free skills need no account. Premium skills connect your real data for $9/mo.
Repo: cognyai/claude-code-marketing-skills
Other skills on claude-code-marketing-skills.
brand-kit
Build a portable brand-kit.json for the user's product — colors, typography, voice — that other skills (video, ad creative, landing page) can consume. Multiple…
cogny
Run Cogny marketing analysis tasks — fetch scheduled tasks, analyze ad accounts via MCP, report findings
community-pulse
Weekly read on Discord community health — joins, active channels, top contributors, themes, and unanswered questions
conversion-debug
Conversion Tracking Debugger — diagnose discrepancies across GTM, GA4, Google Ads & Meta Pixel with live API access, BigQuery validation queries, and…

