How It Works

Stagehand (by Browserbase, v4 as of August 2026) extends browser agents with external capabilities through MCP — you pass MCP servers to stagehand.agent() via the integrations array. Dead Simple Email runs a hosted MCP server at https://api.deadsimple.email/mcp, so your browser agent gets 14 email tools alongside its browsing tools: create_inbox, send_email, wait_for_email, get_verification_code, get_verification_link, and more.

That combination unlocks the flows browser agents usually stall on: the agent can invent its own identity (a fresh inbox), sign up for a service, and complete email verification without a human checking a mailbox.

Quick Start

Stagehand's integrations array accepts plain URL strings for MCP servers that take API keys as query parameters. Dead Simple Email authenticates with an Authorization header instead (keys stay out of URLs and logs), so connect with connectToMCPServer and pass the client in:

signup_agent.ts
import { Stagehand, connectToMCPServer } from "@browserbasehq/stagehand";

// Connect the email MCP server with header auth
const emailServer = await connectToMCPServer({
  serverUrl: "https://api.deadsimple.email/mcp",
  requestOptions: {
    requestInit: {
      headers: { Authorization: `Bearer ${process.env.DSE_API_KEY}` },
    },
  },
});

const stagehand = new Stagehand({ env: "BROWSERBASE" });
await stagehand.init();

const agent = stagehand.agent({
  integrations: [emailServer],
});

const result = await agent.execute(
  "Create a new email inbox, then sign up at https://example.com/signup " +
  "using that address. Wait for the verification email, extract the code, " +
  "and enter it to finish the signup."
);

console.log(result.message);

One instruction, end to end: the agent calls create_inbox, fills the form with the returned address using its browser tools, calls get_verification_code (which waits for the email and extracts the OTP), and types the code into the page.

The Signup / OTP Pattern

This is the flow Stagehand + email is built for, and it's worth understanding the two tools doing the heavy lifting:

  1. create_inbox — mints a real, receivable email address in about a second. One inbox per signup keeps identities isolated.
  2. wait_for_email — blocks until a message matching a sender or subject filter arrives, so the agent doesn't race the email.
  3. get_verification_code — waits like wait_for_email, then extracts the OTP from the message body automatically and returns just the code.
  4. get_verification_link — same, but returns the confirmation / magic-link URL, which the agent can open in the browser directly.

Inbound messages are also scanned for prompt injection before your agent reads them, which matters when a browser agent is acting autonomously on email content.

Alternative: Drive the SDK Between Browser Steps

If you orchestrate Stagehand imperatively with page.act() rather than handing control to stagehand.agent(), skip MCP and call the TypeScript SDK directly (npm install deadsimple-email):

imperative_flow.ts
import { DeadSimple } from "deadsimple-email";

const dse = new DeadSimple(process.env.DSE_API_KEY!);
const page = stagehand.page;

// 1. Mint an inbox for this signup
const inbox = await dse.inboxes.create({ displayName: "signup-bot" });

// 2. Fill the form in the browser
await page.goto("https://example.com/signup");
await page.act(`type "${inbox.email}" into the email field`);
await page.act("click the sign up button");

// 3. Wait for the OTP email — extracted codes ride along on the message
const msg = await dse.messages.waitFor(inbox.inbox_id, {
  subjectContains: "verify",
  timeoutMs: 90_000,
});
const code = msg?.extracted?.verification_code;

// 4. Finish the flow
await page.act(`type "${code}" into the verification code field`);
await page.act("click the confirm button");

waitFor polls the inbox until a matching inbound message arrives, and verification codes and links are extracted server-side onto message.extracted — no regex on your side.

Frequently Asked Questions

Because the web keeps emailing your agent. Signup forms want an address, login flows send OTP codes, and confirmations arrive as messages. With a real inbox of its own, the agent completes those loops autonomously — no shared human mailbox, no manual code copying.

URL strings work for MCP servers that accept API keys as query parameters. Dead Simple Email deliberately authenticates with an Authorization: Bearer header so keys stay out of URLs and request logs — use connectToMCPServer with requestOptions headers and pass the connected client, as shown above.

The get_verification_code tool polls the inbox until a matching message arrives, then extracts the code from the body automatically — the agent gets back a short string it can type into the form. get_verification_link does the same for magic links and confirmation URLs.

Yes. When you orchestrate the browser imperatively with page.act(), call the TypeScript SDK between steps — create the inbox, fill the form, waitFor the email, enter the extracted code. The full pattern is in the last example above.

Yes. The free tier includes 5 inboxes and 5,000 emails per month, requires no credit card, and does not expire.

Ready to build?

Free tier: 5 inboxes and 5,000 emails a month. No credit card required.

API Reference Get Started Free