How to Automate Ticket Follow-Up After Resolution
Follow up with customers after ticket resolution to confirm satisfaction.
Jay Banlasan
The AI Systems Guy
When you automate ticket follow up after resolution for satisfaction checks, you catch problems that customers did not bother to report again. I build these because 80% of unsatisfied customers never reopen a ticket. They just leave. A simple follow-up 24 hours after resolution catches them before they churn.
The system waits for resolution, sends a personalized follow-up, and routes unhappy responses back to the team.
What You Need Before Starting
- A ticketing system with resolution status tracking
- Python 3.8+ with scheduling
- Email sending capability (SMTP or API)
- A feedback collection mechanism
Step 1: Trigger Follow-Up on Resolution
Watch for tickets moving to "resolved" status:
from flask import Flask, request
from datetime import datetime
app = Flask(__name__)
@app.route("/ticket-resolved", methods=["POST"])
def on_resolved():
ticket = request.json
schedule_followup(
ticket_id=ticket["id"],
customer_email=ticket["customer_email"],
customer_name=ticket["customer_name"],
resolved_at=datetime.now(),
delay_hours=24
)
return "scheduled", 200
def schedule_followup(ticket_id, customer_email, customer_name, resolved_at, delay_hours):
conn = sqlite3.connect("followups.db")
send_at = resolved_at + timedelta(hours=delay_hours)
conn.execute("""
INSERT INTO scheduled_followups (ticket_id, email, name, send_at, status)
VALUES (?, ?, ?, ?, 'pending')
""", (ticket_id, customer_email, customer_name, send_at.isoformat()))
conn.commit()
Step 2: Generate Personalized Follow-Up Messages
import anthropic
client = anthropic.Anthropic()
def generate_followup(ticket):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=200,
messages=[{
"role": "user",
"content": f"""Write a brief follow-up email for a support ticket that was resolved.
Keep it under 100 words. Friendly, not corporate. Ask if the issue is truly fixed.
Include a simple 1-5 satisfaction rating request.
Customer name: {ticket['customer_name']}
Original issue: {ticket['subject']}
Resolution: {ticket['resolution_summary']}"""
}]
)
return response.content[0].text
Step 3: Send Follow-Ups on Schedule
Run a job that processes pending follow-ups:
import sqlite3
from datetime import datetime, timedelta
import smtplib
from email.mime.text import MIMEText
def process_pending_followups():
conn = sqlite3.connect("followups.db")
now = datetime.now().isoformat()
pending = conn.execute(
"SELECT * FROM scheduled_followups WHERE status = 'pending' AND send_at <= ?",
(now,)
).fetchall()
for followup in pending:
ticket = get_ticket(followup["ticket_id"])
message = generate_followup(ticket)
send_followup_email(followup["email"], followup["name"], message, followup["ticket_id"])
conn.execute(
"UPDATE scheduled_followups SET status = 'sent', sent_at = ? WHERE id = ?",
(now, followup["id"])
)
conn.commit()
Step 4: Collect and Route Feedback
When a customer responds negatively, reopen or escalate:
@app.route("/followup-response", methods=["POST"])
def handle_feedback():
data = request.json
ticket_id = data["ticket_id"]
rating = data["rating"]
comment = data.get("comment", "")
save_feedback(ticket_id, rating, comment)
if rating <= 2:
reopen_ticket(ticket_id, reason=f"Customer unsatisfied (rating: {rating}). Comment: {comment}")
notify_team(ticket_id, rating, comment)
return "received", 200
Step 5: Track Satisfaction Trends
def get_satisfaction_report(days=30):
conn = sqlite3.connect("followups.db")
start = (datetime.now() - timedelta(days=days)).isoformat()
sent = conn.execute("SELECT COUNT(*) FROM scheduled_followups WHERE sent_at > ?", (start,)).fetchone()[0]
responded = conn.execute("SELECT COUNT(*) FROM feedback WHERE created_at > ?", (start,)).fetchone()[0]
avg_rating = conn.execute("SELECT AVG(rating) FROM feedback WHERE created_at > ?", (start,)).fetchone()[0]
reopened = conn.execute(
"SELECT COUNT(*) FROM feedback WHERE rating <= 2 AND created_at > ?", (start,)
).fetchone()[0]
return {
"followups_sent": sent,
"response_rate": round(responded / sent * 100, 1) if sent else 0,
"avg_satisfaction": round(avg_rating or 0, 1),
"reopened_tickets": reopened
}
What to Build Next
Segment follow-up timing by issue type. Simple password resets can get a follow-up after 2 hours. Complex technical issues should wait 48 hours to give the customer time to verify the fix.
Related Reading
- The Feedback Loop That Powers Everything - follow-ups close the loop between resolution and satisfaction
- AI for Email Marketing Automation - email automation patterns applied to support follow-ups
- The Measurement Framework That Actually Works - measuring real satisfaction, not assumed satisfaction
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