Email Marketing skill for Codex
Lifecycle email that lands in the inbox. Codex designs email programs around events and exit conditions instead of calendar blasts, splits transactional and marketing streams, and checks SPF, DKIM, DMARC alignment and one-click unsubscribe against the Gmail, Yahoo and Outlook bulk sender rules. It measures flows with clicks and holdout groups because opens are inflated, and it will not activate a send or change DNS without your confirmation.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- email-marketing Installs to ~/.agents/skills/email-marketing/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install email-marketing The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project email-marketing Installs to .agents/skills/email-marketing/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/email-marketing.zipunzip -o email-marketing.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) email-marketing PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
104-line POSIX script. No sudo, no telemetry. Read install.sh
Use it in Codex
Start a prompt with $email-marketing, or pick it from /skills.
You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.
What Codex reads before loading it
Plans and builds lifecycle and marketing email programs - welcome, onboarding, activation, trial conversion, win-back and broadcast campaigns - with event-based triggers, segmentation, suppression rules and deliverability set up correctly (SPF, DKIM, DMARC alignment, one-click unsubscribe, Gmail and Yahoo bulk sender rules). Works in Customer.io, Braze, Klaviyo, Loops, Resend, Postmark or SendGrid. Use when asked to design an onboarding sequence, fix emails landing in spam, segment a list, set up DMARC, or measure email performance.
Use it when
- You need welcome, onboarding, trial or win-back flows mapped to product events
- Emails land in spam or Postmaster Tools shows rising complaint rates
- A list needs behavioural segments and suppression rules before a campaign
- You must meet Gmail and Yahoo bulk sender requirements
Use something else when
- You are emailing prospects who never opted in: use cold-email-outreach
- The task is building HTML email templates that render in Outlook: use email-template-design
- You are growing a content newsletter audience: use newsletter-growth
How to check the result
A test send shows SPF, DKIM and DMARC PASS for your domain in Gmail's Show original, and each flow's goal conversion beats its holdout group.
The mistake it prevents
Judging flows by open rate, which Apple Mail Privacy Protection inflates, and sending marketing mail from the same domain as password resets.
A lifecycle program is done well when each email is triggered by something the user did (or did not do), goes only to people who consented and are not suppressed, authenticates with aligned SPF/DKIM/DMARC, and is judged by clicks and downstream conversions rather than opens.
Inspect before building
- Read
AGENTS.md; find the ESP and how email is sent today:rg -n "resend|postmark|sendgrid|@sendgrid|mailgun|customerio|braze|klaviyo|loops|nodemailer|ses" -g '!node_modules'. - Separate the two streams: transactional (receipts, password resets, security) and marketing/lifecycle. Send them from different subdomains or at least separate streams/IP pools so a marketing complaint spike cannot delay password resets.
- Check the sending domain’s DNS (needs network):
dig +short TXT example.com | grep -i spf
dig +short TXT _dmarc.example.com
dig +short TXT <selector>._domainkey.mail.example.com # selector from the ESP's setup page
- Find where consent is stored (signup form checkbox,
marketing_opt_incolumn) and where unsubscribes and bounces are recorded. If there is no consent record, stop and raise it before sending any marketing email.
Deliverability baseline (non-negotiable)
Since 2024, Gmail and Yahoo require this for anyone sending around 5,000+ messages a day to their users, and Microsoft Outlook.com applies similar rules from May 2025. Treat it as required for every sender.
| Requirement | Detail |
|---|---|
| SPF | v=spf1 include:<esp> ~all; stay under 10 DNS lookups |
| DKIM | 2048-bit key published by the ESP, signing with your domain (not the ESP’s) |
| DMARC | At least p=none with rua= reporting; From domain must align with SPF or DKIM domain |
| One-click unsubscribe | List-Unsubscribe with an HTTPS URL plus List-Unsubscribe-Post: List-Unsubscribe=One-Click (RFC 8058); honour within 2 days |
| Spam complaint rate | Keep under 0.1% in Google Postmaster Tools; never reach 0.3% |
| Valid forward and reverse DNS for sending IPs | Usually handled by the ESP |
DMARC rollout: p=none with reports for 2-4 weeks, fix every legitimate source that
fails alignment, then p=quarantine; pct=25 and step up to p=reject. Changing DNS on a
production domain is an outward-facing change; show the exact record and get the user’s
confirmation before applying it.
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r"
Program design
Map lifecycle emails to the user journey and to one behavioural goal each:
| Stage | Trigger | Goal metric | Exit condition |
|---|---|---|---|
| Welcome | user_signed_up | First key action within 24 h | Key action done |
| Onboarding / activation | Signup + missing setup event after N hours | Activation event | Activated |
| Trial conversion | trial_started, 3-5 days before trial end | Paid conversion | Subscribed |
| Feature adoption | Active user who never used feature X | Feature used | Used X |
| Re-engagement | No login for 30 days | Return session | Logged in |
| Win-back | Subscription cancelled 30-60 days ago | Reactivation | Resubscribed, or 2 sends |
| Sunset | No opens or clicks for 90-180 days | List hygiene | Suppress |
Rules for every flow:
- Every flow has an exit condition; nobody gets “set up your account” after setting it up.
- Frequency cap across flows (e.g. max 1 lifecycle email per day, 4 per week).
- Quiet hours by recipient time zone if the ESP supports it.
- Broadcasts exclude users currently in a high-intent flow (trial ending) when the broadcast would compete.
Segmentation
Segment on behaviour and lifecycle stage first, demographics second.
-- Example: activated in the last 30 days, never used integrations, consented, not suppressed
SELECT u.id, u.email
FROM users u
WHERE u.marketing_opt_in = true
AND u.email_status = 'deliverable'
AND u.activated_at >= now() - interval '30 days'
AND NOT EXISTS (SELECT 1 FROM events e WHERE e.user_id = u.id AND e.name = 'integration_connected')
AND NOT EXISTS (SELECT 1 FROM suppressions s WHERE s.email = u.email);
Send events to the ESP with stable names and properties (trial_started { plan, trial_end_at })
rather than syncing computed segments nightly; real-time triggers convert better and
stay correct.
Writing each email
- One goal, one primary link or button. Secondary links are fine; competing CTAs are not.
- Subject line states the value or the action; 30-50 characters reads fully on mobile. Preheader extends the subject, it does not repeat it.
- Plain, short body; personal sender name for lifecycle (
Maya at Acme) where the brand allows. - Personalisation tokens always have fallbacks:
{{ first_name | default: "there" }}(Liquid) or the ESP’s equivalent. - Accessible: real text not images of text, alt text on images, 14px+ body, sufficient
contrast, a plain-text part. HTML build and client rendering belong to
email-template-design. - Footer: physical postal address and unsubscribe link (CAN-SPAM), plus preference centre if you have one.
Measurement
- Apple Mail Privacy Protection preloads images, so open rates are inflated and unreliable. Use clicks, click-to-conversion and the goal metric per flow.
- Measure flows against a holdout group (5-10% of eligible users who receive nothing) to know whether the flow causes the behaviour or just coincides with it.
- Track per send: delivered, bounce rate (hard bounces under 2%), complaint rate, unsubscribe rate, click rate, goal conversion.
- Tag links with UTMs consistently (
utm_medium=email,utm_campaign=<flow-slug>); conventions inutm-attribution.
Consent and law (summary, not legal advice)
- US CAN-SPAM: no deceptive headers or subjects, physical address, opt-out honoured within 10 business days.
- EU/UK (GDPR, ePrivacy/PECR): marketing to individuals generally needs prior opt-in consent; soft opt-in for existing customers about similar products in the UK. Keep a record of when and how consent was given.
- Canada CASL: express or implied consent with strict expiry; identification and unsubscribe in every message.
When the program spans jurisdictions or uses purchased data, the user’s lawyer must review. Never send to purchased or scraped lists from the marketing domain.
Sending safely
Any real send (broadcast, flow activation, bulk re-import of subscribers) reaches people and cannot be recalled. Before activating:
- [ ] Recipient count matches the expected segment size (sanity check vs. total list)
- [ ] Suppression list and unsubscribes applied
- [ ] Test sends to seed inboxes (Gmail, Outlook, Apple Mail) look right, links work
- [ ] UTM tags and tracking present
- [ ] User explicitly confirmed the send or activation
Warm a new domain or IP gradually: start with the most engaged recipients and increase daily volume over 2-4 weeks while watching complaint and bounce rates.
Gotchas
- Marketing email sent from the root domain with a bad reputation drags down password
resets on the same domain. Split subdomains (
mail.for marketing,notify.for product). List-Unsubscribeadded by hand in templates but the ESP rewrites headers; verify in the raw message source (Gmail “Show original”).- DMARC
p=rejectbefore fixing all senders (CRM, support desk, invoicing tool) silently drops their mail. - Re-engagement emails to long-dead addresses hit spam traps; sunset instead of reviving.
- Double-sends from overlapping flows; check entry criteria and caps across all flows.
Verification
- Gmail “Show original” on a test send shows
SPF: PASS,DKIM: PASS,DMARC: PASSwith your domain. - One-click unsubscribe works from the Gmail UI link and records suppression.
- Google Postmaster Tools spam rate below 0.1% one week after launch.
- Flow goal conversion beats the holdout group.
Output template
## Email program: <name>
**Streams:** transactional via <ESP/subdomain>, marketing via <ESP/subdomain>
**Auth:** SPF ok / DKIM ok (selector) / DMARC p=<policy>, aligned
| Flow | Trigger | Emails (timing) | Goal | Exit | Holdout |
**Segments:** <definitions>
**Open items needing approval:** DNS changes, first send, legal review What the zip contains
SKILL.md plus the interface file below. Nothing runs on install.
agents/openai.yaml
Gives the Codex app a display name, a one-line description and a starter prompt for this skill.
interface:
display_name: "Email Marketing"
short_description: "Lifecycle email that lands in the inbox"
default_prompt: "$email-marketing Design an onboarding email sequence for new trial users based on our product events" About this skill
Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.