Email Bot

Deploy AI agents to handle email via IMAP/SMTP or the zero-config AgentMail API with event-driven modes

Email bots connect your AI agents to email — choose AgentMail (zero-config API) or IMAP/SMTP (self-hosted).

python
import os
import asyncio
from praisonai.bots import AgentMailBot
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Handle emails concisely")
bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent)
asyncio.run(bot.start())

The user sends mail to the inbox; the agent reads threads, drafts replies, and sends responses via AgentMail or IMAP/SMTP.

Diagram

Choose Your Platform

📬 EmailBot
IMAP / SMTP
Self-hosted

⚡ AgentMailBot
AgentMail API
Zero-config

🧠 Agent

How It Works

Diagram
Email BotAgentUserEmail BotAgentUserRequestProcess requestResult Agent–>>User: Response

Quick Start

AgentMail (Recommended)

Zero-config email — no IMAP/SMTP setup. Get an email address instantly.

  1. Set API Key
    bash
    export AGENTMAIL_API_KEY="am_..."
  2. Start Bot
    python
    import os
    import asyncio
    from praisonai.bots import AgentMailBot
    from praisonaiagents import Agent
    
    agent = Agent(name="assistant", instructions="Handle emails concisely")
    bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent)
    asyncio.run(bot.start())

IMAP/SMTP (Self-Hosted)

Use your own Gmail, Outlook, or corporate email server.

  1. Set Environment Variables
    bash
    export EMAIL_ADDRESS="your-bot@gmail.com"
    export EMAIL_APP_PASSWORD="xxxx xxxx xxxx xxxx"
    # Optional: defaults to Gmail
    export EMAIL_IMAP_SERVER="imap.gmail.com"
    export EMAIL_SMTP_SERVER="smtp.gmail.com"
  2. Start Bot
    python
    import asyncio
    from praisonai.bots import Bot
    from praisonaiagents import Agent
    
    agent = Agent(name="assistant", instructions="Handle emails professionally")
    bot = Bot("email", agent=agent)
    asyncio.run(bot.start())

Platform Comparison

FeatureEmailBot (IMAP/SMTP)AgentMailBot (API)
SetupEmail credentials + IMAP/SMTP configAPI key only
Email AddressYour existing addressAuto-generated (@agentmail.to)
Custom Domains✅ Any provider✅ Via create_inbox(domain=...)
Inbox Lifecycle❌ Manual✅ create_inbox() / delete_inbox()
Event-Driven Modes❌ Poll only✅ poll, ws, webhook, hybrid
Fastest Latency10-30s (poll interval)~250ms (WebSocket push)
DependenciesNone (stdlib)pip install agentmail
Best ForCorporate/existing emailNew projects, multi-inbox, real-time

Event-Driven Modes (AgentMail)

AgentMailBot supports 4 reception modes. Choose based on your latency and reliability needs.

Diagram

Choose a Mode

No

Yes

Dev / single bot

Production

Yes

No

Need sub-second
latency?

poll
10-30s latency
Simple, backwards compat

Production or
dev?

ws
~250ms via WebSocket
Auto-reconnect

Want fallback?

hybrid ★ Recommended
WS + 60s poll fallback

webhook
~350ms via HTTP POST
Horizontal scale

ModeTriggerLatencyUse Case
pollTimer (default)10-30sBackwards compat, simple
wsAgentMail WebSocket push~250msDev, single-bot, self-hosted
webhookAgentMail HTTP POST~350msProduction, horizontal scale
hybridWS primary + 60s poll fallback~250msRecommended — fast + reliable

YAML Configuration

carousel
```yaml
# Poll (default — omit mode)
channels:
  agentmail:
    token: ${AGENTMAIL_API_KEY}
```
<!-- slide -->
```yaml
# WebSocket (simplest event-driven)
channels:
  agentmail:
    token: ${AGENTMAIL_API_KEY}
    mode: ws
```
<!-- slide -->
```yaml
# Webhook (production, scalable)
channels:
  agentmail:
    token: ${AGENTMAIL_API_KEY}
    mode: webhook
    webhook_url: https://my-server.com
    webhook_port: 8080          # AgentMail always binds its own server (historical 8080 default)
```
<!-- slide -->
```yaml
# Hybrid (recommended)
channels:
  agentmail:
    token: ${AGENTMAIL_API_KEY}
    mode: hybrid
```

Python API

carousel
```python
import os
# Poll (default)
bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent)
await bot.start()
```
<!-- slide -->
```python
# WebSocket — sub-second
bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent, mode="ws")
await bot.start()
```
<!-- slide -->
```python
# Hybrid — recommended
bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent, mode="hybrid")
await bot.start()
```
<!-- slide -->
```python
# Webhook — production
bot = AgentMailBot(
    token=os.getenv("AGENTMAIL_API_KEY"), agent=agent,
    mode="webhook", webhook_port=9090
)
await bot.start()
```

Webhook Verification

When using mode: webhook, set AGENTMAIL_WEBHOOK_SECRET in production. An unset secret causes all inbound webhooks to be rejected with HTTP 401 (fail-closed).

Accepted signature headers: X-AgentMail-Signature, X-Webhook-Signature, X-Signature.

For local development without a real AgentMail webhook, set PRAISONAI_INSECURE_WEBHOOKS=true — never in production. See Webhook Verification.


Duplicate protection on retries

AgentMailBot derives one stable AgentMail Idempotency-Key per outbound send and reuses it across every retry (the outbound resilience layer retries up to 3× by default). If a send succeeds on AgentMail but the client times out, the retry is deduplicated at the provider — the recipient gets exactly one email.

python
import os
import asyncio
from praisonai.bots import AgentMailBot
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Reply concisely")
bot = AgentMailBot(token=os.getenv("AGENTMAIL_API_KEY"), agent=agent)

# Default: a UUID is auto-generated per logical send
asyncio.run(bot.send_message(
    channel_id="user@example.com",
    content={"subject": "Hi", "body": "hello"},
))

Pass your own key when you need deterministic replay across process restarts — for example a key derived from a durable job or webhook id:

python
# Advanced: reuse a stable key so a re-send is dedup'd by AgentMail
await bot.send_message(
    channel_id="user@example.com",
    content={"subject": "Order confirmation", "body": "..."},
    idempotency_key=f"order-{order_id}",   # 1–256 chars, honoured by AgentMail for 24h
)
Diagram
☁️ AgentMail📧 AgentMailBot🤖 Agent☁️ AgentMail📧 AgentMailBot🤖 Agentderive ONE Idempotency-Keysend_message(…)messages.send (Idempotency-Key: K)timeout (email already accepted)retry (same Idempotency-Key: K)200 (deduplicated — no second email)BotMessage

Inbox Lifecycle Management

AgentMailBot implements the EmailProtocol from the core SDK, enabling programmatic inbox creation:

python
# Create a new inbox
inbox = await bot.create_inbox(domain="mycompany.com")
print(inbox["email_address"])  # support-abc@mycompany.com

# List all inboxes
inboxes = await bot.list_inboxes()

# Delete an inbox
await bot.delete_inbox(inbox["id"])

Using as Agent Tools

Don’t need a full bot? Use email as one-shot agent tools — auto-detects backend from env vars:

python
from praisonaiagents import Agent
from praisonaiagents.tools import (
    send_email, list_emails, read_email, reply_email,
    search_emails, archive_email, draft_email, resolve_profiles,
)

agent = Agent(
    name="Mailer",
    instructions="Send, read, and manage emails",
    tools=[send_email, list_emails, read_email, reply_email, search_emails, archive_email, draft_email],
)

agent.start("Search my inbox for emails from Bob and archive the old ones")

AgentMail Backend

bash
export AGENTMAIL_API_KEY="am_..."
export AGENTMAIL_INBOX_ID="you@agentmail.to"
# Same code, uses AgentMail API

Gmail / Outlook Backend

bash
export EMAIL_ADDRESS="you@gmail.com"
export EMAIL_PASSWORD="xxxx xxxx xxxx xxxx"
# Same code, uses SMTP/IMAP

Shared Features

Both EmailBot and AgentMailBot share these capabilities:

  • Auto-Reply Prevention: Detects Auto-Submitted headers and common bot addresses to prevent infinite loops.
  • Blocked Sender Filtering: Configurable via BotConfig.blocked_users.
  • Email Address Extraction: Parses "Name <email>" format consistently.
  • Session Isolation: Per-sender AgentState for independent conversations.
  • Command Handling: Subject-based commands (e.g., START:, STOP:).
  • Thread Correlation: In-Reply-To and References headers maintained.

Capabilities Matrix

CapabilityEmailBot (IMAP)AgentMailBot
Receive email (poll)✅✅
Receive email (WebSocket)❌✅
Receive email (webhook)❌✅
Receive email (hybrid)❌✅
Send / reply email✅✅
Sub-second latency❌✅ (~250ms)
Auto-reconnect❌✅ (1s→60s backoff)
No missed messages❌ (poll gaps)✅ (hybrid mode)
Webhook server + health check❌✅ (GET /health)
YAML mode: config❌✅
Graceful shutdown (all modes)⚠️ Poll only✅ All modes
Async client❌✅ (lazy AsyncAgentMail)

Configuration

Environment Variables

VariablePlatformDefaultDescription
AGENTMAIL_API_KEYAgentMail—AgentMail API key
AGENTMAIL_INBOX_IDAgentMail—Existing inbox to connect to
AGENTMAIL_DOMAINAgentMail—Custom domain for new inboxes
EMAIL_ADDRESSIMAP/SMTP—Bot email address
EMAIL_APP_PASSWORDIMAP/SMTP—App Password (recommended)
EMAIL_IMAP_SERVERIMAP/SMTPimap.gmail.comIMAP server
EMAIL_SMTP_SERVERIMAP/SMTPsmtp.gmail.comSMTP server
EMAIL_POLL_INTERVALBoth60 / 10Seconds between checks

BotConfig Options

OptionTypeDefaultDescription
modestr"poll"Reception mode: poll, ws, webhook, hybrid
webhook_urlstrNonePublic URL for webhook registration
webhook_pathstr"/webhook"Webhook endpoint path
webhook_portOptional[int]None → 8080Standalone webhook server port. AgentMail always binds its own server (falls back to the historical 8080) and does not use Shared Webhook Ingress
polling_intervalfloat1.0Seconds between polls

send_message Options (AgentMail)

OptionTypeDefaultDescription
channel_idstr—Recipient email address
content`str \dict`—Body string, or {"subject": ..., "body": ...}
reply_to`str \None`NoneMessage-ID to reply to
thread_id`str \None`NoneThread ID for conversation tracking
idempotency_key`str \None`auto-generated UUIDStable key forwarded as AgentMail’s Idempotency-Key header. The same value is reused across retries of one logical send, so a timeout-after-send never duplicates the email. 1–256 chars; 24h key lifetime per AgentMail.

Best Practices

Use Hybrid Mode for Production

mode: hybrid gives sub-second latency via WebSocket with a 60-second poll fallback to catch any missed messages. Best of both worlds.

Use Dedicated App Passwords

Never use your main account password. Generate a platform-specific App Password for the bot.

Configure Blocked Senders

Use BotConfig.blocked_users to exclude noreply addresses or known marketing domains.

Use AgentMail for Multi-Tenant

Need separate inboxes per customer? Use AgentMailBot.create_inbox() to provision on demand.


Related