--- title: "Campaign Setup Guide" description: "Learn how to create, configure, and optimize email campaigns — from sequences and A/B testing to scheduling, email account rotation, and advanced settings" --- ## Overview A SmartLead campaign is the core unit of outbound email. It ties together your email accounts, sequences, leads, and sending schedule into a single automated workflow. This guide covers everything you need to configure a campaign programmatically. ## Campaign Architecture Every campaign has four building blocks: 1. **Email Accounts** — The sending addresses that rotate automatically 2. **Sequences** — The emails and follow-ups your leads receive 3. **Leads** — The prospects imported into the campaign 4. **Schedule** — When and how fast emails are sent ``` Campaign ├── Email Accounts (1+) ├── Sequences │ ├── Step 1 (Initial email) │ │ ├── Variant A │ │ └── Variant B (optional A/B test) │ ├── Step 2 (Follow-up, +3 days) │ └── Step 3 (Break-up, +5 days) ├── Leads (up to 400 per import) └── Schedule (timezone, days, hours) ``` ## Creating a Campaign ```python Python import requests import os API_KEY = os.getenv("SMARTLEAD_API_KEY") BASE_URL = "https://server.smartlead.ai/api/v1" campaign_payload = { "name": "Q1 SaaS Outreach — VP Sales", "track_settings": { "track_open": True, "track_click": True } } response = requests.post( f"{BASE_URL}/campaigns/create", params={"api_key": API_KEY}, json=campaign_payload ) campaign = response.json() campaign_id = campaign["campaign"]["id"] print(f"Campaign created: ID {campaign_id}") ``` ```javascript JavaScript const API_KEY = process.env.SMARTLEAD_API_KEY; const BASE_URL = 'https://server.smartlead.ai/api/v1'; const response = await fetch(`${BASE_URL}/campaigns/create?api_key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Q1 SaaS Outreach — VP Sales', track_settings: { track_open: true, track_click: true } }) }); const campaign = await response.json(); const campaignId = campaign.campaign.id; console.log(`Campaign created: ID ${campaignId}`); ``` Use descriptive campaign names that include the quarter, ICP, and persona. This makes it easier to filter and compare performance later. Example: `Q1 SaaS Outreach — VP Sales — US`. ## Building Sequences Sequences define the emails your leads receive and the timing between them. Each step can optionally include A/B test variants. ### Basic Sequence ```python Python sequences_payload = { "sequences": [ { "seq_number": 1, "subject": "Quick question about {{company_name}}", "email_body": """Hi {{first_name}}, I noticed {{company_name}} is scaling its outbound — are you exploring ways to improve reply rates? We help {{industry}} companies like yours book 3x more meetings through automated cold email. Worth a 15-minute call this week? Best, Sarah""", "seq_delay_details": {"delay_in_days": 0} }, { "seq_number": 2, "subject": "Re: Quick question about {{company_name}}", "email_body": """Hi {{first_name}}, Following up — I wanted to share a case study from a {{industry}} company that went from 2% to 14% reply rates in 30 days. Happy to walk through what they did if you have 10 minutes. Sarah""", "seq_delay_details": {"delay_in_days": 3} }, { "seq_number": 3, "subject": "Re: Quick question about {{company_name}}", "email_body": """Hi {{first_name}}, Don't want to be a pest — just checking if improving outbound pipeline is a priority for {{company_name}} right now. If the timing isn't right, no worries. Happy to reconnect next quarter. Best, Sarah""", "seq_delay_details": {"delay_in_days": 5} } ] } response = requests.post( f"{BASE_URL}/campaigns/{campaign_id}/sequences", params={"api_key": API_KEY}, json=sequences_payload ) print("Sequences created!") ``` ### Personalization Variables Use double curly braces to insert lead-specific data into your emails: | Variable | Description | Source | |---|---|---| | `{{first_name}}` | Lead's first name | Lead import | | `{{last_name}}` | Lead's last name | Lead import | | `{{email}}` | Lead's email address | Lead import | | `{{company_name}}` | Company name | Lead import | | `{{location}}` | Lead's location | Lead import | | `{{custom_field_name}}` | Any custom field | `custom_fields` on import | If a personalization variable is missing for a lead, SmartLead will leave the placeholder blank. Use fallback values in your copy to handle this gracefully — for example, write "your team" as a fallback for `{{company_name}}`. ### A/B Testing Variants Test different subject lines or email bodies to optimize performance: ```python Python sequences_with_variants = { "sequences": [ { "seq_number": 1, "subject": "Quick question about {{company_name}}", "email_body": "Hi {{first_name}},\n\nI noticed {{company_name}} is scaling...", "seq_delay_details": {"delay_in_days": 0}, "variants": [ { "subject": "{{first_name}}, quick thought on {{company_name}}", "email_body": "Hey {{first_name}},\n\nSaw that {{company_name}} is growing fast...", "variant_distribution": 50 } ] } ] } response = requests.post( f"{BASE_URL}/campaigns/{campaign_id}/sequences", params={"api_key": API_KEY}, json=sequences_with_variants ) ``` SmartLead automatically splits traffic between variants and tracks open/reply rates for each. Test one variable at a time (subject line OR body, not both) so you can isolate what drives performance. Run tests for at least 200 sends before drawing conclusions. ## Linking Email Accounts Connect one or more email accounts to your campaign. SmartLead rotates between them automatically to maximize deliverability. ```python Python # Link existing email accounts by their IDs response = requests.post( f"{BASE_URL}/campaigns/{campaign_id}/email-accounts", params={"api_key": API_KEY}, json={"email_account_ids": [101, 102, 103]} ) print("Email accounts linked!") ``` ### Fetching Available Accounts ```python Python # List all email accounts response = requests.get( f"{BASE_URL}/email-accounts", params={"api_key": API_KEY} ) accounts = response.json() for account in accounts: print(f"ID: {account['id']} | {account['from_email']} | Warmup: {account['warmup_enabled']}") ``` Only link accounts that have been warmed up for at least 14 days. Sending cold emails from a fresh account will hurt your deliverability and sender reputation. See the [Email Warmup Guide](/guides/email-warmup) for details. ## Configuring the Schedule Control when emails are sent and how many go out per day: ```python Python schedule_payload = { "timezone": "America/New_York", "days_of_the_week": [1, 2, 3, 4, 5], # Monday-Friday "start_hour": "09:00", "end_hour": "17:00", "min_time_btw_emails": 8, # Minutes between emails "max_new_leads_per_day": 30 # New leads contacted per day } response = requests.post( f"{BASE_URL}/campaigns/{campaign_id}/schedule", params={"api_key": API_KEY}, json=schedule_payload ) print("Schedule configured!") ``` | Parameter | Description | Recommended | |---|---|---| | `timezone` | IANA timezone for send window | Match your leads' timezone | | `days_of_the_week` | 1=Mon through 7=Sun | `[1,2,3,4,5]` (weekdays) | | `start_hour` | Earliest send time | `"08:00"` - `"10:00"` | | `end_hour` | Latest send time | `"16:00"` - `"18:00"` | | `min_time_btw_emails` | Gap between sends (minutes) | `5` - `12` | | `max_new_leads_per_day` | Daily new lead cap | `20` - `50` per account | ## Campaign Settings ### Track Settings ```python Python # Update tracking settings response = requests.patch( f"{BASE_URL}/campaigns/{campaign_id}/settings", params={"api_key": API_KEY}, json={ "track_settings": { "track_open": True, "track_click": True } } ) ``` ### Stop Conditions Automatically stop emailing a lead when certain events occur: ```python Python settings_payload = { "stop_lead_settings": { "stop_on_reply": True, "stop_on_auto_reply": False, "stop_on_click": False } } response = requests.patch( f"{BASE_URL}/campaigns/{campaign_id}/settings", params={"api_key": API_KEY}, json=settings_payload ) ``` Always enable `stop_on_reply`. Continuing to send follow-ups after someone replies creates a poor experience and can increase spam complaints. ## Activating the Campaign Once everything is configured, set the campaign status to `ACTIVE`: ```python Python response = requests.post( f"{BASE_URL}/campaigns/{campaign_id}/status", params={"api_key": API_KEY}, json={"status": "ACTIVE"} ) print("Campaign is now ACTIVE!") ``` ### Campaign Statuses | Status | Description | |---|---| | `DRAFTED` | Campaign created but not yet active | | `ACTIVE` | Currently sending emails on schedule | | `PAUSED` | Temporarily stopped; can be resumed | | `COMPLETED` | All leads have received all sequences | | `STOPPED` | Manually stopped; leads won't receive more emails | ```python Python # Pause a campaign requests.post( f"{BASE_URL}/campaigns/{campaign_id}/status", params={"api_key": API_KEY}, json={"status": "PAUSED"} ) ``` ## Monitoring Campaign Performance Track your campaign's performance with the analytics endpoints: ```python Python # Get campaign analytics response = requests.get( f"{BASE_URL}/campaigns/{campaign_id}/analytics", params={"api_key": API_KEY} ) analytics = response.json() print(f"Sent: {analytics.get('total_sent', 0)}") print(f"Opened: {analytics.get('total_opened', 0)}") print(f"Replied: {analytics.get('total_replied', 0)}") print(f"Bounced: {analytics.get('total_bounced', 0)}") ``` ### Key Metrics to Watch | Metric | Good | Warning | Action Needed | |---|---|---|---| | Open Rate | > 50% | 30–50% | < 30% — fix subject lines or deliverability | | Reply Rate | > 5% | 2–5% | < 2% — improve copy or targeting | | Bounce Rate | < 3% | 3–5% | > 5% — verify email list quality | | Unsubscribe Rate | < 0.5% | 0.5–1% | > 1% — review targeting and frequency | ## Troubleshooting Check these in order: (1) Email accounts are linked and warmed up, (2) the schedule window includes the current day and time, (3) leads have been imported and are in "Not Contacted" status, (4) email accounts haven't hit their daily sending limit. Verify your lead list quality. Use an email verification service before importing leads. Check that your email accounts' DNS records (SPF, DKIM, DMARC) are properly configured. Consider reducing your daily sending volume. Test different subject lines with A/B testing. Check your sender reputation using tools like mail-tester.com. Ensure your email accounts are properly warmed up. Avoid spam trigger words in subject lines. Verify that the delay days are set correctly between steps. Check if `stop_on_reply` or other stop conditions are triggering. Ensure the campaign status is still ACTIVE. ## What's Next? Warm up accounts before adding them to campaigns Import, segment, and manage leads at scale Optimize deliverability, copy, and campaign structure Get real-time notifications for campaign events