Proxy Mail QA

Test sign-up emails with pytest

To test email verification in pytest, give each test a fresh address, sign up with it, then wait for the code or link and finish the flow. Proxy Mail QA's Python helper is one file using only the standard library: create_address before the form, wait_for_code or wait_for_link after it. It works with Playwright for Python and Selenium, on the Free plan.

Updated

Set up

Copy the helper, proxymail_qa.py, from the Python docs into your tests folder, and put an API key in PROXYMAIL_QA_API_KEY, in your shell, a .env file kept out of Git, or your CI’s secrets. The Free plan is enough.

The test

With Playwright for Python:

test_signup.py
import re

from playwright.sync_api import Page, expect

from proxymail_qa import create_address, delete_address, now, wait_for_link


def test_sign_up_verifies_the_email(page: Page):
    account = create_address()
    page.goto("/signup")
    page.get_by_label("Email").fill(account["address"])
    page.get_by_label("Password").fill(account["password"])

    submitted = now()
    page.get_by_role("button", name="Sign up").click()

    page.goto(wait_for_link(account["address"], since=submitted))
    expect(page).to_have_url(re.compile("verified"))
    delete_address(account["address"])

For a code, use wait_for_code(address, since=submitted) and type what it returns. With Selenium, the calls are the same: find the fields with driver.find_element and send the code or open the link. since makes the wait ignore anything sent before the form was submitted, so a retried test never reads an old email.

test_emails.py
import time

from proxymail_qa import check_email, count_emails, now, wait_for_link


def test_sign_up_sends_one_good_verification_email(page, account):
    submitted = now()
    page.get_by_role("button", name="Sign up").click()
    wait_for_link(account["address"], since=submitted)
    time.sleep(10)  # give a duplicate time to arrive
    assert count_emails(account["address"], since=submitted, type="link")["count"] == 1
    assert check_email(account["address"], since=submitted, expect_host="staging.example.com")["failed"] == []

check_email returns verdicts on SPF, DKIM and DMARC, links to localhost or plain http, where the link goes and more, never the email itself. expect_no_email checks that an action sends nothing, such as a second reset request that should be refused.

Run it in CI, with a report on the pull request

Import the helper’s pytest hooks in conftest.py. In GitHub Actions, add the Proxy Mail QA action before the tests: the report on the pull request then says which test each email came from, and lists the failed tests with what their emails did.

conftest.py
from proxymail_qa import pytest_runtest_setup, pytest_runtest_teardown, pytest_runtest_logreport, pytest_sessionfinish
.github/workflows/e2e.yml
      - uses: aaquib90/proxymail-qa-action@v1
        with:
          api-key: ${{ secrets.PROXYMAIL_QA_API_KEY }}
      - run: pytest
        env:
          PROXYMAIL_QA_API_KEY: ${{ secrets.PROXYMAIL_QA_API_KEY }}

The hooks do nothing outside a run, and never fail your tests themselves. More in the Python docs and Running in CI.

Try it on your next sign-up test

Free plan, no credit card. Create an address and watch the code or link arrive.

Create a free accountOpen the app

Questions

Is there a pip package?

Not yet. The helper is a single file using only Python's standard library: copy it from the Python docs into your test folder, and there's nothing to install or keep updated.

Does it work with Selenium?

Yes. The helper doesn't touch the browser: it creates the address and returns the code or link, and your Selenium or Playwright code types or opens it.

What if the email never arrives?

The wait raises ProxyMailQAError saying why as far as Proxy Mail QA can tell: most often the app's email provider is in sandbox or test mode and only sends to verified addresses. Fix the sending side rather than waiting longer.

Built your app with an AI tool? Pick yours