Proxy Mail QA

Review a simple sign-up form: email, password, done

A simple form has fewer places to go wrong, but the ones it has are the ones every user hits. 12 checks cover it.

Updated

Our recommendation, up front. We make Proxy Mail QA, so we’re not neutral. For a short sign-up form (an email, a password, perhaps a name) we recommend it for one thing: a fresh test address for each try and the verification email that follows, whether you check by hand with Proxy Mail QA for Chrome, through an AI agent, or in an automated test. Most of the checklist below needs no product at all. Proxy Mail QA doesn’t review layout or wording, and doesn’t fill in or submit the form for an agent or a test: they do that themselves.

The checklist

The email field

  1. It’s type="email" with autocomplete="email", so phones show the @ keyboard and browsers offer the right address.
  2. It accepts valid but unusual addresses: capitals, a plus tag (jane+acme@mailclub.dev), an apostrophe (o'brien@mailclub.dev). It refuses ones with no @ or two.
  3. An address that’s already registered gets a sensible answer: either “You already have an account” with a link to sign in, or “Check your email” either way, if you don’t want to reveal who has an account.

The password field

  1. The rules are shown before someone types, and they’re the same rules the server enforces.
  2. It’s type="password" with autocomplete="new-password", allows paste and has a way to show what was typed.
  3. A password that’s too short gets an error at the field, saying the rule. (If it doesn’t, see Why is my registration form not showing password errors?)
  4. A long password, 64 characters, is accepted and signs in afterwards.

Submitting

  1. One click makes one account and sends one email, even if the button is pressed twice.
  2. The button shows it’s working, and errors from the server appear on the page rather than vanishing.

The email

  1. It arrives within a minute.
  2. Its link goes to the site you’re testing, not localhost or production, and any expiry it states is true.
  3. The code or link finishes the sign-up, and works only once.

By hand, in about ten minutes

  1. Install Proxy Mail QA for Chrome, open your sign-up page and choose Turn on for this site in its popup.
  2. Click the Proxy Mail QA button in the email field to fill the form with a new test account: email, name if there is one, and a password that fits the field’s rules.
  3. For checks 6 and 7, click the key button in the password field and open its card’s Edge-case password list (“Should be accepted”, “Should be rejected”), then try a few. For check 2, add a plus tag to the address in the field before you submit: mail to +anything still reaches the same test inbox, and shows in the app rather than in the page.
  4. Submit. When the email lands, the code shows in the page with Fill and Copy, or the link with Open.
  5. Read the whole email once in the app, where a link to localhost is flagged on the address’s row.

With an AI agent

With Proxy Mail QA connected to your agent (in Qoder, from the Marketplace), ask:

Prompt
Review the sign-up form at https://staging.acme.dev/signup with Proxy Mail QA.
Sign up with a new address and finish the verification. Check the email with
check_email (expect_host: staging.acme.dev) and count_emails: exactly one should come.
Try get_address_variants and get_password_variants (min_length 8, max_length 64) in
the fields, using a plus tag on the address for each new account.
Give me the twelve-point checklist below with pass or fail for each.

Paste the checklist above under the prompt, so the agent reports against it.

In an automated test

With the proxymail-qa npm package and Playwright, checks 8 to 12 run on every change:

TypeScript
import { expect, test } from '@playwright/test';
import { ProxyMailQA } from 'proxymail-qa';

const qa = new ProxyMailQA(); // reads PROXYMAIL_QA_API_KEY

test('sign-up sends one working verification link', async ({ page }) => {
  const { address, password } = await qa.createAddress({ password: true });
  const submitted = new Date();

  await page.goto('/signup');
  await page.getByLabel('Email').fill(address);
  await page.getByLabel('Password').fill(password);
  await page.getByRole('button', { name: 'Sign up' }).click();

  const { value: link } = await qa.waitForLink(address, { type: 'verify', since: submitted });
  const check = await qa.checkEmail(address, { since: submitted, type: 'link', expectHost: 'staging.acme.dev' });
  expect(check.failed).toEqual([]);

  await page.goto(link);
  await expect(page).toHaveURL(/welcome/);

  await new Promise((resolve) => setTimeout(resolve, 10_000)); // time for a duplicate
  expect((await qa.countEmails(address, { since: submitted, type: 'link' })).count).toBe(1);

  await qa.deleteAddress(address);
});

since makes the wait ignore anything sent before the form was submitted, so a retry never picks up an old link.

What this doesn’t cover

For a form that asks for more (date of birth, country, a second screen), see Review a multi-page sign-up form.

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

Built your app with an AI tool? Pick yours