setup-outreach-campaign-smartlead
Set up a complete outbound email campaign in Smartlead: create the campaign, add leads, write a 2-3 email sequence, configure the schedule, and allocate mailboxes.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
| campaign_name | Yes | -- | Name for the campaign (e.g., "Truewind - Accounting Firms - Feb 2026") |
| campaign_goal | Yes | -- | What outcome the campaign drives (book demos, drive signups, etc.) |
| lead_list | Yes | -- | CSV file path OR person-list JSON from upstream skill |
| value_proposition | Yes | -- | Core pain point or benefit the emails address |
| cta | Yes | -- | Call to action (e.g., "Book a 15-min demo", "Reply to learn more") |
| tone | No | semi-formal | Email tone: casual, semi-formal, formal |
| personalization_angle | No | -- | Hook for personalization (event attendance, job posting, news mention) |
| timezone | No | America/New_York | Timezone for send schedule |
| send_days | No | [1,2,3,4,5] | Days of week to send (0=Sun, 6=Sat) |
| start_hour | No | 08:00 | Start of send window |
| end_hour | No | 18:00 | End of send window |
| max_leads_per_day | No | 20 | Max new leads contacted per day |
| min_time_btw_emails | No | 10 | Minutes between emails from same mailbox |
| num_mailboxes | No | 5 | Number of mailboxes to allocate |
| mailbox_selection | No | auto | "auto" (pick free ones) or "manual" (show list to user) |
Setup
Requires a Smartlead account with API access. This skill does not use the Gooseworks proxy — the user must supply their own Smartlead API key.
export SMARTLEAD_API_KEY=your_api_key_here
You can find your API key in the Smartlead dashboard under Settings → API Keys. If SMARTLEAD_API_KEY is not set, ask the user for it before proceeding.
All API calls go to https://server.smartlead.ai/api/v1 with ?api_key=$SMARTLEAD_API_KEY appended.
Rate limit: 10 requests per 2 seconds.
Procedure
Step 1: Gather Campaign Info
Ask the user the following questions. Group them conversationally — don't dump all at once.
Campaign identity:
- "What is the name for this campaign?" (e.g., "Truewind - Accounting Firms - Feb 2026")
- "What is the goal?" (e.g., book demos, drive trial signups, conference follow-up)
Audience & leads:
- "Who is the target audience?" (ICP: title, company type, size, industry)
- "How are you providing the lead list?" — options: CSV file, output from a prior skill (company-contact-finder, luma-event-attendees), or "I need to find leads first" (chain to company-contact-finder)
Messaging:
- "What is the core value proposition or pain point?"
- "What is the call to action?" (e.g., "Book a 15-min demo")
- "What tone — casual, semi-formal, or formal?"
- "Any personalization angle?" (e.g., reference their job posting, event, industry news)
Schedule:
- "What days should emails be sent?" (default: Mon-Fri)
- "What hours and timezone?" (default: 8am-6pm ET)
- "Max new leads per day?" (default: 20)
- "When should the campaign start?" (default: tomorrow)
Mailboxes:
- "How many mailboxes to allocate?" (default: 5)
- "Auto-select free mailboxes, or show me a list to choose from?"
After gathering answers, present a summary and confirm before proceeding.
Step 2: Create the Campaign
POST https://server.smartlead.ai/api/v1/campaigns/create?api_key=$SMARTLEAD_API_KEY
Body:
{
"name": "<campaign_name>",
"client_id": null
}
Response:
{
"ok": true,
"id": 3023,
"name": "Test email campaign",
"created_at": "2022-11-07T16:23:24.025929+00:00"
}
Capture campaign_id from id. All subsequent calls use this.
Step 3: Find and Allocate Mailboxes
This step determines which mailboxes are available and assigns them to the campaign.
3a: Fetch all email accounts
GET https://server.smartlead.ai/api/v1/email-accounts/?api_key=$SMARTLEAD_API_KEY&offset=0&limit=100
Returns a list of all email accounts with id, from_email, from_name, daily_sent_count, warmup_details, is_smtp_success, is_imap_success.
3b: Identify which mailboxes are currently in use
Fetch all campaigns:
GET https://server.smartlead.ai/api/v1/campaigns?api_key=$SMARTLEAD_API_KEY
For each campaign with status = "ACTIVE" or "STARTED", fetch its email accounts:
GET https://server.smartlead.ai/api/v1/campaigns/{campaign_id}/email-accounts?api_key=$SMARTLEAD_API_KEY
Build a set of all email_account_id values currently assigned to active campaigns.
3c: Filter for free mailboxes
A mailbox is "free" if:
- Its
idis NOT in the active-campaign set from 3b is_smtp_success= true ANDis_imap_success= true (account is functional)
Sort free mailboxes by daily_sent_count ascending (prefer coolest/least-used mailboxes).
3d: Select and assign
If mailbox_selection = "auto": select the first N free mailboxes.
If mailbox_selection = "manual": display all accounts as a table (name, email, daily_sent_count, status) and let the user pick.
If fewer than N free mailboxes are available, tell the user: "Only X free mailboxes found. Proceed with X, or pick some currently-in-use mailboxes?"
Assign selected mailboxes:
POST https://server.smartlead.ai/api/v1/campaigns/{campaign_id}/email-accounts?api_key=$SMARTLEAD_API_KEY
Body:
{
"email_account_ids": [101, 204, 305, 412, 518]
}
Step 4: Ingest Leads
4a: Parse the lead list
From CSV: Read the file, map columns to Smartlead fields. Flexible column matching:
email(required) — also matchesEmail,email_addressfirst_name— also matchesfirstname,first,First Namelast_name— also matcheslastname,last,Last Namecompany_name— also matchescompany,organization,Company- Any extra columns become
custom_fields
From upstream skill (person-list JSON): Map fields:
first_name <- name.split()[0]
last_name <- name.split()[1:]
email <- email
company_name <- company
custom_fields <- { "title": title, "linkedin_url": linkedin_url }
4b: Validate and deduplicate
- Remove rows without a valid email
- Deduplicate by email (keep first occurrence)
- Report: total rows, valid, invalid, duplicates removed
4c: Upload in batches
Smartlead accepts max 100 leads per call. Chunk the list and call for each batch:
POST https://server.smartlead.ai/api/v1/campaigns/{campaign_id}/leads?api_key=$SMARTLEAD_API_KEY
Body:
{
"lead_list": [
{
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"company_name": "Acme Corp",
"custom_fields": {"title": "CFO"}
}
],
"settings": {
"ignore_global_block_list": false,
"ignore_unsubscribe_list": false,
"ignore_duplicate_leads_in_other_campaign": false
}
}
Response:
{
"ok": true,
"upload_count": 95,
"total_leads": 100,
"already_added_to_campaign": 2,
"duplicate_count": 1,
"invalid_email_count": 2,
"unsubscribed_leads": 0
}
Report totals across all batches to the user.
Step 5: Craft the Email Sequence
Write a 2-3 email sequence based on the user's inputs from Step 1. Default structure:
Email 1 — Cold intro (Day 0)
- Subject: short, curiosity-driven or relevant to their pain
- Body: 3-5 sentences. Acknowledge their world, surface the problem, introduce the solution briefly, clear CTA
- Personalize with
{{first_name}}and any custom fields
Email 2 — Follow-up (Day 3)
- Subject: different angle (metric, case study, specific outcome)
- Body: 2-4 sentences. Add value, restate CTA
- Leave subject blank to send as same-thread reply
Email 3 — Breakup (Day 8)
- Subject: brief, direct ("Still relevant?", "Closing the loop")
- Body: 2-3 sentences. Acknowledge they're busy, keep door open, soft CTA
Present the full sequence to the user as a formatted table. Wait for approval or edits.
After user approves,