Tempcase

Tempcase Testing Notes

OTP resend testing:
match each email to its request

You clicked resend twice, but the second email arrived first. Don’t assume the latest arrival is the latest code issued. Link requests, send events and inbox records to find out where things went wrong.

About 12 min read OTP regression

A test inbox can confirm that an email arrived and let you inspect its contents. It cannot determine which code the application accepts. This guide assumes you’re testing a staging environment you’re authorized to use, with test accounts that hold no real assets. All identifiers in the examples are illustrative, not records of production incidents.

Why automated regression tests still confuse two rounds in 2026

Automation scripts often follow a simple flow: request a code → wait for an email → fetch the latest one → submit it. A successful single run doesn’t guarantee that repeated resends work reliably: the first email may still be queued when the second request completes, or two test windows may share an account while the script records only the time of the last click.

The latest email in the inbox may belong to an earlier request. Fetching mail by subject, unread status or arrival order alone can misreport out-of-order delivery as an invalid code—or accidentally pass with the wrong code and miss a defect. Start by correlating test registration emails with their requests, not by writing a regex to grab six digits.

Define resend behavior first—don’t guess from the inbox

Before running OTP resend tests, agree on a testable specification with the product and backend teams: Does resend reuse a still-valid code or issue a new one? When is the old code revoked? Does the expiry period start at the first issuance or the latest one? Does the rule apply per account, purpose or verification session?

Write down expectations before introducing out-of-order delivery

“Only the latest code is valid” and “multiple codes remain valid until they expire” are different designs. The latter isn’t necessarily a bug just because an old code works. Both designs still need defined rules for attempt limits, rate limits, expiry and one-time use after success.

Record the rule version in the test case. If the rules aren’t clear, note what needs confirmation instead of letting an automated assertion make a product decision. The reproduction below assumes that issuing a new code immediately invalidates the old one.

One case per round: the address is only part of the context

Start with a temporary inbox and copy a unique address. Assign the round an identifier such as case-r17. Keep that address for the initial send and any resends in the same round. Record the staging build, account identifier, verification purpose and session identifier. Don’t switch addresses after every resend: that turns “resend for the same account” into “first send for a new account.”

Record each request’s application request ID, response and send-event ID generated by the sending service. A successful API response may only mean the task was queued. If the asynchronous task hasn’t created a send event yet, mark the field “pending correlation” and fill it in later. A rate-limited or rejected request generally shouldn’t trigger a new email, but check the API contract.

Tempcase email record IDs belong to the receiving side and won’t automatically match application request IDs. If the message details don’t expose headers or correlation fields, use send logs, controlled test markers or observability tools in the test environment. Don’t pair records just because their timestamps are close.

Build a five-column correlation table so every email has a traceable source

These five columns are the minimum correlation framework. Record the account, environment, rule version and timeline at the top of each round. If one request triggers multiple delivery attempts, keep a separate row for each and note retry relationships—don’t overwrite earlier events.

Example records: R1 and R2 use the same test address and verification session
Test round Request ID Delivery event ID Email record ID Application validation result
case-r17 / R1 req-a evt-a mail-a, arrived later Old code A: expected rejection; accepted in practice
case-r17 / R2 req-b evt-b mail-b, arrived first New code B: validate in a separate reproduction

Also record the stage of each “delivery event”: queued, handed to the sending service, accepted by the remote server or bounced. Don’t use “delivered” as a catch-all. An email record ID can help locate a message, but it can’t replace the result from the application’s verification endpoint.

What continuous resends, two windows and queue delays each test

Continuous resends: check rules and rate limits

Send R1 and R2 outside the allowed resend interval and record each response. Then test a click during the cooldown period separately. Check that rejected requests don’t create new tasks and that the expiry period after a resend matches the specification. Don’t generate load with rapid requests or bypass rate limits.

Two windows: check the scope of verification state

Use the same test account in two windows, trigger requests in a defined order and record each session identifier. Check whether revocation applies across windows. An old prompt still visible in one window doesn’t mean the server accepts the old code. Conversely, an updated page doesn’t prove that the server revoked it.

Queue delays: check application behavior when delivery is out of order

Only in an authorized test environment, delay R1 using a controllable queue or fault injection so R2 arrives first. Record where the delay was introduced and its duration. This tests whether the system enforces OTP rules when delivery is out of order; it doesn’t measure real-world email latency, and you must not modify a production queue.

Email order isn’t request order

Requests, code issuance, task execution and email receipt can happen in different orders. The email’s Date header is also generated by the sending side, so it isn’t a reliable receipt time. To identify out-of-order OTP delivery, prioritize traceable event correlation over simply checking the latest email.

In templates you control, you can include a non-secret test correlation ID, or log a mapping between the request ID and the email’s Message-ID . The OTP itself can’t serve as a correlation key: systems may reuse a code, and different requests can produce the same digits. If there’s no evidence to link them, report the result as “request association unconfirmed.”

Validate old-code invalidation against the application

Assert three things separately: whether the email reached the inbox, whether the application accepted the code, and whether authentication established the correct session or application state. Receiving an email doesn’t mean the code is valid, and a successful response from the OTP endpoint doesn’t necessarily mean the login flow is complete.

To test an old code, submit the code for R1 after R2 has been successfully issued, and record the application error type and challenge state. Test whether the new code works and can be reused in a separate reproduction branch: successfully using the new code first may consume the entire challenge, making the old code fail while hiding a failure to revoke it on resend.

Restore the same initial conditions for every branch and stay within the attempt limit. Record only “accepted” or “rejected” and a stable error category. Never put a full OTP in assertion reports, screenshot names or CI logs.

Timestamp evidence: use a consistent format and keep the source

Use ISO 8601 timestamps with time zones. Convert them to UTC for summaries while retaining the original values and their sources. Label timestamps separately—for example, “application code issuance,” “sending service acceptance,” “receiving service record” and “browser observation.” Matching display formats don’t mean the system clocks are synchronized.

  • Use a monotonic clock to measure duration within a process, and keep a wall-clock timestamp for reference.
  • Before comparing timestamps across services, check clock synchronization. Without a reliable bound on clock skew, don’t subtract timestamps and claim an exact delay.
  • The time a poll first detects an email is only an observation time. Checking every few seconds creates an observation window.
  • Email header timestamps are supporting evidence only; they don’t replace issuance, queue or application validation timestamps.

If you only know that an email wasn’t there during one check but was there during the next, record that interval. An honest gap for what you can’t measure is more useful than a millisecond-precise conclusion with no reliable source.

Reproduction: the second email arrives first

This is a controlled example, not a report of an incident involving Tempcase or any application. Expected behavior: once R2 issues a new code for the same challenge, the old R1 code becomes invalid immediately.

  1. Create a test challenge and send R1. Record req-a → evt-a, then delay its delivery in the test queue.
  2. After the resend interval, send R2 and confirm that a new code was issued. Record req-b → evt-b.
  3. Observe mail-b first. Release the delay, then observe mail-a. Use the correlation IDs to confirm which request each email belongs to.
  4. Submit old code A before the challenge has been successfully consumed. If it’s accepted, record the verification response and challenge state, then end this branch immediately.

Bug report summary · illustrative example

Title
Old code still passes validation after a resend issues a new code for the same challenge
Expected
After R2 is successfully issued, submission of the old R1 code should be rejected.
Actual
Old code A was accepted; the correlation chain and validation response were retained in redacted form.
Scope
Out-of-order delivery is the trigger, not proof that the queue is the root cause; revocation and validation logic still need investigation.

If only the first email arrives late and the old code is correctly rejected, don’t report out-of-order delivery as an authentication defect. It may call for clearer email content or page guidance, but that’s different from a failure of the security rules.

Share redacted evidence with teammates, not full OTPs

A handoff should let a teammate reproduce the issue step by step, not use your credentials. Use the checklist below; use account identifiers, and handle real addresses and correlation IDs according to your team’s data classification rules.

Minimum reproducible record

  • Environment and build version, rule version, test round and account identifier.
  • Initial state, session scope, request interval and delay-injection method.
  • Five-column correlation table, sourced timeline and redacted response categories.
  • Expected and actual results, number of reproductions, untested branches and known uncertainties.

Never include full OTPs, login tokens, cookies, authentication links or temporary email access tokens in shared reports. Redact secrets in screenshots, and check the address bar and developer tools before sharing screen recordings. Avoid using ordinary hashes for short numeric codes: the value space is small and easy to enumerate. Use unrelated labels such as A and B instead.

When to change addresses and when to keep the same account

Change the address after a test round ends or when you need to verify a clean registration flow; this helps isolate leftover emails. Keep the same address and context while testing resends, two windows, rate limits or old-code revocation for the same account—otherwise you change the test conditions.

Tempcase temporary addresses are valid for 3 hours by default and can be extended, up to 24 hours per address. Each extension request adds 3 hours, subject to the limit. Emails can’t be recovered after expiry, so don’t use the inbox as an evidence archive. If you need to keep an account’s email destination across multiple days, use the email forwarding sign-in page to create an alias. Aliases only forward incoming mail; they don’t replace application logs or provide indefinite evidence retention.

Next round: get the correlation working first

You don’t need to cover every edge case on the first run. Start with one normal send you can correlate, add a resend, then introduce controlled out-of-order delivery. If you can’t confirm whether an email was sent, first check the sending and receiving evidence with our email delivery troubleshooting guide. After the email arrives, check its layout, then open the email template preview.

One new case, one complete evidence trail.

Start with a unique address, then trigger a registration flow you’re authorized to test. Match each email to its request, and leave code validity checks to the application.