← Back to tutorials

AI Outbound Sales: Personalizing Prospecting at Scale Without Being Spammy

How to use AI to research prospects and write genuinely personalized outreach that gets replies

AI Outbound Sales: Personalized Prospecting at Scale

Cold outreach is broken. Generic "Hi [FirstName], I noticed you're a [Title] at [Company]" emails get 1-2% reply rates. But truly personalized outreach — referencing specific things about the person and company — gets 8-15% reply rates. AI makes personalization scalable.

The Personalization Paradox

True personalization requires research: reading the prospect's LinkedIn, their company's news, their recent posts, their company's tech stack. This takes 15-30 minutes per prospect.

At scale, this is impossible. But AI can do this research and drafting in seconds.

Building a Personalization Engine

python
import anthropic
from openai import OpenAI
import json
import httpx
from dataclasses import dataclass
from typing import Optional

client = anthropic.Anthropic() openai_client = OpenAI()

@dataclass class ProspectResearch: company_name: str prospect_name: str job_title: str company_news: list[str] linkedin_posts: list[str] company_tech_stack: list[str] company_size: str recent_funding: Optional[str] job_postings: list[str] # Hiring signals competitor_connections: list[str]

class AIProspectResearcher: """ Automates prospect research for personalized outreach. """ def research_company(self, company_name: str, domain: str) -> dict: """ Research a company using available signals. In production: use APIs from Clearbit, Apollo, LinkedIn, etc. """ # This is a framework - replace with real API calls research_data = { 'company_name': company_name, 'recent_news': self._get_company_news(company_name), 'job_postings': self._get_job_postings(domain), 'tech_stack': self._get_tech_stack(domain), 'funding': self._get_funding_data(company_name), 'size_estimate': self._estimate_company_size(domain) } return research_data def _get_company_news(self, company_name: str) -> list[str]: """Get recent company news from news APIs.""" # Would use: NewsAPI, Google News API, or web scraping return [f"Recent news for {company_name} would appear here"] def _get_job_postings(self, domain: str) -> list[str]: """Get job postings as intent signals.""" # Hiring for AI/ML engineers = investing in AI # Hiring for SDRs = scaling sales # Job postings reveal strategic priorities return ["Example: 5 AI/ML engineer postings (investing in AI infrastructure)"] def _get_tech_stack(self, domain: str) -> list[str]: """Get company's tech stack from Clearbit, BuiltWith, etc.""" return ["Salesforce", "HubSpot", "Slack", "AWS"] def _get_funding_data(self, company_name: str) -> Optional[str]: """Get funding information from Crunchbase API.""" return "Series B - $45M raised, announced 3 months ago" def _estimate_company_size(self, domain: str) -> str: """Estimate company size from LinkedIn or Clearbit.""" return "201-500 employees"

class OutreachPersonalizer: """ Generates personalized outreach based on prospect research. """ def __init__(self): self.client = anthropic.Anthropic() self.researcher = AIProspectResearcher() def generate_cold_email(self, prospect: dict, your_product: dict, email_type: str = 'first_touch') -> dict: """ Generate a personalized cold email for a prospect. email_type: first_touch, follow_up_1, follow_up_2, breakup """ # Research the prospect's company company_research = self.researcher.research_company( prospect.get('company'), prospect.get('company_domain', '') ) # Identify the best personalization angle angle = self._identify_best_angle(prospect, company_research, your_product) email_prompt = f"""Write a personalized cold {email_type} email to: Name: {prospect.get('name')} Title: {prospect.get('title')} Company: {prospect.get('company')}

Best personalization angle: {angle['angle']} Evidence: {angle['evidence']}

About our product: Name: {your_product.get('name')} Value proposition: {your_product.get('value_prop')} Relevant use case for them: {your_product.get('use_case_for_prospect')} Social proof: {your_product.get('customer_proof', 'customer example')}

Email requirements:

  • Subject line: <40 characters, personalized, curiosity-driven (NO "Quick question" or "Following up")
  • Opening: Reference SPECIFIC, REAL thing about them (not generic flattery)
  • Middle: Connect their situation to a specific problem you solve (1-2 sentences)
  • CTA: Single, specific, low-commitment ask (15-minute call OR reply to question)
  • Length: Under 100 words for first touch
  • Tone: Peer-to-peer, not salesy or obsequious
  • NO: "I came across your profile", "I hope this finds you well", "I'd love to pick your brain"
  • Return JSON with subject, preview_text, body, cta""" message = self.client.messages.create( model="claude-opus-4-5", max_tokens=500, messages=[{"role": "user", "content": email_prompt}] ) try: email_data = json.loads(message.content[0].text) except json.JSONDecodeError: email_data = {"body": message.content[0].text} email_data['personalization_angle'] = angle['angle'] email_data['prospect_id'] = prospect.get('id') return email_data def _identify_best_angle(self, prospect: dict, company_research: dict, product: dict) -> dict: """ Identify the most relevant personalization angle. Priority: recent news > job postings > tech stack > general role """ # Check for recent funding (major trigger) if company_research.get('funding') and 'raised' in str(company_research['funding']).lower(): return { 'angle': 'recent_funding', 'evidence': company_research['funding'], 'reason': 'Companies scale teams and tools after funding' } # Check for relevant job postings ai_hiring = [j for j in company_research.get('job_postings', []) if any(tech in j for tech in ['AI', 'ML', 'data', 'automation'])] if ai_hiring: return { 'angle': 'ai_investment', 'evidence': ai_hiring[0], 'reason': 'Active investment in AI = likely to buy AI tools' } # Check tech stack for integration opportunities if company_research.get('tech_stack'): return { 'angle': 'tech_integration', 'evidence': f"Noticed you're using {company_research['tech_stack'][0]}", 'reason': 'Integration with existing stack' } # Default to role-based angle return { 'angle': 'role_pain_point', 'evidence': f"As a {prospect.get('title')} at a growing company", 'reason': 'Generic but still targeted to role' } def generate_sequence(self, prospect: dict, product: dict, num_emails: int = 4) -> list[dict]: """Generate a complete multi-touch sequence.""" email_types = ['first_touch', 'follow_up_1', 'follow_up_2', 'breakup'] delays_days = [0, 3, 7, 14] # Days from previous email sequence = [] for i in range(min(num_emails, len(email_types))): email = self.generate_cold_email(prospect, product, email_types[i]) email['send_delay_days'] = delays_days[i] email['sequence_position'] = i + 1 sequence.append(email) return sequence

    Example: Generate outreach for a list of prospects

    def run_personalization_campaign(prospects: list[dict], product: dict) -> list[dict]: """Generate personalized sequences for all prospects.""" personalizer = OutreachPersonalizer() all_sequences = [] for i, prospect in enumerate(prospects): print(f"Personalizing for {prospect.get('name')} ({i+1}/{len(prospects)})...") try: sequence = personalizer.generate_sequence(prospect, product) all_sequences.append({ 'prospect': prospect, 'sequence': sequence }) except Exception as e: print(f"Error for {prospect.get('name')}: {e}") return all_sequences

    Reply Rate Benchmarks

    ApproachReply RateMeeting Booked Rate

    Generic blast1-2%0.3-0.5% Template with name/company3-5%1-1.5% AI-personalized (angle)8-12%3-5% Full manual research12-18%5-8%

    AI personalization gets you 80% of manual quality at 1000x the scale. For a team sending 200 emails/week, the difference between 3% and 9% reply rate is 12 additional conversations per week.

    The key: Use AI to personalize the opening and angle, but make sure the product pitch is genuinely relevant. AI can't save an irrelevant offer.

    Also available in 中文.

    AI Outbound Sales: Personalizing Prospecting at Scale Without Being Spammy | AI Skill Navigation | AI Skill Navigation