Creating Campaigns
Campaigns are multi-step cold email sequences that automatically send to your leads based on schedules, conditions, and mailbox rotation. This guide walks you through creating your first campaign.
Prerequisites
- At least one active mailbox with tested SMTP credentials
- At least one lead list with uploaded contacts
Creating a Campaign (Dashboard)
Navigate to Campaigns
From the dashboard sidebar, click Campaigns → New Campaign.
Configure campaign settings
Set the following:
- Name — Internal name for your reference
- Timezone — Used for send window enforcement (default: UTC)
- Send Window — Start/end hours (e.g., 09:00 – 17:00)
- Send Days — Which days to send (e.g., Monday–Friday = 1,2,3,4,5)
- AI Auto-Reply — Toggle ON to auto-respond when leads reply
- AI Context — Prompt telling the AI about your product/goals
- Scheduled Start — Optional future date/time to begin sending
Add sequence steps
Add one or more email steps. Each step supports:
- Subject — Primary subject line (with personalization variables)
- Subject Variants — Additional subject lines for A/B rotation
- Body — HTML email content with variables and spintax
- Body Variants — Additional body versions for rotation
- Delay Days / Hours — Wait time before this step (after previous)
- Condition — When to send:
not_replied,replied,not_opened,opened - Is Reply — Thread this step as a reply (adds Re: prefix, In-Reply-To header)
Assign mailboxes
Select the mailbox accounts to use for sending. The dispatcher rotates between them using round-robin — picks the mailbox with the lowest sent_today that's under its daily limit.
Add leads to the campaign
Assign leads from your uploaded lists to this campaign. Only leads that are not bounced, unsubscribed, or blocklisted will receive messages.
Start the campaign
Click Start to activate. The dispatcher will begin sending when the next send window opens (or immediately if within window). Requirements to start:
- At least 1 step must exist
- At least 1 mailbox must be assigned
Creating via API
# Step 1: Create the campaign
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/campaigns \
-H "Content-Type: application/json" \
-H "Cookie: auth_token=YOUR_JWT_TOKEN" \
-d '{
"name": "Q2 Outreach",
"timezone": "America/New_York",
"send_window_start": "09:00",
"send_window_end": "17:00",
"send_days": "1,2,3,4,5",
"ai_auto_reply": true,
"ai_context": "We sell project management software. Be helpful and concise."
}'
# Step 2: Add a step
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/campaigns/CAMPAIGN_ID/steps \
-H "Content-Type: application/json" \
-H "Cookie: auth_token=YOUR_JWT_TOKEN" \
-d '{
"step_type": "email",
"subject": "Hey {{first_name}}, quick question",
"subject_variants": ["{{first_name}} — saw your work at {{company}}"],
"body": "<p>Hi {{first_name}},</p><p>{I noticed|I saw} your work at {{company}}...</p>",
"delay_days": 0,
"condition": "not_replied"
}'
# Step 3: Assign mailboxes
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/campaigns/CAMPAIGN_ID/mailboxes \
-H "Content-Type: application/json" \
-H "Cookie: auth_token=YOUR_JWT_TOKEN" \
-d '{"mailbox_ids": ["MAILBOX_UUID_1", "MAILBOX_UUID_2"]}'
# Step 4: Start
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/campaigns/CAMPAIGN_ID/start \
-H "Cookie: auth_token=YOUR_JWT_TOKEN"Campaign Lifecycle
| Status | Behavior |
|---|---|
draft | Not processing — safe to edit steps and settings |
active | Dispatcher is sending to leads per schedule |
paused | Stopped — can be resumed, leads retain their position |
If hard bounce rate exceeds 5% (after 100+ sends), the campaign is automatically paused to protect sender reputation. Fix your list quality before resuming.
How the Dispatcher Works
The campaign dispatcher runs as a periodic Asynq task and:
- Finds leads with
next_send_at <= now(usesFOR UPDATE SKIP LOCKEDto prevent races) - Checks campaign is active and within its send window (timezone-aware)
- Checks scheduled start time (skips if not yet time)
- Picks the mailbox with lowest
sent_todayunder its effective limit - Checks blocklist (email + domain level)
- Picks subject/body variant (deterministic based on lead email hash)
- Renders spintax + variable substitution
- Builds threading headers for follow-ups (In-Reply-To, References)
- Injects tracking pixel + unsubscribe link
- Sends via SMTP with human-mimicry delay (30–90 seconds between sends)
- On success: advances lead to next step, updates stats
- On hard bounce: blocklists lead, pauses campaign if rate > 5%
- On soft bounce: retries in 4 hours