📱 OpenInbox is now on Android & iOS! Get the app today.

OpenInbox on Telegram

Get a temp inbox right inside Telegram.

Open Telegram bot

Custom domains

Use your own domain on paid plans.

Learn More
Developer API • /python

/python Temp Email API

Create disposable inboxes, receive verification emails, and extract OTP codes from Python — a small httpx client plus a runnable pytest integration test.

Verifying email flows in Python — Django or Flask signups, password resets, OTP logins — usually stalls because the confirmation email lands in a mailbox pytest can't see. The OpenInbox API gives each test a disposable inbox over plain HTTP: create it, trigger the flow, poll, and pull the code out of the body. This guide uses httpx (requests works identically) and a pytest fixture, all against the real API.

How the flow works

  • Create a disposable inbox: POST /api/inbox (no auth) → {"id", "email", "expiresAt"}.
  • Use that address in your signup/reset flow so your app emails it.
  • Poll GET /api/inbound/api/emails?inboxEmail=<email> with the X-API-KEY header until an email arrives.
  • re.search a 4–8 digit code (or URL) in the email textBody.
  • Submit the code / visit the link and assert.

Setup

Install httpx (or requests) and pytest. Reading the inbox is a premium endpoint, so read the key from the environment rather than hard-coding it.

terminalbash
pip install httpx pytest

export OPENINBOX_API_KEY="your-premium-api-key"

A reusable OpenInbox client

Wrap the two calls you need. create_inbox creates a fresh inbox; wait_for_otp polls the inbox and returns the first 4–8 digit code it finds in textBody.

openinbox.pypython
import os, re, time, httpx

BASE = "https://api.openinbox.io/api"
HEADERS = {"X-API-KEY": os.environ["OPENINBOX_API_KEY"]}


def create_inbox() -> dict:
    """Create a disposable inbox (no auth required)."""
    res = httpx.post(f"{BASE}/inbox")
    res.raise_for_status()
    return res.json()  # {"id", "email", "expiresAt", ...}


def wait_for_otp(inbox_email: str, timeout: int = 30) -> str:
    """Poll until an email arrives, then return the OTP from textBody."""
    deadline = time.time() + timeout
    while time.time() < deadline:
        res = httpx.get(
            f"{BASE}/inbound/api/emails",
            params={"inboxEmail": inbox_email},
            headers=HEADERS,
        )
        emails = res.json().get("emails", [])
        if emails:
            match = re.search(r"\b\d{4,8}\b", emails[0].get("textBody") or "")
            if match:
                return match.group(0)
        time.sleep(2)
    raise TimeoutError("No OTP email arrived in time")

A pytest integration test

A fixture gives every test a fresh inbox. The test triggers your signup, waits for the code, and asserts it looks like an OTP — extend it to drive your verify endpoint end to end.

test_signup.pypython
import httpx, pytest
from openinbox import create_inbox, wait_for_otp


@pytest.fixture
def inbox():
    return create_inbox()


def test_signup_sends_otp(inbox):
    # Trigger your app so it emails the verification code
    httpx.post(
        "https://staging.yourapp.com/api/register",
        json={"email": inbox["email"], "password": "Str0ng!Pass"},
    )

    otp = wait_for_otp(inbox["email"])
    assert otp.isdigit() and 4 <= len(otp) <= 8

    # …submit otp to your verify endpoint and assert the success state

Async (httpx.AsyncClient)

For suites that create many inboxes at once, the same calls work with httpx.AsyncClient inside async def tests (with pytest-asyncio): await client.post(f"{BASE}/inbox") to create and await client.get(...) with the X-API-KEY header to poll. The endpoints and the textBody field are identical.

Common pitfalls

  • Bound the polling loop with a deadline (as shown) — an unbounded while will hang the test session if no email arrives.
  • Creating an inbox needs no auth, but GET /api/inbound/api/emails is premium. A 401/403 means the X-API-KEY header is missing or the plan is not paid.
  • Read email["textBody"] — there is no pre-parsed code field. re.search(r"\b\d{4,8}\b", ...) grabs a 4–8 digit run; narrow it (e.g. r"code[:\s]*(\d{6})") if the body has other numbers.
  • httpx.get with params= URL-encodes the inbox address for you; if you build the URL by hand, encode it yourself.
  • Give each test its own inbox via the fixture so pytest-xdist parallel workers never share a mailbox.

Frequently Asked Questions

How do I create a temporary email in Python?

Send httpx.post("https://api.openinbox.io/api/inbox") (no auth) and read the email field from the JSON response, which also includes id and expiresAt. requests works the same way.

Do I need an API key?

Creating an inbox is unauthenticated. Polling received emails (GET /api/inbound/api/emails) requires a premium X-API-KEY, read from the OPENINBOX_API_KEY environment variable.

How do I extract the OTP code in Python?

Run re.search(r"\b\d{4,8}\b", email["textBody"]).group(0) on the email returned by the poll endpoint. There is no separate parsed field — it is a one-line regex on textBody.

Does this work with Django or Flask test suites?

Yes. The OpenInbox calls are framework-agnostic HTTP, so they slot into Django, Flask, or plain pytest tests. Only the part that triggers your app changes.

Can I do this asynchronously?

Yes — use httpx.AsyncClient with pytest-asyncio. The endpoints, headers, and textBody field are unchanged; you just await the requests.

How long does a disposable inbox last?

Free inboxes expire after one hour, ample for a test. Create a fresh inbox per test so parallel tests stay isolated.

Related Pages

Explore More

Your private inbox is one click away

Free, instant, no registration needed. Works with any service. Expires automatically after 1 hour.

View API Docs