A successful first verification email only shows that a message can arrive; it says nothing about state changes during a resend. Before writing test cases, confirm whether the product expects only the newest code to work or allows every unexpired code. Otherwise, a test that rejects an older code may be judging behavior the product never promised.
Use a separate address for each test run
Get a fresh address from the temporary test inbox, note the current time and expected validity period, then request the first message from the signup page. Once it appears, record its subject, arrival time, and any expiry details in the message. Use a new address for the next branch so older messages from one run do not get mixed into another.
The address is only one part of the verification state. The email entered by the user, current code, number of sends, next permitted resend time, and current signup step may all change. Add columns for the active address and send number to your test log. If needed, record a request identifier returned by the system, but never share a working verification code.
Cooldowns: check the visible timer and the real limit
Click repeatedly or submit with the keyboard as soon as the countdown appears, and watch for duplicate messages. Switch browser tabs, reload the page, and reconnect after going offline to see whether the frontend timer stays in sync with the server limit. A disabled button is not proof of rate limiting: if reopening the signup page bypasses the restriction, users may receive a confusing stack of messages.
If the product says a resend is available every minute, try once just before the cooldown ends and again just after. Record the visible feedback and the number of messages actually received; do not mistake network variation for a one-second timer bug. Test server-side limits only in an environment approved by your team, not by repeatedly triggering messages to real users.
Old and new codes: define the rule before asserting
Label the first message A, then request B as soon as resending is allowed. Confirm that both messages belong to the same account and environment. Enter A and then B separately, recording whether each succeeds and what explanation the page displays. If the first message arrives late, use send sequence numbers—not inbox order—to identify which code is newer. The signup email timeline guide can help reconstruct arrival order.
Write expected results for each possible rule: the old code expires when a new one is sent; both codes remain valid during their own validity windows; or only a link in the latest email can be used. A team should not mix these rules. If the product has not documented one, clarify the requirement instead of leaving pass or fail criteria to individual interpretation.
Also submit an intentionally incorrect code. The message should distinguish an invalid code from an expired code, a rate limit, or an account that is already verified. Do not include working codes or complete activation links in public screenshots; record the message number and outcome instead.
Resend after changing the address: verify the recipient
On the code-entry screen, choose the option to change the email address and enter a second, separate test address. After submitting, confirm that the new message goes only to the new address, that the interface shows that address, and whether a code sent to the old address can still verify the signup. If the product allows a return to the previous address, test the complete state transition rather than checking only the subject line.
If resend messages keep arriving at the old address after a change, the issue may involve account binding, queued jobs, or a field still stored in the frontend. Keep redacted versions of both recipient addresses, click timestamps, and the target shown on screen. This evidence helps distinguish a delayed queued job from a message sent to the wrong recipient.
Include expiry and duplicate submission in boundary tests
Submit A and B just before and just after their validity windows end. Record whether expiry is measured from code generation, message dispatch, or code entry. After a code succeeds, submitting it again should be rejected or clearly identified as already used, depending on the product design; browser back navigation should not activate the account a second time. If signup is available on mobile and desktop, check that cooldowns and code state remain consistent across devices.
Temporary test addresses are available for 3 hours by default, which suits a short verification run. For tests that span days or need a longer email history, consult the inbox lifetime planner. For longer retention, use a forwarding alias or a team-managed test inbox instead of relying on an expired temporary address.
Deliver a record someone else can reproduce
Write one row per event with preconditions, action, expected result, observed result, and visible evidence. Preconditions should include the environment, account state, and which messages have arrived. Distinguish sending, resending, changing the address, and submitting a code; record the countdown, recipient, and error shown. The signup testing checklist can help cover first-time signup, duplicate signup, and activation paths.
If a resend succeeds but the user still cannot sign in, identify which code was entered, when it was submitted, and which address the page showed at the time. That gives developers a way to find inconsistent state instead of receiving only “the code sometimes fails.”
Start with a clean inbox
Use a separate address, record the first send and resend, then compare old-code behavior with your product rules.
Get a test address