Email for CrewAI Agents

Give every CrewAI agent its own inbox. Create inboxes via API, deliver inbound emails as structured JSON, and handle full conversation threads — no SMTP config, no deliverability headaches.

How OpenMail works with CrewAI

Create an inbox per agent

One API call provisions a live inbox on your domain and returns the address immediately. Map the inbox_id to your CrewAI agent for routing.

import os, requests

OPENMAIL_API_KEY = os.environ["OPENMAIL_API_KEY"]

def create_agent_inbox(agent_name: str) -> dict:
    response = requests.post(
        "https://api.openmail.sh/v1/inboxes",
        headers={"Authorization": f"Bearer {OPENMAIL_API_KEY}"},
        json={"mailboxName": agent_name},
    )
    response.raise_for_status()
    inbox = response.json()
    # inbox["id"]      → "inb_8f3a1b2c"
    # inbox["address"] → "agent@yourdomain.com"
    return inbox

Pass credentials to your CrewAI agent

Three environment variables. The API key is shared across agents; inbox ID and address are unique per agent. Pass them as tools or environment variables to your CrewAI agent.

OPENMAIL_API_KEY=om_...
OPENMAIL_INBOX_ID=inb_8f3a1b2c
OPENMAIL_ADDRESS=agent@yourdomain.com

Send and reply from the agent

Your CrewAI agent sends email via the API. Save the threadId to reply in the same thread later and keep conversations threaded correctly in the recipient's client.

import os, requests

def send_email(to: str, subject: str, body: str, thread_id: str = None) -> dict:
    payload = {"to": to, "subject": subject, "body": body}
    if thread_id:
        payload["threadId"] = thread_id
    response = requests.post(
        f"https://api.openmail.sh/v1/inboxes/{os.environ['OPENMAIL_INBOX_ID']}/send",
        headers={"Authorization": f"Bearer {os.environ['OPENMAIL_API_KEY']}"},
        json=payload,
    )
    return response.json()

Receive inbound emails as structured events

Connect via WebSocket — no public URL needed. When an email arrives, OpenMail fires an event with the parsed message body, thread context, and any extracted attachments. Route by inbox_id to the correct CrewAI agent.

import asyncio, json, os, websockets

async def listen():
    uri = "wss://api.openmail.sh/v1/ws"
    headers = {"Authorization": f"Bearer {os.environ['OPENMAIL_API_KEY']}"}
    async for ws in websockets.connect(uri, extra_headers=headers):
        try:
            await ws.send(json.dumps({"type": "subscribe"}))
            async for raw in ws:
                event = json.loads(raw)
                if event.get("event") == "message.received":
                    inbox_id = event["inbox_id"]
                    message = event["message"]
                    # Route to the correct CrewAI agent by inbox_id
        except websockets.ConnectionClosed:
            continue

asyncio.run(listen())

What your CrewAI agent can do with email

Send emails autonomously from a branded address on your domain

Receive replies in real time via WebSocket — no polling

Read full thread history as structured JSON for agent context

Parse PDF, CSV, and DOCX attachments automatically

Handle OTP codes and verification links for autonomous signup flows

What's included

Dedicated inbox per agent

Each CrewAI agent gets its own address on your domain — no shared inboxes, no filtering logic.

Real-time inbound delivery

WebSocket events delivered in under 500ms. Your agent receives email the moment it arrives.

Full thread history as structured JSON

Pull complete conversation context via the history endpoint and feed it directly into your agent's context window.

Attachment parsing

PDF, CSV, and DOCX files automatically extracted to plain text. Your agent gets the content without handling MIME types.

Managed deliverability

SPF, DKIM, and DMARC configured automatically on provisioning. Primary inbox from day one.

Works with any CrewAI version

REST API, no additional SDK required. Any CrewAI agent that can make HTTP requests works with OpenMail.

Frequently asked questions

Every CrewAI agent deserves its own inbox.