title: "Automate Your Email with AI Agents" date: "2026-02-24" description: "Learn how to build an AI-powered email automation system using OpenClaw. Automatically triage, draft replies, and manage your inbox with intelligent agents." category: "Tutorial" author: "OpenClaw Team" tags: ["email", "automation", "productivity"] readTime: "14 min"
Email is one of the highest-leverage places to apply AI automation. The average knowledge worker spends over two hours a day in their inbox — reading, triaging, drafting replies, and following up. With OpenClaw, you can delegate most of that to a set of cooperating agents that work around the clock.
This tutorial builds a complete email automation system from scratch: an inbox connection, a triage agent that categorizes incoming mail, an auto-reply agent that drafts responses, and a follow-up agent that nudges threads that have gone quiet.
What You'll Build
By the end of this tutorial, you'll have a working email automation pipeline with:
- An IMAP listener that polls your inbox for new messages
- A triage agent that classifies emails by urgency and category
- A reply drafting agent that writes contextual responses for your review
- A follow-up agent that flags threads needing a nudge
- A filtering layer that applies AI-generated rules to route mail
Prerequisites
Before you begin, make sure you have:
- OpenClaw installed and running (installation guide)
- Claude API configured (setup guide)
- An email account with IMAP/SMTP access enabled (Gmail, Outlook, or any standard mail server)
- An app-specific password if your provider requires it (Gmail does)
- Python 3.10+ for the custom agent scripts in this tutorial
Step 1: Connect Your Inbox via IMAP
OpenClaw includes a built-in email connector. Configure it with your IMAP credentials:
# openclaw.yaml
integrations:
email:
provider: imap
host: "imap.gmail.com"
port: 993
tls: true
username: "${EMAIL_ADDRESS}"
password: "${EMAIL_APP_PASSWORD}" # Use an app password, not your main password
polling_interval: 60s # Check for new mail every 60 seconds
folders:
- INBOX
- "[Gmail]/Sent Mail" # Monitor sent folder for follow-up tracking
For SMTP (sending replies and follow-ups), add a separate outbound block:
smtp:
host: "smtp.gmail.com"
port: 587
starttls: true
username: "${EMAIL_ADDRESS}"
password: "${EMAIL_APP_PASSWORD}"
Test the connection before building agents on top of it:
openclaw integration test email
# Expected output:
# IMAP connection: OK (inbox contains 247 messages)
# SMTP connection: OK (test message delivered)
Step 2: Build the Triage Agent
The triage agent is the front door of your automation. It reads each new email and assigns three properties: category, urgency, and required action.
Define the agent in your agents config:
# agents.yaml
agents:
triage:
role: "Email Triage Specialist"
model: claude-3-5-haiku-20241022 # Fast and cheap — runs on every email
instructions: |
You are an expert email triage assistant. For each email, analyze:
1. CATEGORY: Choose one of:
- customer_inquiry (questions from customers or prospects)
- internal (from colleagues, team members)
- newsletter (marketing, subscriptions, digests)
- notification (automated alerts, system messages)
- personal (from friends, family)
- spam (unsolicited, irrelevant)
2. URGENCY: Choose one of:
- urgent (requires response within 2 hours)
- normal (respond within 24 hours)
- low (respond within a week or not at all)
3. ACTION: Choose one of:
- reply_needed (must send a response)
- draft_reply (draft a reply for human review)
- archive (no action required, safe to archive)
- unsubscribe (newsletter or marketing to unsubscribe from)
- escalate (needs human attention immediately)
Respond ONLY with valid JSON. No prose.
output_schema:
type: object
required: [category, urgency, action, summary]
properties:
category: {type: string}
urgency: {type: string}
action: {type: string}
summary: {type: string, description: "One sentence summary of the email"}
The triage agent uses claude-3-5-haiku-20241022 because it runs on every single email — including newsletters and spam. Using a cheaper, faster model here keeps costs minimal. The heavy models are reserved for drafting thoughtful replies.
Wire the triage agent into an email trigger:
# workflows/email-triage.yaml
name: email_triage
trigger:
type: email_received
folder: INBOX
steps:
- name: triage
agent: triage
input:
from: "{{email.from}}"
subject: "{{email.subject}}"
body: "{{email.body_text | truncate: 2000}}" # Limit context for speed
date: "{{email.date}}"
output: triage_result
- name: apply_labels
type: email_action
action: label
email_id: "{{email.id}}"
labels:
- "{{triage_result.category}}"
- "{{triage_result.urgency}}"
- name: route
type: conditional
conditions:
- if: "{{triage_result.action == 'draft_reply'}}"
then: draft_reply_workflow
- if: "{{triage_result.action == 'archive'}}"
then: archive_email
- if: "{{triage_result.urgency == 'urgent'}}"
then: send_urgent_notification
Step 3: Build the Reply Drafting Agent
For emails that need a response, the drafting agent generates a contextual reply based on the original message and your writing style.
First, create a style profile that the agent will use as a reference. You can generate this by feeding it examples of your past emails:
openclaw agent train reply_drafter \
--samples "./email-samples/*.txt" \
--output "./profiles/my-writing-style.yaml"
Then configure the drafting agent:
# agents.yaml (continued)
reply_drafter:
role: "Email Reply Specialist"
model: claude-3-5-sonnet-20241022 # Better writing quality
context_files:
- "./profiles/my-writing-style.yaml"
- "./data/company-faq.txt" # Common answers to inject automatically
instructions: |
You draft email replies on behalf of the user. Follow their writing style
exactly as described in the style profile.
Guidelines:
- Match the formality level of the incoming email
- Be concise — aim for the shortest response that fully addresses the question
- Never invent facts. If you don't know the answer, say so and offer to find out.
- Always end with a clear next step or call to action
- Do not include a subject line — only the body text
- Leave [PLACEHOLDER] for any specific detail you cannot confidently fill in
output_schema:
type: object
required: [draft, confidence, notes]
properties:
draft: {type: string, description: "The full reply body text"}
confidence: {type: number, minimum: 0, maximum: 1}
notes: {type: string, description: "Any flags or uncertainties for the human reviewer"}
The confidence score is important. Low-confidence drafts get flagged for mandatory human review before sending:
# workflows/draft-reply.yaml
name: draft_reply_workflow
steps:
- name: draft
agent: reply_drafter
input:
original_email: "{{email.full_content}}"
triage_summary: "{{triage_result.summary}}"
category: "{{triage_result.category}}"
output: draft_result
- name: save_draft
type: email_action
action: save_draft
to: "{{email.from}}"
subject: "Re: {{email.subject}}"
body: "{{draft_result.draft}}"
- name: notify_if_low_confidence
type: conditional
conditions:
- if: "{{draft_result.confidence < 0.7}}"
then:
action: send_notification
channel: slack
message: |
Low-confidence draft saved for {{email.from}}.
Subject: {{email.subject}}
Notes: {{draft_result.notes}}
Review: {{draft_result.review_url}}
Drafts are saved to your drafts folder for review, never sent automatically. You review, edit if needed, and hit send. Over time you can raise the auto-send threshold for high-confidence replies in low-stakes categories.
Step 4: Build the Follow-Up Agent
Threads that need follow-up are tracked in OpenClaw's internal store. A scheduled job runs daily to surface emails that have gone quiet:
# agents/followup_agent.py
from openclaw import Agent, EmailStore, ScheduledTask
from datetime import datetime, timedelta
class FollowUpAgent(Agent):
name = "follow_up"
model = "claude-3-5-haiku-20241022"
def run(self):
store = EmailStore()
# Find sent emails with no reply after 3 days
pending = store.query(
folder="sent",
no_reply_since=datetime.now() - timedelta(days=3),
exclude_categories=["newsletter", "notification"]
)
for thread in pending:
assessment = self.assess_followup_need(thread)
if assessment["needs_followup"]:
draft = self.draft_followup(thread)
store.save_draft(
thread_id=thread.id,
body=draft,
label="follow-up-needed"
)
def assess_followup_need(self, thread) -> dict:
return self.complete(
prompt=f"""
I sent this email {thread.days_ago} days ago and haven't heard back.
Should I follow up?
Original email:
{thread.sent_body}
Respond with JSON: {{"needs_followup": bool, "reason": str}}
"""
)
def draft_followup(self, thread) -> str:
return self.complete(
prompt=f"""
Write a brief, friendly follow-up to this email thread.
Keep it to 2-3 sentences. Don't be pushy.
Original subject: {thread.subject}
Original email: {thread.sent_body}
"""
)
Schedule it to run once a day:
# schedules.yaml
schedules:
daily_followup:
agent: follow_up
cron: "0 9 * * 1-5" # 9am Monday through Friday
timezone: "America/New_York"
See the scheduling AI tasks guide for more patterns around cron-based agent triggers.
Step 5: Apply AI-Generated Filtering Rules
Beyond the triage agent, you can have OpenClaw generate Gmail-style filter rules from your email history. This creates a deterministic pre-filter that catches obvious cases before the AI even runs — saving tokens and latency:
# generate_rules.py
from openclaw import RuleGenerator, EmailStore
store = EmailStore()
# Sample the last 30 days of mail
sample = store.sample(days=30, max_messages=500)
generator = RuleGenerator(model="claude-3-5-sonnet-20241022")
rules = generator.generate(
email_sample=sample,
objective="""
Generate filtering rules to:
1. Auto-archive newsletters and marketing emails
2. Label emails from my team with 'internal'
3. Flag anything with words like 'urgent', 'ASAP', 'deadline' with high priority
4. Move automated notifications to a 'Notifications' folder
"""
)
# Write rules to OpenClaw config
rules.save("./config/email-rules.yaml")
print(f"Generated {len(rules)} rules")
The generated rules file looks like this:
# config/email-rules.yaml
rules:
- name: "Auto-archive newsletters"
conditions:
- field: from
operator: contains_any
values: ["newsletter", "no-reply", "noreply", "digest", "updates@"]
- field: list_unsubscribe
operator: exists
actions:
- label: newsletter
- archive: true
skip_ai_triage: true # Don't waste tokens on these
- name: "Flag urgent keywords"
conditions:
- field: subject
operator: matches_regex
value: "(?i)(urgent|asap|deadline|time.sensitive)"
actions:
- label: urgent
- notify: slack
Step 6: Test the Full Pipeline
Run the end-to-end test to validate the complete pipeline before going live:
# Replay the last 10 emails through the pipeline (dry-run, no actions taken)
openclaw workflow test email_triage \
--source inbox \
--last 10 \
--dry-run
# Output:
# Email 1 (support request): triaged=customer_inquiry, urgency=normal, action=draft_reply ✓
# Email 2 (newsletter): triaged=newsletter, urgency=low, action=archive ✓
# Email 3 (urgent client): triaged=customer_inquiry, urgency=urgent, action=escalate ✓
# ...
# 9/10 correctly classified. 1 misclassified (false positive on urgency).
Review misclassifications and adjust the triage agent's instructions accordingly. A few rounds of refinement typically gets accuracy above 95%.
Common Issues and Fixes
Gmail blocking IMAP access — Enable IMAP in Gmail settings (Settings > See all settings > Forwarding and POP/IMAP) and generate an App Password at myaccount.google.com/apppasswords.
Triage agent misclassifying a specific sender — Add an explicit rule in email-rules.yaml for that sender. Deterministic rules run before AI and take priority.
Reply drafts are too long — Add "Aim for under 150 words" to the drafting agent's instructions and set max_tokens: 400 in the generation config.
Too many low-confidence flags — The agent needs more context. Add your FAQ file to context_files or increase the number of writing style samples used during training.
Next Steps
With your email automation running, explore what else you can build:
- Build a multi-agent system to coordinate the email agents with other workflows
- Claude API setup guide to tune your model selection for cost and speed
- Security hardening guide to protect the credentials stored in your automation
Email automation is one of those things where the upfront investment pays dividends every single day. Set it up once, refine it over a few weeks, and reclaim hours you were spending on inbox management.