> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Choose Your Platform"
        direction TB
        IMAP["📬 EmailBot<br/>IMAP / SMTP<br/>Self-hosted"]
        AM["⚡ AgentMailBot<br/>AgentMail API<br/>Zero-config"]
    end

    IMAP --> A[🧠 Agent]
    AM --> A

    classDef imap fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef am fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff

    class IMAP imap
    class AM am
    class A agent

    classDef tool fill:#189AB4,color:#fff

    classDef agent fill:#8B0000,color:#fff
```

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Feature as Email Bot

    User->>Agent: Request
    Agent->>Feature: Process request
    Feature-->>Agent: Result    Agent-->>User: Response
```

## Quick Start

<Tip>
  `Bot("email", agent=agent).run()` auto-reconnects on a dropped connection by default and stays supervised until the IMAP poll loop stops — see [Auto-reconnect on `long-running-bots`](/docs/docs/features/long-running-bots#auto-reconnect-default).
</Tip>

<Note>
  `praisonai bot email` and all four `agentmail` modes now stay running correctly. Previously these non-blocking adapters exited `0` in about a second, so `systemd Restart=on-failure` never restarted them. The CLI now holds the loop open while the adapter is running, and startup failures exit **1**.
</Note>

<Tabs>
  <Tab title="AgentMail (Recommended)">
    Zero-config email — no IMAP/SMTP setup. Get an email address instantly.

    <Steps>
      <Step title="Set API Key">
        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        export AGENTMAIL_API_KEY="am_..."
        ```
      </Step>

      <Step title="Start Bot">
        ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        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())
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="IMAP/SMTP (Self-Hosted)">
    Use your own Gmail, Outlook, or corporate email server.

    <Steps>
      <Step title="Set Environment Variables">
        ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        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"
        ```
      </Step>

      <Step title="Start Bot">
        ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
        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())
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

***

## Platform Comparison

| Feature | EmailBot (IMAP/SMTP) | AgentMailBot (API) |
| - | - | - |
| **Setup** | Email credentials + IMAP/SMTP config | API key only |
| **Email Address** | Your existing address | Auto-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 Latency** | 10-30s (poll interval) | \~250ms (WebSocket push) |
| **Dependencies** | None (stdlib) | `pip install agentmail` |
| **Best For** | Corporate/existing email | New projects, multi-inbox, real-time |

***

## Event-Driven Modes (AgentMail)

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

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    subgraph "Choose a Mode"
        Q{Need sub-second<br/>latency?}
        Q -->|No| Poll["poll<br/>10-30s latency<br/>Simple, backwards compat"]
        Q -->|Yes| Q2{Production or<br/>dev?}
        Q2 -->|Dev / single bot| WS["ws<br/>~250ms via WebSocket<br/>Auto-reconnect"]
        Q2 -->|Production| Q3{Want fallback?}
        Q3 -->|Yes| Hybrid["hybrid ★ Recommended<br/>WS + 60s poll fallback"]
        Q3 -->|No| Webhook["webhook<br/>~350ms via HTTP POST<br/>Horizontal scale"]
    end

    classDef default fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef rec fill:#10B981,stroke:#7C90A0,color:#fff

    class Poll,WS,Webhook default
    class Hybrid rec
```

| Mode | Trigger | Latency | Use Case |
| - | - | - | - |
| `poll` | Timer (default) | 10-30s | Backwards compat, simple |
| `ws` | AgentMail WebSocket push | \~250ms | Dev, single-bot, self-hosted |
| `webhook` | AgentMail HTTP POST | \~350ms | Production, horizontal scale |
| `hybrid` | WS primary + 60s poll fallback | \~250ms | **Recommended** — fast + reliable |

### YAML Configuration

````carousel theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
```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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
```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()
```
````

<Note>
  AgentMail preserves the historical `8080` default for `webhook_port` — it always binds its own server and does **not** participate in [Shared Webhook Ingress](/docs/features/shared-webhook-ingress) (documented behaviour, per PraisonAI PR #5246). Set `webhook_port` to pick its standalone port.
</Note>

### 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).

<Warning>
  The AgentMail API token is **no longer** used as a fallback signing secret. Configure `AGENTMAIL_WEBHOOK_SECRET` explicitly.
</Warning>

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](/docs/features/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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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 theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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
)
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Agent as 🤖 Agent
    participant Bot as 📧 AgentMailBot
    participant AM as ☁️ AgentMail

    Agent->>Bot: send_message(...)
    Note over Bot: derive ONE Idempotency-Key
    Bot->>AM: messages.send (Idempotency-Key: K)
    AM--xBot: timeout (email already accepted)
    Bot->>AM: retry (same Idempotency-Key: K)
    AM-->>Bot: 200 (deduplicated — no second email)
    Bot-->>Agent: BotMessage
```

<Note>
  The key is forwarded to AgentMail via the `Idempotency-Key` header. AgentMail honours it for 24 hours. Reuse the same key within that window to guarantee the send is dedup'd.
</Note>

***

## Inbox Lifecycle Management

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

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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"])
```

<Tip>
  Use `isinstance(bot, EmailProtocol)` to check if a bot supports inbox lifecycle management at runtime.
</Tip>

***

## Using as Agent Tools

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

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
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")
```

<Tip>
  Or use the email profile: `tools=resolve_profiles("email")` — includes send, list, read, reply.
</Tip>

<Tabs>
  <Tab title="AgentMail Backend">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    export AGENTMAIL_API_KEY="am_..."
    export AGENTMAIL_INBOX_ID="you@agentmail.to"
    # Same code, uses AgentMail API
    ```
  </Tab>

  <Tab title="Gmail / Outlook Backend">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    export EMAIL_ADDRESS="you@gmail.com"
    export EMAIL_PASSWORD="xxxx xxxx xxxx xxxx"
    # Same code, uses SMTP/IMAP
    ```
  </Tab>
</Tabs>

***

## 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

| Capability | EmailBot (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

| Variable | Platform | Default | Description |
| - | - | - | - |
| `AGENTMAIL_API_KEY` | AgentMail | — | AgentMail API key |
| `AGENTMAIL_INBOX_ID` | AgentMail | — | Existing inbox to connect to |
| `AGENTMAIL_DOMAIN` | AgentMail | — | Custom domain for new inboxes |
| `EMAIL_ADDRESS` | IMAP/SMTP | — | Bot email address |
| `EMAIL_APP_PASSWORD` | IMAP/SMTP | — | App Password (recommended) |
| `EMAIL_IMAP_SERVER` | IMAP/SMTP | `imap.gmail.com` | IMAP server |
| `EMAIL_SMTP_SERVER` | IMAP/SMTP | `smtp.gmail.com` | SMTP server |
| `EMAIL_POLL_INTERVAL` | Both | `60` / `10` | Seconds between checks |

### BotConfig Options

| Option | Type | Default | Description |
| - | - | - | - |
| `mode` | `str` | `"poll"` | Reception mode: `poll`, `ws`, `webhook`, `hybrid` |
| `webhook_url` | `str` | `None` | Public URL for webhook registration |
| `webhook_path` | `str` | `"/webhook"` | Webhook endpoint path |
| `webhook_port` | `Optional[int]` | `None` → `8080` | Standalone webhook server port. AgentMail always binds its own server (falls back to the historical `8080`) and does not use [Shared Webhook Ingress](/docs/features/shared-webhook-ingress) |
| `polling_interval` | `float` | `1.0` | Seconds between polls |

### `send_message` Options (AgentMail)

| Option | Type | Default | Description |
| - | - | - | - |
| `channel_id` | `str` | — | Recipient email address |
| `content` | `str \| dict` | — | Body string, or `{"subject": ..., "body": ...}` |
| `reply_to` | `str \| None` | `None` | Message-ID to reply to |
| `thread_id` | `str \| None` | `None` | Thread ID for conversation tracking |
| `idempotency_key` | `str \| None` | auto-generated UUID | Stable 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

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="Use Dedicated App Passwords">
    Never use your main account password. Generate a platform-specific App Password for the bot.
  </Accordion>

  <Accordion title="Configure Blocked Senders">
    Use `BotConfig.blocked_users` to exclude `noreply` addresses or known marketing domains.
  </Accordion>

  <Accordion title="Use AgentMail for Multi-Tenant">
    Need separate inboxes per customer? Use `AgentMailBot.create_inbox()` to provision on demand.
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Messaging Bots" icon="robot" href="/docs/features/messaging-bots">
    All supported messaging platforms
  </Card>

  <Card title="Bot Commands" icon="terminal" href="/docs/features/bot-commands">
    Register custom commands
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.