cd /news/ai-agents/how-can-an-ai-agent-read-an-email-ve… · home › topics › ai-agents › article
[ARTICLE · art-141660] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

How can an AI agent read an email verification code without writing a regex?

Agentboxd released an email verification API that lets AI agents extract sign-up codes and confirmation links without regex, using a server-side pattern matcher plus an AI classifier that returns a confidence score. The endpoint GET /v1/inboxes/:id/verification (SDK waitForVerification, MCP get_verification_code) holds a request open for up to 60 seconds until a verification email newer than a supplied timestamp arrives, avoiding polling loops and stale codes. Pattern matching alone caps confidence at 0.7, while the classifier raises it to 0.95 on a clear verification email and drops it to 0.2 on a clear negative.

by read5 min views1 publishedSep 29, 2026

Sign-up forms stop agents with “we sent you a code”. The obvious fix, a six-digit regex over the inbox, works in a demo and breaks on real mail. Here is why, and the one call that replaces it.

TL;DR Give the agent its own inbox, note the time, trigger the email, then call GET /v1/inboxes/:id/verification (SDK waitForVerification, MCP get_verification_code). It waits up to 60 seconds and returns the code or link with a confidence score. The extraction runs on our server the moment the email arrives, and an AI check confirms it is really a verification email.

Because verification emails are full of other numbers. Order numbers, dates, prices, phone numbers, copyright years and ticket IDs all look like codes to \d{6}. And many codes don’t look like six digits at all: some are four or eight digits, some are letters and digits, some are split by a space or a hyphen.

// The usual first attempt
const code = message.text.match(/\b\d{6}\b/)?.[0];

// What it finds in real sign-up emails:
//   "Order 482913 confirmed"          → 482913   (an order number)
//   "© 2026 Example Inc."             → no match, but "2026" at 4 digits would be
//   "Call +1 415 555 0199"            → no match, or part of a phone number
//   "Your code: KQ7-M2X"              → no match (letters and a hyphen)
//   "G-583920 is your Google code"    → 583920, luckily

Links are worse. A sign-up email has a confirm button, but also “log in”, “manage preferences”, “unsubscribe”, tracking pixels and a privacy policy. Taking the first link can unsubscribe the agent instead of confirming it. And an agent that polls the inbox in a loop either waits too long or reads the previous code.

Every inbound email is checked for a code or link the moment it is stored, before your agent asks. The rules favour precision, because a wrong code is worse than none: the agent can always read the message itself.

482 913 → 482913, KQ7-M2X → KQ7M2X, G-583920 → 583920). On top of the pattern match, an AI classifier reads the email and answers one question: is this a login, one-time-code or confirm-your-email message? Pattern matching alone is capped at a confidence of 0.7. A clear yes from the classifier raises it to 0.95; a clear no drops it to 0.2. The classifier’s own answer is returned too, as jev_probability. How the classifier works is in How we classify every email an AI agent receives.

Three steps: note the time, trigger the email, wait. The wait endpoint holds the request open until a verification email newer than since arrives, up to 60 seconds, and returns the newest one, since the latest code is the valid one. No polling loop, no sleep.

import { Agentboxd } from 'agentboxd';

const mr = new Agentboxd({ apiKey: process.env.AGENTBOXD_API_KEY! });

// 1. Note the time BEFORE triggering the email, so an older code can't be picked up.
const since = new Date().toISOString();

// 2. Trigger the sign-up (browser automation, an API call, whatever your agent does).
await signUpOnTheSite({ email: inbox.address });

// 3. Wait up to 60 seconds for the code or link to arrive.
const v = await mr.messages.waitForVerification(inbox.id, { since, timeout: 60, from: 'example.com' });

if (!v) throw new Error('no verification email within 60 s');
if (v.confidence < 0.9) console.warn('low confidence: read the message', v.message_id);

await enterCode(v.code ?? undefined); // or open v.link
python
from datetime import datetime, timezone
from agentboxd import Agentboxd

mr = Agentboxd()  # reads AGENTBOXD_API_KEY

since = datetime.now(timezone.utc).isoformat()
sign_up_on_the_site(email=inbox["address"])

v = mr.messages.wait_for_verification(inbox["id"], timeout=60, since=since, from_="example.com")
if v is None:
    raise TimeoutError("no verification email within 60 s")
print(v["code"] or v["link"], v["confidence"])
curl -s "https://api.agentboxd.com/v1/inboxes/$INBOX_ID/verification?timeout=60&since=2026-09-29T10:00:00Z&from=example.com" \
  -H "Authorization: Bearer $AGENTBOXD_API_KEY"
{
  "data": {
    "code": "583920",
    "link": null,
    "confidence": 0.95,
    "jev_probability": 0.97,
    "message_id": "0b3e8f4c-…",
    "from": "Example <no-reply@example.com>",
    "subject": "Your Example verification code",
    "received_at": "2026-09-29T10:00:07.412Z"
  }
}

Two details matter. Pass since from before you triggered the email: the default is the moment your request arrives, so a code that landed a second earlier would be missed. And pass from (a case-insensitive part of the sender) when the inbox is shared, so a code from another site can’t be picked up. On timeout you get data: null, not an error.

Confidence What it means Suggested action
0.95 Pattern found and the classifier confirmed a verification email Use the code or link
0.5 – 0.7 Pattern found, not confirmed yet (or AI processing is off for the workspace) Use it for a sign-up you just started; otherwise read the message
0.2 The classifier says this is not a verification email Don’t use it; read the message

Yes. A temporary inbox is receive-only, lives on its own domain, and deletes itself and its mail when its time is up (1 minute to 24 hours, 15 minutes by default). Use it for trials and one-off sign-ups; keep a permanent inbox for accounts the agent will log back into.

// A receive-only inbox that deletes itself (and its mail) after 15 minutes.
const inbox = await mr.inboxes.createTemporary({ ttlSeconds: 900 });
const since = new Date().toISOString();
await signUpOnTheSite({ email: inbox.address });
const v = await mr.messages.waitForVerification(inbox.id, { since, timeout: 60 });

Some sites refuse known disposable domains. Temporary inboxes are on a separate domain for exactly that reason: if it gets listed, your permanent agent addresses are unaffected. If a site refuses it, use a permanent inbox.

Yes. The answer has code, link or both; one of them is set whenever a verification email was found.

You get the newest verification email after since. Codes are usually replaced when a new one is sent, so the newest is the one that works.

Yes: the get_verification_code tool does the same wait, and create_temporary_inbox makes a throwaway address. See the MCP server docs.

Only if the workspace allows AI processing (the default, categorize), and then only to the classifier, for the confirmation step. With AI processing off, the pattern match still returns the code, without the confirmation. Details in AI processing and privacy.

Start with the quickstart: an inbox is one API call, and the free plan is enough to try this today.

Originally published on the Agentboxd blog.

── more in #ai-agents 4 stories · sorted by recency
── more on @agentboxd 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-can-an-ai-agent-…] indexed:0 read:5min 2026-09-29 · —