Skip to content
BotServBotServ
EmailAI AgentsAutomationClassificationLocal AI

Email Automation with AI Agents

Email automation with AI agents: classification, responses, routing, spam filtering and practical examples for local AI.

S

schutzgeist

8 min read
Email Automation with AI Agents

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:

  1. Email receipt: IMAP polling or webhook for new messages.
  2. Email parsing: Extract subject, sender, and body.
  3. Classification: Model assigns email to a category.
  4. Prioritization: Model rates importance.
  5. Response drafting: Model suggests a reply.
  6. Routing: Email is forwarded to the right person.
  7. Auto-reply: Response is sent (optional, after approval).
  8. 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

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?

An email agent is an AI agent that processes emails automatically. It reads, classifies, prioritizes, drafts responses, and routes messages.

How does the agent classify emails?

The agent sends the subject and content to the language model with a system prompt that defines the categories. The model responds with the appropriate category.

Should I enable auto-responses?

Be cautious. Auto-responses without approval can be embarrassing or harmful. Use human-in-the-loop instead: the agent drafts, a human reviews and approves.

Can I run email agents locally?

Yes. With Ollama as the backend, the language model runs locally. Email content stays on your hardware with no data transfer to cloud providers.

What is prompt injection in emails?

Prompt injection occurs when an email contains content designed to manipulate the model, such as “Ignore previous instructions.” Protect your system prompt and validate outputs.

Which model is best for email agents?

For classification, a smaller model like llama3.1:8b is sufficient. For response drafting, use a larger model such as qwen2.5:32b or mistral for better quality.

Do I need IMAP and SMTP?

Yes. IMAP for receiving (agent reads emails), SMTP for sending (agent dispatches replies). Both are standard protocols supported by all email providers.

How do I secure email agents?

Use local AI to keep content off the cloud. Enable audit logging, use human-in-the-loop for critical responses, and protect against prompt injection.

Can I use Node-RED instead of Python?

Yes. Node-RED has IMAP and SMTP nodes and can connect to Ollama. See Node-RED for AI automation for details.

What do I do about infinite loops?

If the agent responds to its own replies, a loop can form. Use filters that ignore the agent’s own messages and limit the number of agent steps.

Sources and Further Reading

Back to Blog
Share:

Related Posts