# Send & Receive Emails with Vercel AI SDK (/integrations/frameworks/ai-sdk)

<!-- agent-signals: reading_time_min: 5 · est_tokens: 2116 · updated: 2026-09-06 -->
Related: [Send & Receive Emails with Claude Cowork](/integrations/frameworks/claude-cowork.md), [Send & Receive Emails with Claude Code](/integrations/frameworks/claude-code.md), [Send & Receive Emails with OpenAI Codex](/integrations/frameworks/codex.md), [Send & Receive Emails with OpenClaw](/integrations/frameworks/openclaw.md), [Send & Receive Emails with Grok](/integrations/frameworks/grok.md), [Send & Receive Emails with Manus](/integrations/frameworks/manus.md)



# Give a Vercel AI SDK agent an email inbox

The `agentmail-toolkit` package exposes AgentMail operations as AI SDK `Tool` objects for `generateText` and `streamText`. Use it when an agent built on AI SDK 6 should create inboxes, send email, and read and reply to threads, from a script or from a Next.js route that fires on incoming mail.

## Do this

```bash
npm install agentmail-toolkit ai@6 @ai-sdk/openai@3
npm install -D tsx
npm pkg set type=module
export AGENTMAIL_API_KEY="<API_KEY>"
export OPENAI_API_KEY="<OPENAI_API_KEY>"
```

Save as `agent.ts`. Run scripts that import it with `npx tsx <script>.ts`:

```typescript
import { openai } from "@ai-sdk/openai";
import { AgentMailToolkit } from "agentmail-toolkit/ai-sdk";
import { generateText, stepCountIs } from "ai";

export async function runEmailAgent(prompt: string) {
  const result = await generateText({
    model: openai.chat("gpt-4o"),
    system:
      "You are an email agent with your own AgentMail inbox. " +
      "You can create inboxes, send email, and read and reply to threads.",
    prompt,
    tools: new AgentMailToolkit().getTools(),
    stopWhen: stepCountIs(10),
  });
  return result.text;
}
```

`openai.chat("gpt-4o")` and `stopWhen: stepCountIs(10)` are both load-bearing. See Not supported.

## SDK

Install: `npm install agentmail-toolkit ai@6 @ai-sdk/openai@3`

* Build the toolkit: `new AgentMailToolkit()` reads `AGENTMAIL_API_KEY` from the environment.
* Pass credentials another way: `new AgentMailToolkit(new AgentMailClient({ apiKey: "..." }))`.
* Get every tool, keyed by tool name: `new AgentMailToolkit().getTools()`. The object goes straight into `tools:`.
* Get a subset: `new AgentMailToolkit().getTools(["list_threads", "get_thread", "reply_to_message"])`.
* The same `tools` object works in `streamText`.
* Verify webhook deliveries with `svix` (`npm install svix`): `new Webhook(process.env.AGENTMAIL_WEBHOOK_SECRET).verify(rawBody, headers)` with headers `svix-id`, `svix-timestamp`, `svix-signature`.

Core SDK and CLI installs: /integrations/sdks-and-cli

## Facts

* The toolkit builds its tools for AI SDK 6. Pin `ai@6` together with the matching provider major, `@ai-sdk/openai@3`.
* The AI SDK's default stop condition is `stepCountIs(1)`. Without `stopWhen`, the run ends after the model's first tool call with empty `text`. Budget steps for the task's tool calls plus a final answer.
* `openai.chat("gpt-4o")` routes through the Chat Completions API. The provider default `openai("gpt-4o")` routes through the Responses API, where the model fills every optional tool field with empty strings and empty arrays, values the listing tools reject.
* A failed tool call does not end the run. The AI SDK records it as a `tool-error` part and feeds the error text back to the model, which can retry in its next step.
* Creating an inbox with a taken username fails with a `403` naming up to 3 available variants in `suggestions`. Creating past the plan's inbox cap fails with `403` `limit_exceeded`, an error that names the cap and the upgrade that raises it.
* Tools the page exercises: `create_inbox`, `send_message`, `list_threads`, `get_thread`, `reply_to_message`.
* A reply-only agent needs `list_threads`, `get_thread`, and `reply_to_message`. A webhook route needs only `get_thread` and `reply_to_message`, because the `message.received` event already names the `inbox_id` and `thread_id` that changed.
* Webhook deliveries are signed over the exact raw request body. Read it with `await request.text()` before parsing, verify with the subscription's signing secret stored as `AGENTMAIL_WEBHOOK_SECRET`, return `400` on failure and `200` otherwise.
* Nothing carries over between runs. Each prompt must name the inbox to operate on.
* Delivery takes about two seconds in each direction. An agent that reports an empty inbox most likely ran before the email arrived. Run it again.
* A Vercel Marketplace install already carries AgentMail credentials in the project environment: /integrations/marketplaces.
* A shell `export` covers only local runs. A deployed route needs `AGENTMAIL_API_KEY` in the project's environment settings.

## Not supported

* `ai@7` does not install next to the toolkit. npm refuses with a conflicting peer dependency error naming `ai@"^6.0.0-beta.150"`, the range the toolkit accepts.
* The Responses API route via `openai("gpt-4o")` does not work with the listing tools. Each `list_threads` call fails as `Type validation failed`, then `HTTP 400`, and the agent gives up.
* Unknown names in `getTools([...])` are silently dropped, leaving the agent with fewer tools than intended. Log `Object.keys(tools)` once to confirm the list.
* A missing `AGENTMAIL_API_KEY` does not fail the run. The run finishes with every email tool call erroring and the agent reporting it could not do the work.

## Errors

| Error                                                                                                       | Status              | Cause                                                         | Fix                                                                                                             |
| ----------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `AI_LoadAPIKeyError`                                                                                        | none, thrown        | `OPENAI_API_KEY` unset. Fails before any email tool runs      | Set `OPENAI_API_KEY`                                                                                            |
| `Please provide 'apiKey' when initializing the client, or set the 'AGENTMAIL_API_KEY' environment variable` | none, per tool call | `AGENTMAIL_API_KEY` unset where the process runs              | Set the variable in that environment. For a deployed route, the project's environment settings                  |
| `Type validation failed`, then `HTTP 400`                                                                   | 400                 | Model called through the Responses API via `openai("gpt-4o")` | Use `openai.chat("gpt-4o")`                                                                                     |
| Conflicting peer dependency naming `ai@"^6.0.0-beta.150"`                                                   | none, npm install   | `ai@7` installed next to the toolkit                          | Install `ai@6` with `@ai-sdk/openai@3`                                                                          |
| `403` with `suggestions` on `create_inbox`                                                                  | 403                 | Requested inbox username taken                                | Fed back to the model as a `tool-error`, so the agent retries with an available name. Or leave the username out |
| `limit_exceeded`                                                                                            | 403                 | Inbox creation at the plan's cap                              | The error names the cap and the upgrade that raises it                                                          |
| `invalid signature` from the webhook route                                                                  | 400                 | Signature did not verify over the raw body                    | Check `AGENTMAIL_WEBHOOK_SECRET` and verify the raw body before parsing                                         |

## Verify

Save as `tools.ts` and run `npx tsx tools.ts`:

```typescript
import { AgentMailToolkit } from "agentmail-toolkit/ai-sdk";
console.log(Object.keys(new AgentMailToolkit().getTools()));
```

Success prints the tool names, including `create_inbox`, `send_message`, `list_threads`, `get_thread`, and `reply_to_message`. This confirms the install, not the key. To confirm the key, run the send flow above and check that the email arrives.

## Related

* /advanced/webhooks - register the subscription the route needs and process deliveries exactly once
* /advanced/safety - keep untrusted email content from steering the agent
* /integrations/marketplaces - AgentMail credentials provisioned through the Vercel Marketplace
* /integrations/mcp-and-skills - hosted MCP server alternative to the toolkit
