
Email Generation
- 42 installs
- 104 repo stars
- Updated July 1, 2026
- extruct-ai/gtm-skills
Helps with ai & agent building tasks.
About
email-generation is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- email-generation
- AI & Agent Building
- AI-coding skill
Email Generation by the numbers
- 42 all-time installs (skills.sh)
- Ranked #8,070 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 31, 2026 (Skillselion catalog sync)
npx skills add https://github.com/extruct-ai/gtm-skills --skill email-generationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 42 |
|---|---|
| repo stars | ★ 104 |
| Last updated | July 1, 2026 |
| Repository | extruct-ai/gtm-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Email Generation
Generate cold outreach emails from a contact CSV + prompt template. The prompt template is self-contained — it has all voice, research, value prop, proof points, and personalization rules baked in. This skill just runs it per row.
Architectural Principle
This skill is a runner, not a reasoner. All strategic reasoning (voice, value angles, proof points, research data) was done by the email-prompt-building skill at prompt-build time and embedded in the prompt template. This skill reads the prompt + CSV and generates emails. It does NOT read the context file, hypothesis set, or research files.
prompt template (.md) ─┐
├──▶ generate email per row ──▶ emails CSV
contact CSV ───────────┘Inputs Required
| Input | Source | Required |
|---|---|---|
| Contact CSV | File with recipient data + enrichment columns | yes |
| Prompt template | .md file from email-prompt-building skill | yes |
That's it. No context file, no hypothesis set, no research files.
Contact CSV Columns
The prompt template specifies which columns it needs. Check the prompt's "Enrichment data fields" section for the expected column names. Common columns:
Required (always):
first_name,last_name,company_name,job_title
Enrichment (campaign-specific): Listed in the prompt template. If the prompt references a field that's not in the CSV, the email quality degrades. Check column alignment before running.
Name Sanitization
Before generating emails, run scripts/sanitize-names.py on the contact CSV:
python3 scripts/sanitize-names.py <contact.csv> [output.csv]The script strips titles (Dr, Prof, etc.), removes rows with single-character names, emoji, junk values (N/A, Test, -), and fixes all-caps casing. It outputs a *_sanitized.csv and prints what was cleaned/removed.
Review the removed rows before proceeding. Do not generate emails for rows with invalid names.
Running the Generator
Script-first, not in-context. Always generate via a script that calls the API per contact. Never generate emails inside the conversation — it's slow, expensive, and impossible to rerun after prompt edits.
Step 1: Dry run
Before spending API credits, show the user a dry run: 1. Read the prompt template and contact CSV 2. For 2-3 sample contacts, display exactly what data will be passed (all enrichment fields, hypothesis match, structural variant selection) 3. Ask the user to confirm the data looks correct before proceeding 4. If enrichment fields are missing or misaligned, flag it and stop
Step 2: Generate via script
Write a generation script that reads the prompt template + contact CSV, calls the API per row, and writes output files. See references/generation-script.md for the script template and implementation details.
Adapt the script to the user's API setup (Anthropic, OpenAI, etc.) and the specific prompt format.
Step 3: Output both CSV and MD
Always generate two output files:
claude-code-gtm/csv/output/{campaign-slug}/emails.csv— for upload to sequencerclaude-code-gtm/csv/output/{campaign-slug}/emails.md— for human review (one email per section, with contact name and company as headers)
Quality Checks
After generating, verify:
- [ ] Every email is within the word limit specified in the prompt
- [ ] No banned phrases from the prompt template appear
- [ ] Enrichment data was actually used — not just generic text
- [ ] Example queries in P2 are specific to each recipient's verticals
- [ ] Proof points vary across emails (not the same PS for everyone)
- [ ] Subject lines meet the prompt's length constraints
Segmentation-Aware Generation
When the contact CSV includes segmentation data (from list-segmentation):
Tier 1 companies:
- Generate individually with full attention to enrichment data
- Route through
email-response-simulationfor review before sending
Tier 2 companies:
- Group by
hypothesis_number - Generate in batches within each hypothesis group
- Spot-check 2-3 from each group
Tier 3 companies:
- Do not generate emails
- Route back to
list-enrichmentorlist-building
Feedback Loop
When the user gives feedback on generated emails, the workflow is always:
1. User identifies what's wrong (tone, structure, missing data, wrong angle) 2. Update the prompt template — the fix must be systemic, never a one-off edit 3. Rerun the script with the updated prompt 4. Review the new output
Never hand-edit individual emails. If one email is bad, the prompt is bad — fix the source. Track changes made to the prompt so the user can see the evolution.
Building a New Prompt Template
If no prompt template exists for this campaign, use the email-prompt-building skill to build one. That skill reads the context file and research, then synthesizes a self-contained prompt. Do not build prompts ad hoc in this skill.
Generation Script Template
Python script that reads a prompt template + contact CSV, calls the LLM API per row, and writes emails to CSV and MD.
Usage
python3 generate_emails.py \
--prompt prompts/{vertical}/en_first_email.md \
--contacts csv/input/{campaign}/contacts.csv \
--output csv/output/{campaign}/emails \
[--enrichment csv/input/{campaign}/enrichment.csv]Script structure
#!/usr/bin/env python3
"""
Email generation script.
Reads a prompt template + contact CSV, calls the API per row,
writes emails to CSV and MD.
"""
import csv, json, os, sys, argparse
from pathlib import Path
# 1. Parse arguments: --prompt, --contacts, --output, --enrichment (optional)
# 2. Read the prompt template as the system/user prompt
# 3. Read the contact CSV into a list of dicts
# 4. If --enrichment is provided, merge enrichment data by matching key (e.g., company_name or email)
# 5. For each CSV row:
# a. Format the row data as JSON
# b. Append to the prompt as the per-contact context
# c. Call the API and parse the JSON response
# d. Accumulate the result
# e. Print progress (row N/total, company name, subject line)
# 6. Write all results to CSV (for sequencer upload)
# 7. Write all results to MD (for human review, one email per section)Output format
CSV columns: recipient_name, recipient_company, email, subject, body
MD format:
# Campaign: {campaign-slug}
## 1. {recipient_name} — {recipient_company}
**Subject:** {subject}
{body}
---Adapting to API provider
- Anthropic: use
anthropicSDK,client.messages.create() - OpenAI: use
openaiSDK,client.chat.completions.create()
Set the prompt template as the system message. Pass each contact row as the user message. Parse the JSON response for subject + body.