Automate Sales Follow-Up Sequences with Python and Your CRM
The single biggest reason deals stall isn't a bad pitch — it's a follow-up that never happened, or happened too late, because a rep got busy and a lead slipped down their priority list. You can automate sales follow-up sequences with Python and your CRM to trigger timely, personalized outreach based on actual prospect behavior, ensuring every lead gets a consistent, well-timed touchpoint without depending entirely on a rep's memory or discipline.
This tutorial builds a Python script that pulls lead activity from your CRM, applies follow-up rules based on real behavior signals, and triggers personalized outreach automatically at the right moment.
Why Manual Follow-Up Discipline Breaks Down at Scale
A rep juggling twenty active leads can usually remember to follow up with each one reasonably well. A rep juggling two hundred leads across different pipeline stages cannot, and the leads that slip through aren't random — they're disproportionately the ones that require a nuanced follow-up rather than a simple next step, exactly the leads worth the most effort to convert.
Standard CRM reminder features help, but they're static: a reminder to "follow up in 3 days" doesn't account for whether the prospect actually opened your last email, visited your pricing page, or went completely silent, all of which should change what your follow-up actually says and how urgently it should go out.
Building the Behavior-Based Follow-Up Automation
Step 1: Pull Recent Lead Activity from Your CRM
1import requests2import os34CRM_API_KEY = os.environ["CRM_API_KEY"]5CRM_BASE_URL = "https://api.yourcrm.com/v1"67def get_active_leads():8 response = requests.get(9 f"{CRM_BASE_URL}/leads",10 headers={"Authorization": "Bearer " + CRM_API_KEY},11 params={"status": "open", "stage": "in_progress"}12 )13 return response.json()["leads"]1415def get_lead_activity(lead_id):16 response = requests.get(17 f"{CRM_BASE_URL}/leads/{lead_id}/activity",18 headers={"Authorization": "Bearer " + CRM_API_KEY}19 )20 return response.json()["activity"]
Most modern CRMs (HubSpot, Salesforce, Pipedrive) expose an activity or engagement endpoint that includes email opens, link clicks, and page visits, which is exactly the behavior data you need to make follow-up decisions smarter than a fixed timer.
Step 2: Apply Follow-Up Rules Based on Behavior
1from datetime import datetime, timedelta23def determine_followup_action(lead, activity):4 last_contact = datetime.fromisoformat(lead["last_contacted_at"])5 days_since_contact = (datetime.now() - last_contact).days67 opened_last_email = any(a["type"] == "email_open" for a in activity)8 visited_pricing = any(a["type"] == "page_visit" and "pricing" in a["url"] for a in activity)9 no_recent_activity = len(activity) == 01011 if visited_pricing and days_since_contact >= 1:12 return "high_intent_followup"13 elif opened_last_email and days_since_contact >= 2:14 return "warm_followup"15 elif no_recent_activity and days_since_contact >= 5:16 return "reengagement_followup"17 else:18 return None
This is the core logic that makes the automation smarter than a fixed reminder — a prospect who just visited your pricing page gets a fast, direct follow-up, while someone who's gone quiet for five days with no activity at all gets a different kind of re-engagement message entirely.
Step 3: Generate Personalized Follow-Up Copy with AI
1from openai import OpenAI23ai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])45def generate_followup_email(lead, action_type):6 prompts = {7 "high_intent_followup": f"Write a short, direct follow-up email to {lead['name']} at {lead['company']}, who just viewed our pricing page. Reference their interest naturally and offer to answer pricing questions or set up a call. Keep it under 100 words.",8 "warm_followup": f"Write a follow-up email to {lead['name']} at {lead['company']}, who opened our last email but hasn't replied. Add one new piece of value (a relevant resource or insight) rather than just 'checking in.' Keep it under 100 words.",9 "reengagement_followup": f"Write a brief, low-pressure re-engagement email to {lead['name']} at {lead['company']}, who has gone quiet for over a week. Acknowledge the gap naturally and ask a single easy question to restart the conversation. Keep it under 80 words."10 }1112 response = ai_client.chat.completions.create(13 model="gpt-4o",14 messages=[{"role": "user", "content": prompts[action_type]}],15 temperature=0.616 )17 return response.choices[0].message.content
Using distinct prompts per action type ensures the tone and content genuinely matches the situation — a high-intent prospect who just looked at pricing shouldn't receive the same soft re-engagement note as someone who's gone cold for over a week.
Step 4: Queue the Email for Rep Review and Send
1def queue_followup_for_review(lead, email_content, action_type):2 requests.post(3 f"{CRM_BASE_URL}/tasks",4 headers={"Authorization": "Bearer " + CRM_API_KEY},5 json={6 "lead_id": lead["id"],7 "type": "review_and_send_email",8 "priority": "high" if action_type == "high_intent_followup" else "normal",9 "draft_content": email_content,10 "assigned_to": lead["owner_id"]11 }12 )1314def run_followup_automation():15 leads = get_active_leads()16 for lead in leads:17 activity = get_lead_activity(lead["id"])18 action = determine_followup_action(lead, activity)19 if action:20 email_draft = generate_followup_email(lead, action)21 queue_followup_for_review(lead, email_draft, action)2223if __name__ == "__main__":24 run_followup_automation()
Queuing the draft as a task for the assigned rep, rather than sending it automatically, keeps a human in the loop for the final send — a sensible balance for outreach where getting the tone exactly right with a real relationship still matters.
Scheduling the Automation
Run the script every morning so reps start their day with a queue of prioritized, pre-drafted follow-ups instead of having to remember who needs outreach and write each message from scratch:
10 8 * * 1-5 /usr/bin/python3 /path/to/followup_automation.py
Real-World Example: Recovering Stalled Pipeline
A SaaS sales team running this automation for one quarter found that leads flagged as "high_intent_followup" — those who'd visited pricing pages without a scheduled call — converted to meetings at nearly triple the rate of leads followed up with generic, non-behavior-triggered outreach. The behavior signal turned out to be a strong predictor of readiness to talk, and surfacing it automatically meant reps were consistently reaching out at exactly the moment prospects were most engaged, rather than days later when that engagement had cooled.
Best Practices / Pro Tips
Always route AI-generated follow-up drafts through a rep for review rather than auto-sending, at least until you've validated the messaging quality and tone over several weeks of real use.
Tune your behavior thresholds (days since contact, which pages count as high-intent) based on your actual sales cycle length — a fast-moving transactional sale needs tighter thresholds than an enterprise deal with a multi-month cycle.
Track conversion rates by follow-up type over time, and use that data to refine both your behavior rules and your AI prompts, since the categories that convert best will become clear only after a few weeks of real results.
Make sure your CRM's activity tracking is actually reliable before building rules on top of it — garbage behavior data produces confidently wrong follow-up recommendations.
Conclusion
You can automate sales follow-up sequences with Python and your CRM by combining real prospect behavior data with rules that trigger the right kind of outreach at the right moment, then using AI to draft personalized copy a rep can review and send in seconds. This closes the gap between knowing follow-up discipline matters and actually having the consistent capacity to execute it across every lead in an active pipeline, converting more of the leads that would otherwise have quietly gone cold.
Frequently Asked Questions
Will this work with any CRM, or only specific platforms?
The pattern works with any CRM exposing a REST API with lead and activity data, which includes HubSpot, Salesforce, Pipedrive, and most modern platforms — you'll just need to adjust the specific endpoint URLs and field names to match your CRM's API documentation.
Should follow-up emails send automatically or always require review?
Starting with mandatory human review is the safer approach, especially for higher-value leads, until you've built confidence in the AI-generated copy's quality and tone over several weeks. Lower-stakes, high-volume segments may eventually be safe to automate fully.
How do I decide what counts as "high intent" behavior for my business?
Look at your historical closed-won deals and identify what behavior patterns preceded them most consistently — pricing page visits are common across many businesses, but your specific high-intent signal might be a demo request, a case study download, or a specific product page visit.
What if a lead doesn't have enough activity data to trigger any rule?
The no_recent_activity re-engagement rule handles this case directly, triggering a low-pressure check-in after a defined period of silence rather than leaving genuinely inactive leads with no automated follow-up at all.
Related articles: Automate Your Sales Pipeline with CRM Workflows, Lead Scoring Automation with Python and Your CRM, Automate Sales Proposal Generation with Python
Sponsored Content
Interested in advertising? Reach automation professionals through our platform.
