Email testing with pytest
A conftest fixture that gives every test its own inbox and cleans up afterwards, whether the test passed or not.
How it fits together
pytest fixtures are the natural home for this: one inbox per test, created before and deleted after, with the address handed straight to the test function.
Skip the setup
The steps below are what a working project looks like. If you want that project rather than the explanation, generate it — one runnable smoke test, one signup test to edit, and a gitignored .env for your key.
npm create mailflat@latest -- --template pytest
Zero dependencies of its own; the generated project pulls the SDK.
The fixture
Everything after the yield is teardown, so a failing test still cleans up.
# conftest.py
import os, uuid, pytest
from mailflat import MailFlat
@pytest.fixture(scope="session")
def mf():
return MailFlat(api_key=os.environ["MAILFLAT_API_KEY"])
@pytest.fixture
def inbox(mf):
box = mf.create(prefix=f"pytest-{uuid.uuid4().hex[:8]}", retention_hours=2)
yield box
box.delete()
The test
# test_signup.py
def test_signup_sends_a_verification_code(inbox, client):
client.post("/signup", json={"email": inbox.address})
otp = inbox.wait_for_otp(timeout=60)
assert client.post("/verify", json={"code": otp}).status_code == 200
Run it in parallel
pytest-xdist splits tests across processes. Because each test owns its inbox, nothing else has to change.
pytest -n 4
Worth knowing
Keep the client session-scoped and the inbox function-scoped: one HTTP client, many inboxes.
wait_for_otp raises OTPTimeoutError, which pytest reports as a failure with the address in the message.
See also
Python
The official Python client wraps the REST API in two calls: open an inbox, wait for the code. Works in pytest, unittest, Robot Framework or a plain script.
Waiting and timeoutsMail is asynchronous, so every email test waits for something. The difference between a solid suite and a flaky one is how that wait is written.
Testing & CIGive every CI run its own real inbox: the four API calls, parallel shards, teardown, and how to keep an end-to-end suite fast and honest.