← Back to Tutorials
Tutorials beginner Elena Torres ·

Build an AI Sales Agent with n8n — Step-by-Step Guide 2026

Build an AI Sales Agent with n8n — Step-by-Step Guide 2026

What You’ll Learn

By the end of this tutorial, you’ll have built a complete AI sales agent that:

  • Scrapes prospect lists from Apollo.io or LinkedIn Sales Navigator
  • Researches each prospect using web search + Perplexity
  • Generates hyper-personalized cold email copy with GPT-4o
  • Handles replies autonomously (objections, follow-ups, FAQs)
  • Books qualified meetings into Calendly or HubSpot

Prerequisites: n8n instance (self-hosted or cloud), OpenAI API key, basic familiarity with the n8n visual editor.

Step 1: Set Up Your n8n Environment

Start by creating a new workflow in n8n named AI Sales Agent v1. Configure the following credential variables:

  • OPENAI_API_KEY — GPT-4o for email generation and reply classification
  • OPENAI_API_KEY_EMBED — text-embedding-3-small for prospect vector storage
  • PERPLEXITY_API_KEY — for company deep-research nodes
  • APOLLO_API_KEY — (optional) for prospect import
  • SMTP_CREDENTIALS — for sending emails
  • HUBSPOT_API_KEY or CALENDLY_API_KEY — for meeting booking

In n8n, store these under Settings → Credentials → OpenAI / HTTP Request for secure access.

Step 2: Build the Prospect Ingestion Pipeline

Add an n8n Schedule Trigger set to run daily at 08:00.

Chain it to an HTTP Request node hitting the Apollo.io GraphQL endpoint:

POST https://api.apollo.io/api/v1/mixed_people/search
Headers: { "X-Api-Key": "{{$credentials.apollo.apiKey}}" }
Body: {
  "q_organization_domains": ["fintech-startups.com"],
  "person_seniorities": ["vp", "director", "head"],
  "limit": 50
}

Parse the response with an Item Lists → Extract from Array node. For each prospect (first_name, last_name, email, company, title), pass the data into the next stage.

Pro tip: If you don’t have Apollo, replace this with a Google Sheets trigger that watches a “Lead Import” sheet — just paste names and companies.

Step 3: Research Each Prospect with AI

Add a Loop Over Items node (batch size 5, parallelism 3) to process prospects without hitting rate limits.

Inside the loop, place two nodes:

Node A — Perplexity Company Deep Research (HTTP Request):

POST https://api.perplexity.ai/chat/completions
Headers: { "Authorization": "Bearer {{$credentials.perplexity.apiKey}}" }
Body: {
  "model": "sonar-pro",
  "messages": [
    {"role": "system", "content": "Research this company and prospect. Return JSON with: company_mission, recent_news, funding_round, competitor_landscape, growth_challenge."},
    {"role": "user", "content": "Company: {{$json.company}}. Prospect: {{$json.first_name}} {{$json.last_name}}, title: {{$json.title}}"}
  ],
  "response_format": {"type": "json_object"}
}

Node B — OpenAI Research Summarizer:

// Code node — enrich prospect data with AI analysis
const research = $input.first().json.research_output;

const prompt = `Based on this research:
${JSON.stringify(research)}

Write a 3-sentence summary of:
1. What the company urgently needs
2. Why the prospect would care about our AI sales platform
3. The specific pain point to address in the email

Prospect title: ${$json.title}
Company: ${$json.company}`;

// Call OpenAI via n8n's AI node or HTTP Request
// Store result as $json.personalized_angle

Step 4: Generate Personalized Email Copy

Add an OpenAI Chat Model node with GPT-4o. Use this system prompt:

You are a senior B2B sales copywriter. Write a cold email to a prospect.
Rules:
- Max 120 words
- Lead with the prospect's specific challenge (from research)
- Reference a real company milestone or news item
- One specific value proposition (not generic "increase efficiency")
- End with a soft CTA: "Worth 10 minutes to discuss?"
- Never sound templated
- Tone: confident, helpful, peer-level

The user message injects the prospect data:

To: {{$json.first_name}} {{$json.last_name}}
Title: {{$json.title}}
Company: {{$json.company}}
Personalized angle: {{$json.personalized_angle}}

Output the email body into $json.email_body. Add a Wait node (300 seconds) between batches to respect sending limits.

Add a secondary Code node for subject line generation using the same research context:

// Generate 5 subject line variants
const subjects = [
  `{{$json.company}}'s ${$json.recent_news_topic} — a thought`,
  `Quick question re: ${$json.challenge_area}`,
  `Idea for {{$json.company}}'s ${$json.goal_area}`,
  `${$json.first_name}, saw your recent ${$json.news_item}`,
  `{{$json.company}} + ${$json.pain_point}?`
];
return subjects.map(s => ({ subject: s }));

Step 5: Send and Track

Connect the email body to an Email (SMTP) node:

From: you@yourcompany.com
To: {{$json.email}}
Subject: {{$json.subject}}
Body (HTML): {{$json.email_body}}

Add a HubSpot or n8n Database node to log:

  • prospect_email, sent_at, email_body_preview, subject_variant
  • A unique reply_tracking_id in the email footer: {{$json.email}}|{{$json.reply_tracking_id}}

For higher deliverability, set up a custom tracking domain in your email provider (e.g., track.yourdomain.com) and configure SPF/DKIM records.

Step 6: Handle Replies with AI Classification

This is where the agent gets autonomous. Add a Gmail Trigger (or IMAP node) that watches for replies.

Pass each reply into an OpenAI Chat Model node with this classifier prompt:

Classify this email reply into one category:
- "not_interested" — polite decline, unsubscribe request
- "interested" — asks for demo, pricing, more info
- "objection" — raises concerns (budget, timing, competitor)
- "out_of_office" — auto-reply
- "unrelated" — bounced or wrong person

Reply: {{$json.email_body}}

Respond with JSON: {"category": "...", "confidence": 0.0-1.0, "brief_reason": "..."}

Based on the classification, route the workflow:

  • interestedCalendly node to send meeting booking link
  • objectionOpenAI node with objection-handling prompt, then SMTP to send the response. Log objection type to a Google Sheet for sales team review.
  • not_interestedSMTP with gentle goodbye, mark prospect as “cold” in DB, set 90-day re-engagement timer via n8n Wait node.
  • out_of_officeWait 7 days then re-deliver the original email
  • unrelated → forward to human sales rep via Slack webhook

Step 7: Meeting Booking Automation

For interested prospects, use the HTTP Request node with Calendly’s API:

POST https://api.calendly.com/scheduling_links
Headers: {
  "Authorization": "Bearer {{$credentials.calendly.apiKey}}",
  "Content-Type": "application/json"
}
Body: {
  "max_event_count": 1,
  "owner": "https://api.calendly.com/users/YOUR_USER_UUID",
  "owner_type": "EventType",
  "event_type_uuid": "YOUR_EVENT_TYPE_UUID"
}

Include a personalized calendar link in a follow-up email:

Subject: Let's find a time — {{$json.first_name}}?

Body:

Hi {{$json.first_name}},

Great to hear you're interested. I've heard similar challenges from {{$json.company_reference_company}} before they adopted our solution.

Here's my calendar — grab any slot that works:

{{$json.calendly_link}}

Looking forward to it.

Best,
[Your Name]

After booking, trigger an n8n Webhook to Slack notifying your sales team:

Channel: #sales-leads
Message: "🎯 *Hot lead booked!*\nProspect: {{$json.first_name}} {{$json.last_name}}\nCompany: {{$json.company}}\nTime: {{$json.meeting_time}}\nAngle used: {{$json.personalized_angle}}"

Best Practices

  • Start with 5–10 prospects per day. Tune your email copy and objection handling before scaling to 50+.
  • A/B test subject lines. Use a random number node to cycle through 3 variants per prospect batch. Track open rates via your email provider.
  • Review objection logs weekly. The most common objections should become new branches in your workflow. If “budget” appears >20% of the time, adjust your targeting criteria.
  • Use a warmup tool. Integrate with Mailwarm or Lemwarm before cold-sending at scale — free email providers will throttle new domains hard.
  • Keep a human in the loop. For replies with confidence < 0.85, route to Slack for manual review rather than sending autonomously.

Troubleshooting

Issue: Emails landing in spam Fix: Check your domain’s SPF (v=spf1 include:your_smtp_provider.com ~all), DKIM, and DMARC records. Send a warmup sequence (50→200 emails/day over 3 weeks) before scaling. Use a dedicated sending subdomain like outreach.yourdomain.com.

Issue: OpenAI API exceeds rate limits Fix: Add an n8n Wait node (500ms) between each LLM call. Batch prospect research in groups of 3 with a single call using few-shot prompting.

Issue: Replies not being captured Fix: Ensure your IMAP/Gmail trigger checks every 5 minutes. Use the reply_tracking_id in the email headers, not just the body. Some providers strip HTML footers.

Issue: Loop items failing mid-way Fix: Add a Stop and Error workflow with an Error Trigger that catches failures, logs the prospect row to a Google Sheet, and continues the loop from the failure point.

FAQ

Q: Can I run this on n8n Cloud or do I need self-hosted? A: Both work. n8n Cloud handles triggers reliably. Self-host is better if you need to keep prospect data on-premises for compliance (GDPR, SOC 2).

Q: How much will the AI API calls cost per 100 prospects? A: Roughly $8–12. Perplexity research ($0.05/prospect), GPT-4o email generation ($0.02/prospect), and reply classification (~$0.01/reply). Perplexity can be swapped for a free web scrape node to cut costs.

Q: What if a prospect replies multiple times? A: The tracking ID preserves conversation history. Store the thread in an n8n database node and include the last 3 exchanges in the context for each new reply classification pass.

Q: Can I connect this to Salesforce instead of HubSpot? A: Yes — replace the HubSpot node with a Salesforce node using the OAuth2 credential type. Map the same fields (lead status, last touch, notes).

Q: How do I avoid looking spammy? A: Keep personalized angles genuinely specific (reference their recent blog post, funding, or product launch). Avoid generic “I loved your profile” openers. Send max 1 follow-up per prospect unless they reply. Use a real name and headshot in your email signature.