Industry Applications
real estate
How to Automate Real Estate Lead Follow-Up
Follow up with property leads automatically across email and text.
Jay Banlasan
The AI Systems Guy
Automating real estate lead follow-up is where agents stop losing deals. The National Association of Realtors says 80% of sales happen after the fifth follow-up, but most agents stop after one. I build follow-up systems that handle the first five touches automatically, so agents only spend time on leads that respond.
What You Need Before Starting
- Python 3.8+
- An email sending service (SMTP or SendGrid)
- A database for lead tracking
- Lead source (website form, Zillow, Realtor.com)
Step 1: Set Up the Lead Database
import sqlite3
from datetime import datetime
def init_lead_db(db_path="real_estate_leads.db"):
conn = sqlite3.connect(db_path)
conn.execute("""
CREATE TABLE IF NOT EXISTS leads (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
email TEXT,
phone TEXT,
source TEXT,
property_interest TEXT,
lead_type TEXT,
status TEXT DEFAULT 'new',
follow_up_count INTEGER DEFAULT 0,
created_at TEXT,
last_contact TEXT
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS follow_ups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
lead_id INTEGER,
channel TEXT,
message TEXT,
sent_at TEXT,
opened INTEGER DEFAULT 0
)
""")
conn.commit()
conn.close()
Step 2: Define the Follow-Up Sequence
FOLLOW_UP_SEQUENCE = [
{
"delay_hours": 0,
"channel": "email",
"subject": "Thanks for your inquiry about {property}",
"template": "quick_response"
},
{
"delay_hours": 24,
"channel": "email",
"subject": "More details on {property}",
"template": "property_details"
},
{
"delay_hours": 72,
"channel": "email",
"subject": "Similar properties you might like",
"template": "similar_listings"
},
{
"delay_hours": 168,
"channel": "email",
"subject": "Market update for {neighborhood}",
"template": "market_update"
},
{
"delay_hours": 336,
"channel": "email",
"subject": "Still looking in {neighborhood}?",
"template": "check_in"
}
]
Step 3: Build the Message Generator
import anthropic
from dotenv import load_dotenv
load_dotenv()
def generate_follow_up(lead, template_type):
client = anthropic.Anthropic()
prompts = {
"quick_response": f"Write a brief, warm follow-up email to {lead['name']} who inquired about {lead['property_interest']}. Thank them, confirm you received their inquiry, and ask what their timeline looks like. Under 100 words.",
"property_details": f"Write a follow-up email to {lead['name']} with additional details about {lead['property_interest']}. Mention neighborhood highlights and suggest scheduling a showing. Under 120 words.",
"similar_listings": f"Write an email to {lead['name']} suggesting they might also like similar properties near {lead['property_interest']}. Keep it helpful, not salesy. Under 100 words.",
"market_update": f"Write a brief market update email for the area around {lead['property_interest']}. Include a note about timing and invite questions. Under 100 words.",
"check_in": f"Write a casual check-in email to {lead['name']} asking if they are still looking for properties. Offer to help with no pressure. Under 80 words."
}
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=512,
system="You are a friendly real estate agent. Write natural, conversational emails. No ALL CAPS. No exclamation marks overuse. Sound human, not automated.",
messages=[{"role": "user", "content": prompts.get(template_type, prompts["check_in"])}]
)
return response.content[0].text
Step 4: Build the Follow-Up Engine
from datetime import datetime, timedelta
import smtplib
from email.mime.text import MIMEText
def send_email(to_email, subject, body):
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = "[email protected]"
msg["To"] = to_email
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login("[email protected]", "YOUR_APP_PASSWORD")
server.send_message(msg)
def process_follow_ups(db_path="real_estate_leads.db"):
conn = sqlite3.connect(db_path)
leads = conn.execute("""
SELECT id, name, email, property_interest, follow_up_count, created_at
FROM leads WHERE status = 'new' OR status = 'following_up'
""").fetchall()
for lead_row in leads:
lead_id, name, email, property, count, created = lead_row
if count >= len(FOLLOW_UP_SEQUENCE):
conn.execute("UPDATE leads SET status = 'nurture' WHERE id = ?", (lead_id,))
continue
step = FOLLOW_UP_SEQUENCE[count]
created_dt = datetime.fromisoformat(created)
send_after = created_dt + timedelta(hours=step["delay_hours"])
if datetime.utcnow() >= send_after:
lead_data = {"name": name, "property_interest": property}
body = generate_follow_up(lead_data, step["template"])
subject = step["subject"].replace("{property}", property or "your inquiry")
send_email(email, subject, body)
conn.execute("UPDATE leads SET follow_up_count = ?, last_contact = ?, status = 'following_up' WHERE id = ?",
(count + 1, datetime.utcnow().isoformat(), lead_id))
conn.execute("INSERT INTO follow_ups (lead_id, channel, message, sent_at) VALUES (?,?,?,?)",
(lead_id, "email", body[:500], datetime.utcnow().isoformat()))
conn.commit()
conn.close()
Step 5: Schedule Hourly Processing
0 * * * * python3 /path/to/follow_up_engine.py
What to Build Next
Add reply detection. Monitor your inbox for responses and automatically pause the sequence when a lead replies. That prevents the awkward automated email that arrives after they already responded.
Related Reading
- Automating Follow-Ups Without Being Annoying - the art of automated outreach
- AI in Real Estate Operations - AI across the real estate workflow
- Lead Scoring with AI - prioritizing which leads to follow up first
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment