All posts
Guide·Jul 7, 2026·7 min read

How to give a Vercel AI SDK agent its own email inbox

Vercel AI SDK email: give an AI SDK agent a real inbox with AgenticEmail, then wire send and read tools with tool() and zod into generateText.

Dvir Atias

Dvir Atias

Founder

To give a Vercel AI SDK agent its own email inbox, create a real inbox with the AgenticEmail TypeScript SDK, then expose two tools to the model with the Vercel AI SDK's tool() helper: one that sends mail and one that reads it, each with a zod input schema. Pass those tools to generateText or streamText and the model can now send and read email as part of its reasoning loop. There is no dedicated Vercel AI SDK package to install; you wrap the AgenticEmail SDK in tool() yourself, or point the agent at the hosted MCP server, which the Vercel AI SDK also speaks. Either way the agent gets a live address it owns at runtime, not a shared human mailbox it borrows.

Why an AI SDK agent needs a real inbox

The Vercel AI SDK is great at giving a model tools, but a tool that "sends email" through your own account is not the same as the agent having an inbox. An agent that owns an address can receive replies, hold a thread, sign up for services, confirm a booking, and act on what lands in its inbox without a human relaying messages back and forth. That is the difference between an outbound notifier and an autonomous participant.

Real inboxes matter because email is the one identity primitive the outside world already accepts. Password resets, verification codes, vendor confirmations, and other agents all arrive by email. If your agent has no address, every one of those flows stalls on a human. Give it an address and the loop closes: the agent sends, the reply comes back to a mailbox it controls, and the model reads it on the next turn. For the broader case, see why AI agents need email.

Create an inbox with the AgenticEmail TypeScript SDK

Start by provisioning an inbox. AgenticEmail is API-first, so an inbox is just a call away and exists at runtime, not something you register by hand in a console.

import { AgenticEmail } from "agenticemail";

const client = new AgenticEmail({ apiKey: process.env.AGENTICEMAIL_API_KEY });

const inbox = await client.inboxes.create({ username: "research-agent" });

console.log(inbox.address); // research-agent@inbox.agenticemail.dev

Store inbox.id. Every send and read call is scoped to that inbox, so it is the handle your tools will close over. You can create one inbox per agent, or one per task if you want each run to get a fresh, disposable address.

Define send and read tools with tool() and zod

The Vercel AI SDK exposes capabilities to a model through tool(). Each tool has a description the model reads to decide when to call it, an inputSchema written in zod that validates and types the arguments, and an execute function that does the work. We give the agent two tools that call straight into the AgenticEmail SDK.

import { tool } from "ai";
import { z } from "zod";
import { AgenticEmail } from "agenticemail";

const client = new AgenticEmail({ apiKey: process.env.AGENTICEMAIL_API_KEY });
const inboxId = process.env.AGENTICEMAIL_INBOX_ID!;

export const sendEmail = tool({
  description: "Send an email from the agent's own inbox.",
  inputSchema: z.object({
    to: z.string().email().describe("Recipient email address"),
    subject: z.string().describe("Subject line"),
    text: z.string().describe("Plain-text body of the email"),
  }),
  execute: async ({ to, subject, text }) => {
    const message = await client.messages.send(inboxId, { to, subject, text });
    return { id: message.id, status: "sent" };
  },
});

export const readInbox = tool({
  description: "List recent messages in the agent's inbox and read their contents.",
  inputSchema: z.object({
    limit: z.number().int().min(1).max(50).default(10)
      .describe("How many recent messages to return"),
  }),
  execute: async ({ limit }) => {
    const messages = await client.messages.list(inboxId, { limit });
    return messages.map((m) => ({
      id: m.id,
      from: m.from,
      subject: m.subject,
      text: m.text,
      receivedAt: m.receivedAt,
    }));
  },
});

Two things carry the weight here. The zod schema is the contract: the model must produce a valid email address and a body before execute ever runs, so malformed tool calls fail at the boundary instead of hitting the API. And the description strings are prompt surface, not documentation, so write them for the model. "Send an email from the agent's own inbox" tells it exactly what the tool does and that the address is already the agent's own.

Pass the tools to generateText or streamText

Now hand the tools to the model. Set maxSteps above one so the agent can chain calls: read the inbox, reason about a reply, then send it, all inside a single generateText.

import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { sendEmail, readInbox } from "./email-tools";

const result = await generateText({
  model: anthropic("claude-sonnet-4-5"),
  tools: { sendEmail, readInbox },
  maxSteps: 5,
  prompt:
    "Check the inbox for any new sign-up confirmation, then reply to the sender " +
    "confirming the account is active.",
});

console.log(result.text);

streamText takes the identical tools and maxSteps options if you are rendering a live UI. The model decides when to call readInbox and when to call sendEmail; you are not orchestrating the sequence, only exposing the capability. That is the whole point of tools in the Vercel AI SDK, and email fits it cleanly because both actions are self-contained.

Handle inbound over a webhook

Polling with readInbox works for turn-based agents, but for a long-lived agent you want to react the moment mail arrives. Register a webhook once and AgenticEmail will push each inbound message to your endpoint.

await client.webhooks.create({
  url: "https://your-app.dev/api/agent/inbound",
  eventTypes: ["message.received"],
});

Your handler receives the parsed message and kicks off a fresh generateText with the same tools, so the agent processes the reply and can send a follow-up on its own. This turns the inbox into an event source that drives the agent, rather than something it has to remember to check. AgenticEmail also offers a WebSocket stream if you would rather hold a live connection than run a webhook endpoint.

Or skip the wrapper: the MCP path

The Vercel AI SDK can consume tools from an MCP server directly, and AgenticEmail ships a hosted one. Point the SDK's MCP client at it and inbox management, send, and read arrive as tools with no tool() wrappers to write and maintain yourself. It is the leanest path when you want the agent to have an inbox without owning any of the glue code, and it is a good fit alongside other MCP tools your agent already uses. See the MCP email server guide for setup, and the LangChain agent email inbox walkthrough if you also run agents on that stack.

A note on end-to-end encryption

When two of your agents talk to each other over email, the bodies can carry customer records, tokens, or raw tool output. AgenticEmail offers opt-in, agent-to-agent end-to-end encryption: it is zero-knowledge, the private key lives in your agent's runtime, and the platform only ever stores ciphertext. It is opt-in and applies between two AgenticEmail inboxes that have each published a key, not to inbound mail from the outside world. The details are in encrypted email for AI agents.

Ship it

The shape is small on purpose: create an inbox, wrap send and read in tool() with zod schemas, pass them to generateText or streamText, and add a webhook when you need inbound to be reactive. From there your Vercel AI SDK agent has a real address it owns and can act on. The full SDK reference lives in the docs, and if you are weighing options, the alternatives pages compare AgenticEmail with the usual inbox APIs.

Talk to a real person