Email-Capable AI Agents at the Edge

Build Cloudflare Workers that send, read, and manage email through MultiMail's API — with human oversight and zero cold starts.


Cloudflare Workers run at the edge with sub-millisecond cold starts, making them ideal for responsive AI agents. By integrating MultiMail, your Workers gain full email capabilities: sending messages, checking inboxes, replying to threads, and managing contacts — all from edge locations worldwide.

MultiMail itself runs on Cloudflare's infrastructure, which means API calls from your Worker to MultiMail stay within Cloudflare's network for minimal latency. The REST API uses standard fetch, which is native to the Workers runtime with no additional dependencies needed.

Combined with Durable Objects for agent state and Workers AI for inference, you can build complete email-handling agents that process incoming messages, draft responses, and manage approval queues entirely at the edge.

Built for Cloudflare Workers developers

Same Network, Low Latency

MultiMail runs on Cloudflare. API calls from your Worker stay within Cloudflare's network, avoiding extra network hops and delivering consistently low response times for email operations.

No Dependencies Required

The Workers runtime has fetch built in. Calling the MultiMail API requires no npm packages — just standard HTTP requests. This keeps your Worker bundle small and deploy times fast.

Durable Object State for Agents

Use Durable Objects to maintain agent state across requests. Track conversation context, pending approvals, and contact history in a Durable Object while using MultiMail for the actual email operations.

Event-Driven Email Processing

Combine MultiMail webhooks with Workers to process incoming emails in real time. When a new email arrives, MultiMail can trigger your Worker to analyze it, draft a response, and queue it for approval.

Workers AI + Email

Use Workers AI for on-device inference to analyze incoming emails, classify intent, and generate responses — then send those responses through MultiMail's API with oversight controls.


Get started in minutes

Basic Email Worker
typescript
interface Env {
  MULTIMAIL_API_KEY: string;
}

const MULTIMAIL_API = 'https://api.multimail.dev/v1';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const headers = {
      'Authorization': `Bearer ${env.MULTIMAIL_API_KEY}`,
      'Content-Type': 'application/json',
    };

    if (url.pathname === '/send' && request.method === 'POST') {
      const body = await request.json<{
        mailbox_id: string;
        to: string;
        subject: string;
        body: string;
      }>();
      const resp = await fetch(`${MULTIMAIL_API}/send`, {
        method: 'POST',
        headers,
        body: JSON.stringify(body),
      });
      return new Response(await resp.text(), {
        status: resp.status,
        headers: { 'Content-Type': 'application/json' },
      });
    }

    if (url.pathname.startsWith('/inbox/')) {
      const mailboxId = url.pathname.split('/')[2];
      const resp = await fetch(
        `${MULTIMAIL_API}/mailboxes/${mailboxId}/inbox?limit=10`,
        { headers }
      );
      return new Response(await resp.text(), {
        headers: { 'Content-Type': 'application/json' },
      });
    }

    return new Response('Not Found', { status: 404 });
  },
};

A Cloudflare Worker that exposes email send and inbox endpoints using MultiMail's API.

Webhook Handler for Incoming Email
typescript
interface Env {
  MULTIMAIL_API_KEY: string;
  AI: Ai;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }

    const webhook = await request.json<{
      event: string;
      message_id: string;
      from: string;
      subject: string;
      body: string;
    }>();

    if (webhook.event !== 'email.received') {
      return new Response('OK');
    }

    "cm">// Use Workers AI to generate a reply
    const aiResponse = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
      messages: [
        {
          role: 'system',
          content: 'Draft a brief, professional reply to this email.',
        },
        {
          role: 'user',
          content: `From: ${webhook.from}\nSubject: ${webhook.subject}\n\n${webhook.body}`,
        },
      ],
    });

    "cm">// Send reply through MultiMail (queued in gated_send mode)
    await fetch('https://api.multimail.dev/v1/reply', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${env.MULTIMAIL_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        message_id: webhook.message_id,
        body: aiResponse.response,
      }),
    });

    return new Response('OK');
  },
};

Process incoming emails from MultiMail webhooks and generate AI-powered responses.

Durable Object Email Agent
typescript
import { DurableObject } from 'cloudflare:workers';

interface Env {
  MULTIMAIL_API_KEY: string;
  EMAIL_AGENT: DurableObjectNamespace;
}

export class EmailAgent extends DurableObject {
  private headers: Record<string, string>;

  constructor(ctx: DurableObjectState, env: Env) {
    super(ctx, env);
    this.headers = {
      'Authorization': `Bearer ${env.MULTIMAIL_API_KEY}`,
      'Content-Type': 'application/json',
    };
  }

  async processInbox(mailboxId: string): Promise<object> {
    "cm">// Fetch new emails
    const resp = await fetch(
      `https:"cm">//api.multimail.dev/v1/mailboxes/${mailboxId}/inbox?limit=5`,
      { headers: this.headers }
    );
    const inbox = await resp.json<{ messages: any[] }>();

    "cm">// Track processed messages in Durable Object storage
    const processed = (await this.ctx.storage.get<string[]>('processed')) || [];
    const newMessages = inbox.messages.filter(
      (m: any) => !processed.includes(m.id)
    );

    "cm">// Mark as processed
    const allProcessed = [...processed, ...newMessages.map((m: any) => m.id)];
    await this.ctx.storage.put('processed', allProcessed);

    return { new_count: newMessages.length, messages: newMessages };
  }

  async sendReply(messageId: string, body: string): Promise<object> {
    const resp = await fetch('https://api.multimail.dev/v1/reply', {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify({ message_id: messageId, body }),
    });
    return resp.json();
  }
}

A stateful email agent using Durable Objects to maintain conversation context across requests.

Wrangler Configuration
toml
# wrangler.toml
name = "email-agent"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[durable_objects]
bindings = [
  { name = "EMAIL_AGENT", class_name = "EmailAgent" }
]

[[migrations]]
tag = "v1"
new_classes = ["EmailAgent"]

# Set your API key as a secret:
# npx wrangler secret put MULTIMAIL_API_KEY

Configure your Worker with the MultiMail API key as a secret.


Step by step

1

Create a MultiMail Account

Sign up at multimail.dev, create a mailbox, and generate an API key.

2

Scaffold a Worker Project

Create a new Cloudflare Worker project using Wrangler.

bash
npm create cloudflare@latest email-agent -- --type worker-typescript
3

Store Your API Key

Add your MultiMail API key as a Worker secret so it is not exposed in source code.

bash
npx wrangler secret put MULTIMAIL_API_KEY
4

Implement Email Endpoints

Write fetch handlers that call the MultiMail API. Use the env.MULTIMAIL_API_KEY binding for authentication.

5

Deploy and Test

Deploy your Worker and test the email integration. Set up a MultiMail webhook pointing to your Worker URL for incoming email processing.

bash
npx wrangler deploy

Common questions

Do I need any npm packages to call the MultiMail API?
No. Cloudflare Workers have fetch built into the runtime. You can call the MultiMail REST API directly with standard HTTP requests. This keeps your Worker bundle minimal and avoids compatibility issues with Node.js-specific packages.
How do I handle MultiMail webhooks in a Worker?
Create a POST endpoint in your Worker that receives webhook payloads from MultiMail. Configure the webhook URL in your MultiMail dashboard to point to your Worker's URL. The Worker processes the event (e.g., new email received) and can reply or take other actions via the API.
Can I use Workers AI with MultiMail?
Yes. Workers AI provides LLM inference at the edge. Use it to analyze incoming emails, generate reply drafts, or classify messages. Then use MultiMail's API to send the generated responses. This keeps the entire pipeline — inference and email delivery — at the edge.
How do Durable Objects help with email agents?
Durable Objects provide persistent state for your agent. You can track which messages have been processed, store conversation context for ongoing threads, maintain a queue of pending actions, and implement rate limiting. The Durable Object persists between Worker invocations.
Is the MultiMail API compatible with the Workers runtime?
Yes. MultiMail's REST API uses standard HTTP with JSON payloads, which is fully compatible with the Workers runtime. There are no Node.js-specific dependencies or WebSocket requirements. All API calls work with the built-in fetch function.
What about email processing latency?
Since both your Worker and MultiMail run on Cloudflare's network, API calls benefit from internal routing with minimal network hops. A typical send or inbox check completes in under 100ms. Combined with Workers' zero cold start times, your email agent responds near-instantly.

Explore more

The only agent email with a verifiable sender

Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 38-tool MCP server. Formally verified in Lean 4.