Help us improve
Share bugs, ideas, or general feedback.
From webmatrices
Email campaign workflow with safety states. Builds, previews, and sends targeted email campaigns to Webmatrices audience segments. Three-state machine ensures you never accidentally send to 27K users. **Performance rules in this skill are derived from real Brevo data (April 2026 analysis, internal opens filtered).**
npx claudepluginhub bishwas-py/webmatrices-skills --plugin webmatricesHow this skill is triggered — by the user, by Claude, or both
Slash command
/webmatrices:campaignThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Email campaign workflow with safety states. Builds, previews, and sends targeted email campaigns to Webmatrices audience segments. Three-state machine ensures you never accidentally send to 27K users. **Performance rules in this skill are derived from real Brevo data (April 2026 analysis, internal opens filtered).**
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.
Share bugs, ideas, or general feedback.
Email campaign workflow with safety states. Builds, previews, and sends targeted email campaigns to Webmatrices audience segments. Three-state machine ensures you never accidentally send to 27K users. Performance rules in this skill are derived from real Brevo data (April 2026 analysis, internal opens filtered).
DRAFT → PREVIEWED → SENT
| State | What happened | What can happen next |
|---|---|---|
| DRAFT | Email content built, segments chosen | /campaign preview (sends to the site owner only) |
| PREVIEWED | The site owner received the test email | /campaign send (fires to full audience) |
| SENT | Email delivered to segments | Done |
Rules:
/campaign [anything] = always starts in DRAFT state. Never sends./campaign preview = sends to the site owner ONLY (fetch admin user from get_self_personas MCP). Moves to PREVIEWED./campaign send = fires to full segments. If NOT previewed first, asks "Are you sure you want to send without previewing? This will go to [N] users."All numbers below come from Brevo events for the trailing 30 days, internal users (is_internal=true plus bishwasbh+* aliases) filtered out. Use these as the empirical baseline. Do not draft a campaign that ignores them.
| Pattern | Example | Sent | Open % | CTR % |
|---|---|---|---|---|
| Personalized lapsed-user story | "5 sites got reviewed this week, [Name]" | 49 | 51.0% | 18.4% |
| Personalized "it took X before Y" hook | "it took 40 posts before google sent a single visitor, [Name]" | 48 | 54.2% | 10.4% |
| Comment notifications on hot threads | "New comment on your post 'getting rejected by AdSense...'" | 6 | 50.0% | 50.0% |
| Reply notifications | "New reply to your comment on '...'" | 8 | 37.5% | 25.0% |
What unites the champions:
, [Name] suffix)Run these templates weekly against fresh segments. They are 10–15× more effective than any broadcast.
| Subject | Sent | Open % | CTR % | What's wrong |
|---|---|---|---|---|
| "This week on Webmatrices: Vercel breach, vibe coding..." | 84 | 27.4% | 0% | Body buries CTA |
| "Your old content might be killing your new rankings" | 80 | 21.2% | 0% | Story told in-email; no reason to click |
| "A Roblox cheat just took down Vercel..." | 57 | 21.1% | 0% | Multiple links compete |
| "your traffic is down but your rankings are fine" | 117 | 20.5% | 3.4% | Working but underperforming the open rate |
| "a developer let ai write all his code for 4 months" | 141 | 17.7% | 1.4% | Same — opens are great, clicks lag |
Diagnosis: news-event hooks pull opens but the email bodies leak readers. The reader opens, doesn't see one clear destination, bounces. Fix: single button, single thread, body is a tease not a recap. See "Body design" below.
Solid workhorses (no fix needed, run as-is):
| Subject | Sent | Open % | CTR % |
|---|---|---|---|
| "Quick fix — here's the correct link, [Name]" | 51 | 23.5% | 3.9% |
| "Your checklist is waiting, [Name]" | 51 | 23.5% | 5.9% |
| "you joined at the right time — 21 app ideas ready to build" | 234 | 10.7% | 1.3% |
| Subject | Sent | Open % | CTR % | Why dead |
|---|---|---|---|---|
| Mass blast: "what ai, side hustles, and remote work have in common" | 11,409 | 3.6% | 0.25% | Too large; stale list; segment fatigue |
| "We built something new, [Name]" | 116 | 8.6% | 0.9% | Pure announcement frame |
| "this week on webmatrices — 4 new app ideas + fresh posts" | 89 | 6.7% | 0% | Recap framing |
| "4 new app ideas just landed on webmatrices" | 53 | 5.7% | 0% | Recap framing |
Banned subject patterns:
| Cohort | Open rate | CTR |
|---|---|---|
| Last 30 days, all sends | 5.61% | 0.81% |
| Excluding the one mass blast | 20.79% | 5.11% |
| Mass blast in isolation | 3.60% | 0.25% |
Read: the channel is healthy when used surgically. One bad send dragged the average from 21% to 6%. Repeat that mistake monthly and the platform's deliverability degrades for every future send.
The MCP enforces a hard cap of 500 recipients per send. There is no override. To reach more users, batch multiple campaigns and chain excludeUserIds so the second campaign excludes everyone the first reached.
These rules exist because the 2026-04 mass blast (sent before the hard cap was tightened) hit 2.93% hard bounce rate — above the ESP threshold of 2%, throttling above 5%.
| Goal recipient count | How to do it |
|---|---|
| ≤ 500 | Single send_targeted_email call. Sweet spot. |
| 500–1,500 | 2–3 sequential calls, each ≤ 500, chained with excludeUserIds so no overlap |
| 1,500+ | Reconsider. Splitting a topic across that many users almost always lowers per-send performance. Narrow the segment instead. |
all_active (~27K) | Blocked by MCP. Only allowed for critical TOS/policy updates after explicit override. |
is_internal=true users — no skill-level filtering neededemailNotifications=false/post/[slug]) exist; blocks send on broken links{{username}} and {{firstName}} placeholderssentUserIds so you can excludeUserIds in the next batchexcludeUserIds for future sends.inactive_users segment with days: 365 to surface them, route to re-permission flow rather than including in promo campaigns.Do not email the same segment more than once per 7 days unless it's a transactional event (comment notification, reply, account confirmation). Repeated hits cause segment fatigue.
[Concrete number] [outcome verb] [time/scope], [First Name]
Examples that work:
Why it works: name signals 1:1 intent, number signals real story, lowercase signals personal.
[Specific event/entity] [verb] [outcome]. [Optional context.]
Examples that work for opens (need body fix for clicks):
Use only when there's a real news hook AND the body is single-thread, single-button.
[State of affairs] but [contradicting outcome] — [framing question]
Examples that work:
The skill provides inner body HTML only — paragraphs, optional inline links, optional <strong> for emphasis. The MCP wraps it with the email template (header, footer, unsubscribe) and appends the CTA button when you pass ctaText + ctaUrl. Do not write the button HTML yourself. Do not write <table> wrappers. Do not write the email template chrome.
The Tier 2 problem (high open, zero CTR) is bodies leaking readers. These rules exist to fix that.
Every email has one destination — passed as ctaUrl. Do not put multiple inline links inside the body. If you absolutely must mention a secondary item, put it in a small <p> "P.S." line at the bottom with a single secondary inline link. The CTA button (rendered by the MCP from ctaText/ctaUrl) must be the dominant action.
What the skill writes:
<p>hey {{firstName}},</p>
<p>[2-3 sentence personal frame — what made you write this email today.
Real and specific, first person, not corporate.]</p>
<p>[1 sentence specific tease about the thread — a number, a name,
a turn of phrase from the post. Not a summary. Leave the reader curious.]</p>
<p>[1 sentence why this matters to the recipient specifically — segment relevant.]</p>
<p>— bishwas</p>
The MCP appends the CTA button below this body using ctaText and ctaUrl parameters. The button styling, white-text span fix, and centering are all handled by the MCP. Don't write button markup in the body.
Use {{firstName}} and {{username}} in body and subject. The MCP substitutes them per-recipient. Fall-back behavior: if firstName is null, the MCP uses username.
ctaText: action-oriented, max 5 words. ("Read the thread →", "See what changed →", "Drop your URL below →"). Never generic ("Click here", "Learn more").ctaUrl: relative path (e.g., /post/your-slug) or absolute. The MCP verifies the slug exists before sending.| Input | What it does |
|---|---|
"recent" | Finds last 2-3 published posts, builds campaign around them |
| Post ID | Builds campaign promoting that specific post |
| Post slug | Fetches post via get_post_by_slug, builds campaign around it |
| Description text | Builds campaign based on described theme/promotion |
If "recent":
list_posts to get the 5 most recent postsIf postId/slug:
get_post or get_post_by_slug MCPIf description:
search_posts_by_content or list_postsCRITICAL: Single destination only. The data is unambiguous — multi-link emails get 0% CTR even with 21% opens. Pick one thread.
Use preview_audience MCP to check segment sizes before choosing.
Segment selection rules:
Available segments (real MCP names):
| Segment | What it targets | Best for |
|---|---|---|
commenters | Users who have commented at least once | High-engagement campaigns. Most reactive segment. |
post_authors | Users who have published posts | Engagement boosts on related new posts |
lapsed_contributors | Posted/commented but inactive days+ | Reactivation of warm users (set days: 14-30) |
inactive_users | Inactive for days+ (default 30) | Re-engagement (set days: 30/60/90/365) |
new_users | Joined in last days (default 7) | Welcome / starter-content campaigns |
checklist_users | Created project checklists | Tool/workflow related campaigns |
premium_users | Has isPremium=true | Premium-only announcements |
all_active | Everyone active | Blocked by MCP. Critical TOS only. |
Segment chaining: when running multiple sends to overlapping segments, the MCP returns sentUserIds after each send. Pass that array as excludeUserIds on the next send so no user gets duplicates.
Time-window parameter (days): for inactive_users, lapsed_contributors, and new_users, the days argument tunes the window. Use it to surface the right cohort (e.g., lapsed_contributors with days: 30 = posted/commented but quiet for a month).
The MCP automatically excludes is_internal=true users from every send_targeted_email call. You do not need to fetch persona IDs and add them to excludeUserIds. This was previously a skill-level requirement; it's now baked into the MCP. Just use excludeUserIds for chaining across multiple sends and known hard-bouncers.
Before showing the draft, run this internal check. Score 1 point per ✅. Block any draft scoring below 6/8.
| Check | Pass criteria |
|---|---|
| Subject matches a Tier 1 or 2 formula | First-name + number + story OR clear news-event hook |
| Subject is NOT a banned format | No "X just landed", no "this week on", no "we built" |
| Subject is under 70 characters | Mobile preview cuts off |
Body provides single ctaUrl destination | One thread, one button |
| Body word count 80–180 (stripped) | Sweet spot for opens-to-click conversion |
| Body does NOT contain manual button HTML | MCP renders the button from ctaText/ctaUrl |
| Body does NOT contain template chrome | No <table> wrappers, no header/footer markup |
| Segment matches topic and ≤ 500 recipients | MCP hard-caps at 500 |
Show:
Ask: "Ready to preview? Run /campaign preview to send a test to the site owner."
NEVER auto-send. NEVER proceed past DRAFT without user action.
send_email MCP with:
userId: 1 (the site owner's user ID)send_targeted_email for preview — it picks from the segment, not the site owner/campaign send"send_targeted_email MCP with all exclusions appliedTarget: lapsed users (no login 30–90 days, opened at least one email in last 12 months). Format: Tier 1 personalized story hook. Subject: "5 sites got reviewed this week, [Name]" / "it took 40 posts before google sent a single visitor, [Name]" / variant. Send size: 100–300 per batch. Cadence: weekly.
Target: users who commented on related threads in last 30 days. Format: Tier 2 news-event hook OR Formula C pain-point. Subject: news angle from the post. Send size: 80–250. Cadence: 1× per major post.
Target: just-registered users. Format: short, single CTA to a starter thread. Subject: "Confirm your email" / "Welcome to Webmatrices!" — these already perform well (38–55% open).
Target: 12+ months no opens. Format: explicit "still want to hear from us?" with single yes/no link. Send size: 500 per batch max. Cadence: once per stale segment, then drop them if no reply.
ctaUrl is verified to exist (the MCP will block on broken slug — but check yourself first)ctaUrl destinationall_active)excludeUserIds (manual until MCP supports it)excludeUserIds from previous sentUserIdsThe performance numbers in this skill are from the trailing 30 days as of 2026-04-27. Re-run the Brevo analysis quarterly:
/v3/smtp/statistics/events for last 90 daysis_internal=true users (and bishwasbh+* aliases), [Name] suffix)wiki/Forum-Engagement-Diagnosis-YYYY-MM.mdIf a pattern stops working, retire it from TIER 1 immediately. The empirical data leads the rules.
ctaUrl. Multi-link emails get 0% CTR even at 21% opens — proven repeatedly in the data.wiki/Forum-Engagement-Diagnosis-YYYY-MM.md.