Give an AI Agent an Inbox for Sign-Up Codes

When an AI agent reaches an email verification code during a sign-up, give it an inbox it reads through an API, never your personal Gmail. Two small tools are enough: one rents a real @gmail.com or @icloud.com address, the other waits for the code. You keep the API key, the budget and the list of sites the agent may join.

Meant for people building browser and computer-use agents, Playwright MCP setups or coding agents that sign up for tools on their owner's behalf, or test their owner's own product. It assumes the sign-up is one you are allowed to automate.

Why the agent should not use your own Gmail

A rented inbox narrows all four: one address per sign-up, the tool passes the model only what arrives on that order, and nobody ever gets a mailbox login.

The loop an agent runs for an email verification code

  1. Pick the service code from GET /v1/services. A site that is not listed uses ot (Any service), which costs more.
  2. Call POST /v1/orders with an Idempotency-Key. A retry with the same key returns the same order instead of renting a second inbox.
  3. The agent types email into the sign-up form and submits it.
  4. Poll GET /v1/orders/{orderId} every 3–5 seconds. status turns completed with the first code; read the last entry of otp.
  5. No code by codeDeadlineAt (25 minutes at most)? The order cancels itself and 100% goes back to the balance, as the rental refund rules set out. The tool can also cancel earlier.
  6. A login code right after sign-up? Keep polling the same order: new codes are appended while it can still receive them, within limits shown before you rent.

For the agent itself, OTPGmail publishes the whole reference as one Markdown file written for language models, at otpgmail.net/docs/api-v1.md (plain text: api-v1.txt). On the API docs page, Copy for AI offers Copy the full docs (Markdown for AI) to paste into the agent's context, or Copy link + instructions for AI for an agent that can browse.

Two tools in about 30 lines of Python

The functions below are framework-agnostic. Register them as tools in an MCP server or in your framework's function-calling layer; the docstrings double as tool descriptions.

import os, time, uuid, requests

HOST = "otpgmail.net"
H = {"Authorization": "Bearer " + os.environ["OTPGMAIL_API_KEY"]}  # never put the key in the prompt
ALLOWED = {"git", "ot"}  # service codes this agent may rent

def rent_inbox(service: str, task_id: str, domain: str = "gmail.com") -> dict:
    """Rent a real inbox for one sign-up. The same task_id returns the same inbox."""
    if service not in ALLOWED:
        return {"error": "service not allowed for this agent"}
    key = str(uuid.uuid5(uuid.NAMESPACE_URL, f"{task_id}:{service}:{domain}"))
    r = requests.post(f"https://{HOST}/v1/orders", json={"service": service, "domain": domain},
                      headers={**H, "Idempotency-Key": key}, timeout=15).json()
    if not r["success"]:
        return {"error": r["error"]["code"]}  # e.g. NO_MAILS_AVAILABLE, INSUFFICIENT_BALANCE
    return {"order_id": r["data"][0]["orderId"], "email": r["data"][0]["email"]}

def wait_for_code(order_id: str, timeout_s: int = 300) -> dict:
    """Wait for the code or link sent to a rented inbox."""
    end = time.time() + timeout_s
    while time.time() < end:
        o = requests.get(f"https://{HOST}/v1/orders/{order_id}", headers=H, timeout=15).json()["data"]
        if o["otp"]:
            value = o["otp"][-1]["code"]
            if value.startswith("http") and not any(c.isspace() for c in value):
                return {"link": value}
            if len(value) > 80 or "\n" in value or "<" in value:
                return {"error": "full email received; ask a human to read it"}
            return {"code": value}
        if o["status"] == "cancelled":
            return {"error": "no code arrived; order refunded"}
        time.sleep(4)
    requests.post(f"https://{HOST}/v1/orders/{order_id}/cancel", headers=H, timeout=15)
    return {"error": "timed out; order cancelled for a refund"}

Three details are deliberate. The idempotency key comes from the task, so a model that calls rent_inbox twice for the same step gets the same inbox back (keys live 24 hours; a new attempt needs a new task_id). When no code could be extracted, the API returns the whole email; the tool keeps that text away from the model, because it is exactly the untrusted input injection relies on. And errors come back as short codes the agent can act on: INSUFFICIENT_BALANCE means stop and tell the owner, NO_MAILS_AVAILABLE means try later or the other domain.

Guard-rails that matter more than the code

Risk Guard-rail
A site forbids automated sign-ups Keep an allow-list; let the agent sign up only where the site's terms permit someone acting for the account owner, one account per person where the site says so, and never in bulk
Prompt injection by email Give the model only a code or a link; treat anything else as data, never as instructions
A leaked API key The key stays in the tool process, never in the prompt or the browser; Generate new key on the docs page revokes the old one at once
Runaway spending Top up only what the agent may spend; INSUFFICIENT_BALANCE then stops it. Limit orders per task
Captchas and identity checks Stop and hand over to a human; OTPGmail does not solve captchas
Browser permissions Playwright MCP's own README says it "is not a security boundary": run the agent's browser in a separate profile with no saved logins
Retry loops Renting pauses (RATE_LIMITED) after too many cancellations without a code in the last 60 minutes, so let the agent give up and report

Calls are rate limited per key, by default 20 requests per second and 900 per minute; the current values are on the docs page.

What to expect from delivery

Delivery depends on the sender, so the agent must expect misses. Over the last 30 days, 96% of GitHub orders received a code, typically after about 1 minute, and 91% of ChatGPT orders, typically after about 1 minute; for sites outside the list, 87% of Any service orders got one. A miss costs nothing, because the order refunds itself. The agent should report it, not improvise.

Some services send a link rather than a code; the tool returns it and the agent opens it in the same browser session. A rented address serves one sign-up or verification: if the owner will keep the account, the agent's last step should be a reminder to switch it to an address the owner controls while the rented one still works. The Gmail OTP API overview has the remaining endpoints.

Frequently asked questions

Is there an official OTPGmail MCP server?

Not at the time of writing (October 2026). Wrap the two functions above as tools in your own MCP server or framework; the Markdown reference gives the model the field names and error codes.

Can the agent use an app password on my Gmail instead?

Technically yes, over IMAP, but it then reads the whole mailbox, and Google itself says app passwords "aren't recommended and are unnecessary in most cases". If the agent must use a mailbox you own, give it a dedicated one with nothing else in it.

What if the site only offers “Continue with Google”?

A rented inbox delivers codes, not a Google sign-in. That step needs a Gmail account the agent can sign in to: your own, or a short-lived Gmail account bought through /v1/mail-shop. Those last a short time depending on the type, only the first successful sign-in within 2 hours is covered, and a Google captcha, which is not covered, should go to a human.

How long should wait_for_code wait?

A few minutes covers most senders; slow ones need longer. There is no point going past the order's codeDeadlineAt, because the order is cancelled and refunded at that moment anyway.

Related guides

Get your verification code now

Sign up free. You are only charged when an inbox is issued. No code within 25 minutes — 100% refunded automatically.

Can't find the service you need? Use Add service on the rental page and we will add it if our infrastructure supports it.

Need a Gmail account you can sign in to, not just a code? See buy short-lived Gmail accounts · Refund and warranty