All integrations
Vercel AI SDK·TS SDK·5 min read

Mails.ai with the Vercel AI SDK — tool definitions for serverless agents

sdk.vercel.ai
TS SDK

Install with `npm install ai @ai-sdk/anthropic @mailsai/sdk zod`. Then wrap mails.ai as tool() definitions:

import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { mails } from "@mailsai/sdk";

const client = mails({ apiKey: process.env.MAILS_API_KEY! });
const sarah = client.agent("sarah");

const sendEmail = tool({
  description: "Send an email from the sarah agent.",
  parameters: z.object({
    to: z.string().email(),
    subject: z.string(),
    body: z.string(),
  }),
  execute: async ({ to, subject, body }) => {
    const result = await sarah.send({ to, subject, body });
    return { send_id: result.id, pool: result.pool };
  },
});

const listThreads = tool({
  description: "List recent inbound threads on the sarah agent.",
  parameters: z.object({
    since_days: z.number().default(1),
  }),
  execute: async ({ since_days }) => {
    return await sarah.listThreads({ sinceDays: since_days });
  },
});

const result = await generateText({
  model: anthropic("claude-sonnet-4-6"),
  tools: { sendEmail, listThreads },
  prompt: "Email lead@example.com a follow-up about Tuesday's demo.",
});

Vercel AI SDK is the dominant TypeScript SDK for AI features in modern web apps — Next.js, SvelteKit, Nuxt, Remix all use it as the standard AI integration layer. Provider-agnostic (Anthropic, OpenAI, Google, Mistral, all behind one API). Wire mails.ai as tool() definitions and your serverless agent can send + read email as part of generateText, streamText, or experimental_streamUI flows.

Why Vercel AI SDK + mails.ai

The combination is opinionated for the most common modern web-app shape: Next.js + Vercel + Anthropic + serverless. mails.ai bolts onto that stack as a tool layer:

  • In-app AI chat that can email. User chats with your AI assistant in your Next.js app; the assistant offers to email a summary or follow-up; the SDK fires mails.send via the tool definition.
  • Server-Action-driven email automations.User clicks “email our sales team about my use case” in your form; a Server Action invokes generateText with the mails tool, drafts the email, sends it, returns confirmation.
  • Stream UI for live email composition. Use streamText with tool calls to show the agent drafting and sending in real-time, with the UI updating as tool results stream back.
  • Edge-runtime agents. The mails.ai SDK is fetch-based and edge- compatible. Latency-sensitive flows can run in edge runtime without trade-offs.

Setup

  1. Install dependencies. npm install ai @ai-sdk/anthropic @mailsai/sdk zod
  2. Set environment variables. MAILS_API_KEY for mails, ANTHROPIC_API_KEY for the model. Vercel project settings handle both.
  3. Define tool() wrappers. The pattern in the install card. Wrap mails.send, list_threads, and identity as needed by your use case.
  4. Bind to generateText / streamText. Pass the tools object as the tools parameter. The model picks tools by name during the conversation.

Common patterns

Server Action with tool-driven email:

// app/actions/contact.ts
"use server";

import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { mails } from "@mailsai/sdk";

const sarah = mails({ apiKey: process.env.MAILS_API_KEY! }).agent("sarah");

const sendEmail = tool({
  description: "Send an email from sarah.",
  parameters: z.object({
    to: z.string().email(),
    subject: z.string(),
    body: z.string(),
  }),
  execute: async ({ to, subject, body }) => {
    const r = await sarah.send({ to, subject, body });
    return { send_id: r.id };
  },
});

export async function emailSalesTeam(userMessage: string) {
  const { text } = await generateText({
    model: anthropic("claude-sonnet-4-6"),
    tools: { sendEmail },
    prompt: `User said: "${userMessage}". Email sales@ourcompany.com with a brief summary asking them to follow up.`,
  });
  return text;
}

Streaming chat with email tool:

// app/api/chat/route.ts
import { streamText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { mails } from "@mailsai/sdk";

const sarah = mails({ apiKey: process.env.MAILS_API_KEY! }).agent("sarah");

export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: anthropic("claude-sonnet-4-6"),
    messages,
    tools: {
      sendEmail: tool({
        description: "Send an email from sarah",
        parameters: /* ... */,
        execute: async (args) => sarah.send(args),
      }),
    },
  });
  return result.toDataStreamResponse();
}

Inbound webhook handling

For inbound replies, set up a Next.js Route Handler that receives the mails.ai webhook and processes the typed event:

// app/api/webhooks/mails-inbound/route.ts
import { NextRequest, NextResponse } from "next/server";
import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";

export async function POST(req: NextRequest) {
  const event = await req.json();

  // Refuse high-injection-score events at the door
  if (event.injection_score > 0.5) {
    return NextResponse.json({ ok: true, action: "refused_injection" });
  }

  // Use AI SDK to draft a response based on intent
  if (event.intent === "schedule_demo") {
    const { text } = await generateText({
      model: anthropic("claude-sonnet-4-6"),
      prompt: `Draft a calendar-confirmation reply for: ${event.body}`,
    });
    // Send it via mails.ai
    // ...
  }

  return NextResponse.json({ ok: true });
}

Security considerations

  • Server-side only. Tool executions run server-side (generateText/streamText in Server Actions or Route Handlers). The mails.ai key never reaches the browser.
  • Verify webhook signatures. Mails.ai webhooks are signed; verify the signature in your Route Handler before processing the event. Reject mismatches.
  • Per-route mails.ai key. If you have multiple agents (different brand voices, different use cases), use Vercel project environment variables to scope keys per-route.

Compare against the Anthropic SDK setup for a more direct integration when not on Vercel AI SDK, or OpenAI Agents SDK for the framework-driven approach.

FAQ

Questions developers ask after wiring this up.

Why no MCP-client integration like the Anthropic SDK has?

Vercel AI SDK is provider-agnostic — it normalizes Anthropic, OpenAI, Google, Mistral, etc., behind a single API. MCP-client support is on their roadmap but not yet first-class. The tool() helper pattern is the SDK's idiomatic way to add tools today and works identically with any model provider. When MCP-client lands in the SDK, swap to that for consistency with other runtimes.

Does this work with streamText / experimental_streamUI?

Yes. Tools fire during streaming the same way they fire in generateText. For streamUI, the tool result returns a React component spec the SDK can render — useful for showing 'Email sent: ID xyz' confirmations in the UI as the agent works.

Edge runtime or Node runtime — does it matter?

Both work. The @mailsai/sdk client is HTTP-based (just fetch under the hood) and edge-compatible. Edge wins for latency on simple send-and-confirm flows; Node wins if you have other Node-only dependencies (e.g., the React Email rendering pipeline). Pick based on your wider stack.

Can I use this with Server Actions in Next.js App Router?

Yes. Define the tools in a 'use server' file and call generateText from a Server Action invoked by your form/button. The mails.* tool calls happen server-side; the Action returns the agent's final response to the client. Common pattern for chat interfaces where the user types a request and the agent emails on their behalf.

Closed beta

Built for agents.
Self-serve at every volume.

Public API opens Q3 2026. Drop ~6 lines into your agent and ship.

npmpnpmbunpip
$ npm install @mailsai/sdk
Packages publish with cohort 1 · Q3 2026