
Campaign Sending
- 40 installs
- 104 repo stars
- Updated July 1, 2026
- extruct-ai/gtm-skills
Helps with ai & agent building tasks.
About
campaign-sending is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- campaign-sending
- AI & Agent Building
- AI-coding skill
Campaign Sending by the numbers
- 40 all-time installs (skills.sh)
- Ranked #8,266 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 campaign-sendingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 40 |
|---|---|
| repo stars | ★ 104 |
| Last updated | July 1, 2026 |
| Repository | extruct-ai/gtm-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Run Campaign
Upload finalized emails for sequencing and sending.
Environment
Provider selection and credentials are handled in Step 0 of the workflow.
Workflow
Step 0: Confirm provider and learn API
1. Ask the user which email sequencing provider they want to use. If they're unsure, pre-configured options with local reference docs are available in references/. 2. Fetch or read the provider's API documentation and identify:
- Campaign/sequence creation endpoint
- Lead upload endpoint and schema
- Deduplication options
- Custom variable / personalization support
- Authentication method and credentials
- Throughput limits and upload constraints
3. Ask for their API credentials and confirm access 4. Plan the field mapping based on the provider's lead schema and confirm with the user before proceeding
Step 1: Read and analyze final emails
Load the finalized email CSV (output from email-generation). Read the CSV headers to discover all available columns. Verify required columns exist (email, first_name, company_name, company_domain). Identify all content columns (paragraph fields, hypothesis, tier, etc.) that will need to be mapped to the provider's variables.
Step 2: Check DNC list
Read the context file and remove any domains on the DNC list. Report how many were removed.
Step 3: Create or find campaign
Using the chosen provider's API:
- List existing campaigns
- Create a new campaign if needed (suggest name based on vertical + date)
Ask the user to specify the campaign based on region and time zone — leads in different regions/time zones should go into separate campaigns so sending schedules align with recipients' local business hours.
Ask the user: use an existing campaign or create a new one?
Step 4: Map fields to provider lead schema
Analyze the CSV headers discovered in Step 1 and create corresponding fields in the provider:
1. Map email, first_name, last_name, company_name, company_domain to the provider's standard lead fields 2. For every remaining column in the CSV, create a matching custom variable / personalization field in the provider 3. Present the full mapping to the user and confirm before uploading
Step 5: Upload leads in batches
Upload via the provider's API in batches (respect rate limits from Step 0). Enable deduplication if the provider supports it.
Report: uploaded count, skipped (dedup) count, total attempted.
Step 6: Pre-send verification checklist
Present this checklist to the user BEFORE they activate the campaign:
## Pre-Send Verification Checklist
Campaign: [name]
Leads uploaded: [N]
Leads skipped (dedup): [N]
### Verify in your sequencer:
- [ ] **Email accounts connected** — at least 2-3 sending accounts are linked and warmed
- [ ] **Sending schedule set** — check timezone, sending hours, daily limits
- [ ] **Email sequence configured** — first email + follow-up(s) are set up in the campaign
- [ ] **Custom variables working** — preview 3-5 emails to confirm {{variables}} render correctly
- [ ] **Unsubscribe link present** — required for compliance
- [ ] **DNC list checked** — confirm no blacklisted domains made it through
- [ ] **Reply handling set** — auto-stop sequence on reply is enabled
- [ ] **Warmup active** — sending accounts have adequate warmup history
### Sample emails to spot-check:
[Show 3 random emails from the upload for the user to visually verify]Step 7: Remind about manual activation
Never auto-activate a campaign. Always tell the user:
"Leads are uploaded. Please review the campaign in your sequencer, check the sequence and sending settings, then manually activate when ready. I will not start the campaign automatically."
After Sending: Feedback Loop
After the campaign has been running (typically 1-2 weeks), prompt the user to run the feedback loop:
1. Export results from the sequencer (opens, replies, bounces) 2. Run context-building in feedback loop mode to update Campaign History 3. Use results to refine hypotheses and improve future campaigns
API Reference
Pre-configured provider docs in references/ directory. For other providers, docs are fetched during Step 0.
Instantly API Reference
Base URL: https://api.instantly.ai/api/v2 Auth: Bearer token via INSTANTLY_API_KEY environment variable.
Campaigns
List campaigns
GET /campaigns?limit=100&skip=0Response:
{
"items": [
{
"id": "campaign-uuid",
"name": "Campaign Name",
"status": "active" | "paused" | "draft" | "completed"
}
]
}Create campaign
POST /campaignsBody:
{
"name": "PE Rollup - Blue Collar - 2026-03"
}Response: { "id": "campaign-uuid", "name": "..." }
Get campaign
GET /campaigns/{campaign_id}Leads
Upload leads
POST /leadsBody:
{
"campaign_id": "campaign-uuid",
"skip_if_in_workspace": true,
"leads": [
{
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Doe",
"company_name": "Acme Corp",
"personalization": "First paragraph text here",
"website": "acme.com",
"custom_variables": {
"second_paragraph": "...",
"third_paragraph": "...",
"fourth_paragraph": "...",
"hypothesis": "Database blind spot"
}
}
]
}Response:
{
"uploaded": 95,
"skipped": 5
}Dedup options:
skip_if_in_workspace: true— skip if email exists in ANY campaignskip_if_in_campaign: true— skip only if in THIS campaign- Default (both false): always upload
Batch size: Max 100 leads per request.
List leads in campaign
GET /leads?campaign_id={id}&limit=100&skip=0Delete lead
DELETE /leads/{lead_id}Campaign Analytics
Get campaign summary
GET /campaigns/{campaign_id}/analytics/overviewResponse:
{
"total_leads": 500,
"contacted": 450,
"emails_sent": 1200,
"opens": 380,
"replies": 42,
"bounces": 15,
"unsubscribes": 3
}Get lead status
GET /leads?campaign_id={id}&status=repliedStatus values: not_yet_contacted, contacted, replied, bounced, unsubscribed, interested, not_interested, meeting_booked
Email Accounts
List accounts
GET /email-accounts?limit=100Check warmup status
GET /email-accounts/{account_id}Look for warmup_status and reputation_score in response.
Rate Limits
- 10 requests per second
- 100 leads per upload request
- Add 0.5s pause between consecutive uploads
Custom Variables in Email Templates
In the Instantly email template editor, reference custom variables as:
{{personalization}} → first paragraph (maps to lead.personalization)
{{second_paragraph}} → from custom_variables
{{third_paragraph}} → from custom_variables
{{fourth_paragraph}} → from custom_variables
{{first_name}} → lead first name
{{company_name}} → lead company nameTypical Email Template in Instantly
Hey {{first_name}},
{{personalization}}
{{second_paragraph}}
{{third_paragraph}}
{{fourth_paragraph}}This maps cleanly to the P1-P4 structure from email-generation.