Email Automation with AI Agents
What this article covers
- How to implement email automation with AI agents.
- How agents classify emails, draft responses, and route them to the right person.
- How to build spam filters, prioritization, and auto-replies with local AI.
- Real-world examples for support inboxes, sales inquiries, and internal distribution.
- Best practices for security, privacy, and quality assurance.
Introduction: Email automation with AI agents explained
Email remains one of the most time-consuming communication channels. Hundreds of messages land in your inbox every day: support requests, sales leads, spam, internal updates. Manually sorting, responding to, and forwarding them eats up hours. AI agents can automate this. They read emails, classify them, draft responses, and route them to the right recipient. With local AI, these agents run entirely on your hardware without sending email content to cloud providers.
This article is for developers who want to build email automation with AI agents. You should already understand what AI agents are and how to run them locally with Ollama. For Python fundamentals, check out IRC-Coding.de.
Why email automation with AI agents?
Imagine you run a support inbox with 200 emails daily. Each one needs to be read, categorized, answered, or forwarded. Manually, that’s 4-6 hours a day. An AI agent handles it in minutes: reading, classifying, drafting responses, and routing. You just review and send.
Email automation pays off especially when you receive high volume, classification is complex (multiple categories, ambiguous requests), or you need fast response times.
Email automation with AI agents in a nutshell
An email agent is an AI agent that processes emails. It reads incoming messages, classifies them by category, prioritizes them, drafts responses, and forwards them to the right person. The agent uses tools for email access (IMAP/SMTP) and a language model for classification and response generation.
The core idea: the agent is your inbox assistant, the tools are IMAP and SMTP, the model is the brain.
Who should read this
- Support teams wanting to automate email volume.
- Sales teams needing to auto-classify and prioritize leads.
- Developers building email agents.
- System administrators setting up email automation.
You’ll need prior knowledge of Python, AI agents, and Ollama.
Key concepts in email automation
- Email agent - AI agent that processes emails. Useful for: automating email handling.
- IMAP - Protocol for receiving emails. Useful for: allowing the agent to read messages.
- SMTP - Protocol for sending emails. Useful for: letting the agent send responses.
- Classification - Sorting into categories. Useful for: organizing emails by type.
- Prioritization - Assessing importance. Useful for: handling urgent emails first.
- Function Calling - Structured AI responses. Useful for: classification and response drafting.
- Ollama - Local model server. Useful for: powering the agent’s reasoning.
- AI agents - Programs that solve tasks autonomously. Useful for: the foundation.
- Node-RED - Visual workflow editor. Useful for: an alternative to code-based email flows.
Architecture of an email agent
A typical email agent consists of these components:
- Email receipt: IMAP polling or webhook for new messages.
- Email parsing: Extract subject, sender, and body.
- Classification: Model assigns email to a category.
- Prioritization: Model rates importance.
- Response drafting: Model suggests a reply.
- Routing: Email is forwarded to the right person.
- Auto-reply: Response is sent (optional, after approval).
- Logging: All actions are recorded.
Accessing email with Python
IMAP for receiving
import imaplib
import email
from email import policy
def fetch_emails(host, user, password, folder="INBOX", limit=10):
mail = imaplib.IMAP4_SSL(host)
mail.login(user, password)
mail.select(folder)
_, data = mail.search(None, "UNSEEN")
email_ids = data[0].split()[:limit]
emails = []
for eid in email_ids:
_, msg_data = mail.fetch(eid, "(RFC822)")
msg = email.message_from_bytes(msg_data[0][1], policy=policy.default)
emails.append({
"from": msg["from"],
"subject": msg["subject"],
"body": get_body(msg),
"date": msg["date"]
})
mail.logout()
return emails
def get_body(msg):
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/plain":
return part.get_content()
return msg.get_content()
SMTP for sending
import smtplib
from email.mime.text import MIMEText
def send_email(host, user, password, to, subject, body):
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = user
msg["To"] = to
with smtplib.SMTP_SSL(host, 465) as server:
server.login(user, password)
server.send_message(msg)
Classification with Ollama
import requests
def classify_email(subject, body):
prompt = f"""
Classify this email into one of these categories:
- support: Technical question or issue
- sales: Purchase interest or offer
- billing: Invoice or payment
- spam: Advertisement or phishing
- other: Other
Subject: {subject}
Content: {body[:1000]}
Reply with only the category.
"""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.1",
"messages": [
{"role": "system", "content": "You are an email classifier. Reply with only a category."},
{"role": "user", "content": prompt}
],
"stream": False
}
)
return response.json()["message"]["content"].strip().lower()
Prioritization with Function Calling
def prioritize_email(subject, body):
tools = [
{
"type": "function",
"function": {
"name": "set_priority",
"parameters": {
"type": "object",
"properties": {
"priority": {"type": "string", "enum": ["high", "medium", "low"]},
"reason": {"type": "string"}
},
"required": ["priority", "reason"]
}
}
}
]
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.1",
"messages": [
{"role": "system", "content": "Assess the priority of this email."},
{"role": "user", "content": f"Subject: {subject}\nContent: {body[:1000]}"}
],
"tools": tools,
"stream": False
}
)
# Extract tool call
msg = response.json()["message"]
if msg.get("tool_calls"):
return msg["tool_calls"][0]["function"]["arguments"]
return {"priority": "medium", "reason": "Unknown"}
Drafting responses with Ollama
def draft_response(subject, body, category):
prompt = f"""
You are an email assistant. Draft a courteous, professional response.
Category: {category}
Subject: {subject}
Email: {body[:2000]}
Draft an appropriate response. If you're uncertain, suggest forwarding the email to a human.
"""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.1",
"messages": [
{"role": "system", "content": "You are an email assistant. Write courteous, professional responses."},
{"role": "user", "content": prompt}
],
"stream": False
}
)
return response.json()["message"]["content"]
Practical example 1: Support inbox
An agent that classifies support emails, prioritizes them, and drafts responses.
def support_agent(emails):
results = []
for email in emails:
# Classification
category = classify_email(email["subject"], email["body"])
# Process only support emails
if category != "support":
continue
# Prioritization
priority = prioritize_email(email["subject"], email["body"])
# Draft response
draft = draft_response(email["subject"], email["body"], category)
results.append({
"email": email,
"category": category,
"priority": priority,
"draft": draft
})
# Sort by priority
results.sort(key=lambda x: {"high": 0, "medium": 1, "low": 2}[x["priority"]["priority"]])
return results
Practical example 2: Sales lead qualification
An agent that qualifies sales inquiries and routes them to the right sales representative.
def sales_agent(email):
# Qualification
qualification = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.1",
"messages": [
{"role": "system", "content": """
Qualify this sales inquiry. Evaluate:
- budget: Budget mentioned? (yes/no/unknown)
- authority: Decision maker? (yes/no/unknown)
- need: Need identified? (yes/no/unknown)
- timeline: Timeline mentioned? (yes/no/unknown)
Respond as JSON.
"""},
{"role": "user", "content": f"Subject: {email['subject']}\nContent: {email['body'][:2000]}"}
],
"format": "json",
"stream": False
}
).json()["message"]["content"]
# Route based on qualification
score = sum(1 for v in json.loads(qualification).values() if v == "yes")
if score >= 3:
return {"action": "forward_to_senior", "qualification": qualification}
elif score >= 1:
return {"action": "forward_to_junior", "qualification": qualification}
else:
return {"action": "auto_reply_info", "qualification": qualification}
Practical example 3: AI-powered spam filter
An agent that detects spam and phishing.
def spam_agent(email):
result = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.1",
"messages": [
{"role": "system", "content": """
Evaluate whether this email is spam or phishing.
Criteria:
- Unusual sender domain
- Urgent call to action
- Links to unknown sites
- Requests for personal data
- Grammar or spelling errors
Respond as JSON: {"is_spam": true/false, "confidence": "high/medium/low", "reason": "..."}
"""},
{"role": "user", "content": f"From: {email['from']}\nSubject: {email['subject']}\nContent: {email['body'][:2000]}"}
],
"format": "json",
"stream": False
}
).json()["message"]["content"]
return json.loads(result)
Security considerations
- No sensitive data to the cloud: Use local AI so email content stays off cloud provider servers.
- Human-in-the-loop: Critical responses should be reviewed by a human. See Human approval.
- Audit logging: Log all agent actions. See Audit logging.
- Prompt injection protection: Emails may contain prompt injection attempts. See Prompt injection protection.
- No auto-responses without approval: Automatically sent replies should be reviewed by a human.
- Email authentication: Secure SMTP/IMAP with OAuth2 or app-specific passwords.
Common pitfalls
- Misclassification: The model can make mistakes. Use confidence scores and human-in-the-loop.
- Prompt injection: Emails can manipulate the model. Protect your system prompt.
- Auto-responses without approval: Unreviewed responses can be embarrassing or harmful.
- Infinite loops: If the agent responds to its own replies, a loop can form.
- Context length: Long email threads exceed context limits. Use summary memory.
- Data privacy: Email content is sensitive. Use local AI.
Further reading and resources on email automation
- AI agents fundamentals - What AI agents are.
- Running AI agents with Ollama - Operating agents locally.
- Function calling - Tool-use basics.
- Node-RED - Visual alternative for email workflows.
- Human approval - Human-in-the-loop.
- Prompt injection protection - Security for email content.
- Audit logging - Traceability.
- Research workflows - Similar workflow architecture.
Key takeaways:
- Email agents automate classification, prioritization, response drafting, and routing.
- IMAP for receiving, SMTP for sending, Ollama for classification and responses.
- Practical examples: support inbox, sales qualification, spam filter.
- Security: local AI, human-in-the-loop, audit logging, prompt injection protection.
- No auto-responses without approval.
FAQ: Email automation with AI agents - Common questions
What is an email agent?
How does the agent classify emails?
Should I enable auto-responses?
Can I run email agents locally?
What is prompt injection in emails?
Which model is best for email agents?
Do I need IMAP and SMTP?
How do I secure email agents?
Can I use Node-RED instead of Python?
What do I do about infinite loops?
Sources and Further Reading
- Python imaplib - IMAP for Python.
- Python smtplib - SMTP for Python.
- Ollama - Local model server.
- Node-RED - Visual alternative.


