Quickstart: pytest
A conftest.py fixture hands every test its own real inbox. The SDK is stdlib-only (Python 3.9+), so it works with requests-driven API tests, playwright-python, or whatever else drives your app.
1 · Install
Zero dependencies — the client is plain urllib under the hood.
$ pip install mailfixture
2 · Authenticate
Create a key in Dashboard → API keys and export it. The SDK reads MAILFIXTURE_API_KEY automatically — keep it in CI secrets, not in the repo.
MAILFIXTURE_API_KEY=mfx_••••••••••••••••••••
3 · The fixture
Session-scoped client, function-scoped inbox: every test gets a fresh address and tears it down afterward. The 15-minute TTL is the backstop for runs that die mid-flight.
import pytest from mailfixture import MailFixture @pytest.fixture(scope="session") def mail(): return MailFixture() # reads MAILFIXTURE_API_KEY @pytest.fixture def inbox(mail): inbox = mail.create_inbox(ttl_seconds=900) yield inbox inbox.delete()
4 · Write the test
wait_for_otp() long-polls the server — it returns the moment the email lands or raises MailFixtureTimeout. No time.sleep, no retry loop, nothing to tune.
import requests APP = "https://staging.example.com" def test_signup_sends_otp(inbox): requests.post(f"{APP}/api/signup", json={"email": inbox.address}) otp = inbox.wait_for_otp(timeout=30) # held open server-side r = requests.post(f"{APP}/api/verify", json={"email": inbox.address, "code": otp}) assert r.status_code == 200
inbox.wait_for_otp(match="subject:code", timeout=30) — match takes subject:, from:, and to: prefixes. Driving a browser instead? Swap requests for playwright-python's page and this reads like the Playwright quickstart.
5 · Run it
$ pytest test_signup.py test_signup.py . [100%] ========== 1 passed in 1.62s ==========
Parallelism with xdist
Inbox-per-test means pytest -n auto needs no coordination: no shared mailbox, no cross-worker message collisions, nothing to lock. The fixture above is already parallel-safe.