Track three timestamps—not just email order
In 2026, signup flows often queue code-generation tasks: the page says the request was accepted, the backend generates a code, and the email service attempts delivery. “Sent” may only mean the task was created; it doesn’t prove the email reached the receiving server. A second request may take a faster route, so the new code arrives before the old one.
Record at least three times during testing: when you click Send, when the email first appears in your inbox, and when you submit the code. If server logs are available, also record the code’s issue time and the email task ID. Don’t treat the date in the email body or its Date header as the arrival time—they’re usually set by the sender.
Example: Request A at 10:00:00, then B at 10:01:00. B appears at 10:01:04, while A doesn’t show up until 10:01:12. The first email in the list may be A—the old code, which may already be invalid.
Browser polling tells you when the page first noticed an email. Its accuracy depends on the polling interval, network conditions, and whether the page is in the foreground. It can help identify delays measured in minutes, but it isn’t millisecond-level delivery monitoring. For strict service-level metrics, use sender and receiver logs rather than trying to infer timings from screenshots.
Send once to establish a repeatable inbox baseline
First, open the test inbox, copy its current address, and make sure it will remain valid throughout the test. Use it only in a test environment you’re authorized to access; don’t use a temporary email address for assets, production accounts, or identities you may need to recover long term. Address expiry and code expiry are separate: extending one won’t extend the other.
- Prepare a fresh test account and note the test environment, page version, and local time zone.
- Click Send once. Record whether the request succeeds; don’t click repeatedly to “make the email arrive faster.”
- Keep the inbox open until the email arrives. Check the recipient address, subject, and purpose of the message.
- Submit the code while it’s still valid. Record the result, then try the same code once more to check whether it has already been consumed.
Whether submitting the same code a second time should fail depends on the product’s specification. An OTP for one-time login would typically expire after successful use, but testers shouldn’t assume every product works that way. First confirm with the authentication team when expiry starts—at issuance or at send time—whether successful verification consumes the code immediately, and whether only one active code can exist per address.
If no email arrives at this point, go back to the signup testing workbench to check triggering and delivery before trying a resend. Without a successful baseline, it’s easy to confuse “the old code was invalidated” with “the email was never sent.”
Test resends in two rounds to avoid skewing the results
Once the cooldown ends, request code B and label A and B as the first and second requests. If both emails contain the same code, don’t assume they’re duplicates based on the code alone: some systems resend the same code while it’s valid; others issue a new one each time. Check the task IDs, send logs, and product design.
If the specification clearly says that resending invalidates the old code immediately, run two independent tests. In the first, request A, then B, and submit A first; record that it was rejected. In the second, start a clean session, request A and B again, and submit only B to confirm the new code works. Don’t use B first and then conclude the resend logic is correct because A fails: A might have been rejected because the entire challenge had ended.
- Old code accepted after a new one is issued: check how active challenges are stored and invalidated, not just the email queue.
- New code also fails: check the challenge ID, session, test address, and clock, then check the expiry time.
- Email arrives after the code expires: ask the email and authentication teams to investigate the time from issue to delivery.
- Resend is rate-limited: keep the cooldown message and test at the permitted pace; don’t bypass the limit.
Test expiry boundaries with separate samples, too. Submit once while the code is valid, once near expiry, and once after it expires. Don’t repeatedly retry the same code and risk triggering a lockout. The client-side countdown is a guide; the server makes the final decision. A user’s device clock being fast or slow shouldn’t determine whether a code is accepted.
Separate multi-tab conflicts from duplicate emails
If one tab requests A and another requests B, each may have a different challenge or session. If B fails in the first tab, that doesn’t automatically mean the emails arrived out of order. Reproduce the issue with one tab first, then test with two, recording each tab’s actions and expected results.
If you receive two identical emails, distinguish at least three possibilities: the page submitted the request twice, the backend retried delivery, or the inbox displayed the message twice. If you can access the raw headers, compare Message-ID and correlate it with the email task logs. This is a clue, not definitive proof: forwarding or provider processing may rewrite related fields.
Receiving only one email doesn’t prove the system prevents duplicates. The second task may not have run yet, or the email provider may have merged the messages. To verify duplicate prevention, check the tested system’s request IDs and task records. A temporary inbox shows what was ultimately observed; it can’t replace an audit of backend behavior.
Write test records others can reproduce
A useful report includes the environment version, an anonymized account identifier, address expiry, code request time, observed arrival time, code submission time, and page result. Use A and B instead of sharing full codes; reference task IDs when linking logs, and never post a still-valid code in a public ticket. If a screenshot contains a verification link, hide its token before sharing.
Keep conclusions specific. “After the second request, the first code was still accepted in the same session” is more actionable than “OTP security is broken.” Likewise, “The inbox page observed the email after 12 seconds” is more accurate than “Email delivery took 12 seconds,” since you didn’t measure every step in between.
After checking delivery order, inspect the email itself. Does the subject clearly explain its purpose? Does the body state the expiry time? Can users tell similar-looking digits apart on a phone? Next, read Testing notification email content and plain text to check separately that the email arrived and that users can use it correctly. If you’re unsure about a term, consult the email testing glossary.
For your next test, change one variable at a time
Start with a fresh temporary address: send one baseline email, then test a resend. HideRelay only receives email; it doesn’t issue or verify codes for the product under test.