DEV Community

Francisco Perez
Francisco Perez

Posted on • Originally published at uncorreotemporal.com

Registration Bot: Claude Code + Temporary Email

Registration Bot: Claude Code + Temporary Email

Your agent fills the name field, generates a password, clicks "Create account" — and hits the wall: Check your inbox to verify your email. No API to poll. No webhook to register. The verification code is sitting in an inbox only a human can reach, and the agent loop dies.

The fix is mechanical: give Claude Code a disposable inbox it owns and can query. This walkthrough covers the full flow — inbox creation, form submission, email polling, OTP and link extraction — using the UnCorreoTemporal MCP server.


Why registration automation needs a real inbox

Three failure modes appear reliably when teams try to hardcode or share email addresses in registration bots.

Parallel run contamination. A shared qa@company.com inbox receives OTPs from ten concurrent test jobs at once. There is no reliable way to attribute a code to the run that triggered it. Flaky tests follow.

Silent rejection. Many services validate the email domain at signup and reject known free providers, catch-all addresses, and addresses that pattern-match as machine-generated. A hardcoded address either works everywhere or gets blocked with no recovery path.

Credential management overhead. Reading a real inbox programmatically requires OAuth 2.0, token refresh, scoped permissions, and ongoing maintenance. That cost is disproportionate for a CI job that runs every commit.

Per-flow inboxes created on demand via create_signup_inbox eliminate all three. Each run gets a fresh address that lives for the duration of the flow. No shared state, no credential setup.


Prerequisites

This guide assumes you have:

  • Claude Code installed (npm install -g @anthropic-ai/claude-code)
  • uv installed for running the MCP server
  • The UCT MCP server already configured — full setup at uncorreotemporal.com/en/docs/mcp/

The one-line setup command:

claude mcp add uncorreotemporal \
  -e UCT_API_KEY=uct_your_key_here \
  -- uvx uncorreotemporal-mcp
Enter fullscreen mode Exit fullscreen mode

Confirm it loaded by running /tools in a new Claude Code session. You should see create_signup_inbox, wait_for_verification_email, extract_otp_code, extract_verification_link, and complete_signup_flow in the list.


Step 1 — Create a temporary inbox via MCP

Before touching the signup form, the agent creates a dedicated inbox. This is always the first tool call:

Tool: create_signup_inbox
Input: {
  "service_name": "app.example.com"
}
Output: {
  "inbox_id":     "mx_abc123@mail.uncorreotemporal.com",
  "email":        "mx_abc123@mail.uncorreotemporal.com",
  "expires_at":   "2026-05-12T11:30:00Z",
  "service_name": "app.example.com"
}
Enter fullscreen mode Exit fullscreen mode

service_name is a label for your reference — it doesn't affect routing, but it makes debugging easier when running multiple flows. The returned email is the address to use in the registration form. The inbox is live immediately after this call; no propagation delay.

Default TTL is 30 minutes. A complete registration loop runs in under 60 seconds — more than enough headroom.


Step 2 — Navigate to the signup form and fill fields

With the inbox address in context, Claude Code fills the registration form. The exact mechanism depends on the target — browser automation, API call, whatever fits — but the prompt structure is consistent:

Register a free account on app.example.com using:
- Email: mx_abc123@mail.uncorreotemporal.com
- Name: Alex Developer
- Password: TempP@ss2026!

Fill all required fields and submit the form. Stop after submitting.
Do not proceed to email verification yet.
Enter fullscreen mode Exit fullscreen mode

Keep registration and email-polling as separate instructions. When registration fails, you want a clean stopping point — not an agent already polling an inbox that will never receive email.


Step 3 — Submit the form and wait for the verification email

Once the form is submitted, the agent waits for the incoming email with a single blocking call:

Tool: wait_for_verification_email
Input: {
  "inbox_id":        "mx_abc123@mail.uncorreotemporal.com",
  "timeout_seconds": 90
}

// Email arrived:
Output: {
  "status":       "received",
  "message_id":   "msg_9x2p1q",
  "subject":      "Verify your account",
  "from_address": "noreply@app.example.com",
  "received_at":  "2026-05-12T11:01:34Z"
}

// Timeout:
Output: {
  "status":          "timeout",
  "timeout_seconds": 90
}
Enter fullscreen mode Exit fullscreen mode

The tool polls internally every 3 seconds. From Claude Code's perspective it is a single call — no repeated invocations consuming context budget. 90 seconds covers the vast majority of transactional email delivery.

If the target service sends multiple emails at signup, filter to get the right one:

{
  "inbox_id":         "mx_abc123@mail.uncorreotemporal.com",
  "timeout_seconds":   90,
  "subject_contains": "verify",
  "from_contains":    "noreply@app.example.com"
}
Enter fullscreen mode Exit fullscreen mode

Step 4 — Extract the confirmation link/OTP and complete registration

Pass the message_id from the previous step to the appropriate extraction tool.

For OTP codes:

Tool: extract_otp_code
Input: {
  "message_id": "msg_9x2p1q",
  "inbox_id":   "mx_abc123@mail.uncorreotemporal.com"
}
Output: {
  "otp_code":   "847291",
  "candidates": ["847291"]
}
Enter fullscreen mode Exit fullscreen mode

For magic links:

Tool: extract_verification_link
Input: {
  "message_id":        "msg_9x2p1q",
  "inbox_id":          "mx_abc123@mail.uncorreotemporal.com",
  "preferred_domains": ["app.example.com"]
}
Output: {
  "verification_link": "https://app.example.com/verify?token=eyJhbGci...",
  "candidates": [
    "https://app.example.com/verify?token=eyJhbGci...",
    "https://app.example.com/unsubscribe?email=..."
  ]
}
Enter fullscreen mode Exit fullscreen mode

preferred_domains filters out unsubscribe links and tracking URLs that appear in most HTML email. candidates exposes every URL found — useful when debugging extraction failures.

Feed the result back to Claude Code with a straightforward instruction: "The OTP is 847291. Submit it in the verification form." or "Navigate to this URL to confirm the account." The registration is complete. No human touched it.


Error handling patterns (slow email delivery, retry logic, timeouts)

Email never arrives (status: timeout). Common causes: slow SMTP relay on the target service, the email filtered as spam before delivery, or a silent rejection at the registration form. Mitigation: increase timeout_seconds to 120-180 for known slow senders. After a timeout, call get_latest_email against the inbox — sometimes the email arrives just after the window closes and you can extract the token without re-running the signup.

OTP expired before submission. Most OTPs expire in 10 minutes. A complete loop runs in well under 60 seconds, so expiry is rarely the issue. If your browser automation is slow and you're hitting this consistently, request a new code from the service before submitting rather than re-running the full flow.

Service blocks the email domain. Some platforms maintain blocklists of known disposable providers. If the registration form returns "Please use a valid email address," the domain is blocked at the service level. Paid plans support custom domains so the agent receives email at agent@yourdomain.com instead of the default UCT domain — that bypasses most domain-level blocklists.


Making the agent resilient in production

Instruct the agent to stop on failure, not retry automatically. A retry spiral burns API quota and can trigger rate limits on the target service. Adding "If any step returns an error or unexpected result, report what happened and stop" to your agent prompt costs nothing and prevents a class of runaway loops.

Use complete_signup_flow for straightforward cases. If the target service sends exactly one verification email and you need the OTP or link, skip the individual tool chain:

Tool: complete_signup_flow
Input: {
  "service_name":    "app.example.com",
  "timeout_seconds": 90
}
Output: {
  "email":             "mx_abc123@mail.uncorreotemporal.com",
  "otp_code":          "847291",
  "verification_link": "https://app.example.com/verify?token=...",
  "status":            "received"
}
Enter fullscreen mode Exit fullscreen mode

This creates the inbox, waits for the email, and runs both extraction tools in a single call. Use the individual tools when you need subject or sender filtering, multi-email flows, or explicit debugging breakpoints between steps.

Size the TTL to the flow. For flows that span multiple emails — activation link, then API key delivery — extend ttl_minutes at creation time. The default 30 minutes is enough for single-email flows; multi-step flows that take longer need more runway.

For the complete tool parameter reference and additional patterns for CI pipelines, see the MCP tool reference.


The email verification wall is a solved problem. Try UnCorreoTemporal free — no credit card required, and the full agent loop runs in under a minute once the MCP server is configured. The free tier is enough to wire up and validate a complete registration flow before committing it to production.

Top comments (0)