Software Testing

How to Test a Used Email Verification Link Twice with Temp Mail

Does clicking a used email verification link twice cause an expired error, allow re-verification, or send a new link to the same temp inbox? Test it.

Pankaj KumawatPankaj KumawatPublished
Illustrated cover for How to Test a Used Email Verification Link Twice with Temp Mail: an envelope with code brackets representing email testing.
Illustration: Tempmail editorial teamSoftware Testing
Share
Skip to article ↓
On this page6 sections

Short answer: you can reproducibly test how your verification flow handles reuse and resend scenarios by generating a disposable inbox, completing the first verification, then attempting two separate follow-ups in a clean browser context: reopen the original link and watch how the app responds, and request a fresh verification from the app and see whether a second email lands in the same temp inbox. Every one of those three outcomes — expired error, silent re-verification, new link — tells you something different about your token design, and none of it is documented in advance in the supplied sources, so you have to observe it.

That observation is the point of the exercise. The supplied sources describe how to provision inboxes and how verification flows should behave in general; they do not specify reuse semantics, expiry windows, or whether a disposable inbox will receive a second message. So treat this as a recording procedure, not a checklist with known answers.

Generate a Disposable Address for the Test

Start with a fresh inbox so the message you’re inspecting is unambiguously the one from this run.

The Tempmail documentation describes generating disposable addresses with custom tags for test flows, with mail delivered to a live inbox viewable in a sanitized HTML iframe. If you want the step to be scriptable rather than manual, the API reference documents a POST /api/emails/generate endpoint that programmatically provisions a disposable address with an optional custom tag and returns the full email address in the response payload. The tag is supplied as a query parameter:

curl -X POST "https://api-testmail.codaipro.com/api/emails/generate?tag=signup.flow" \
  -H "Authorization: Bearer tm_live_demo994821a8" \
  -H "Content-Type: application/json"

The response includes the full email address:

{
  "email": "demo.signup-flow@inbox.testmail.app",
  "tag": "signup-flow",
  "namespace": "demo"
}

Tags are for your bookkeeping and filtering. The Tempmail documentation emphasizes that everything is disposable — you can generate as many addresses as needed and discard the inbox when you’re done, with tags such as signup.flow or otp.test for filtering later tests. A tag helps you find the right run when you’re juggling several.

Two practical habits make the retest easier to read:

  • Use one address per scenario. If you reuse yesterday’s address for today’s run, you can no longer tell which message belongs to which attempt.
  • Record the address and tag in your test notes before you submit it to the app under test. Copy-paste errors here are the most common cause of a confusing afternoon.

Discard the inbox when the test is finished. Do not route anything you might need later — order confirmations, password resets, return labels — through it.

Complete the First Verification Click

Fill in the disposable address in the application’s sign-up or verification form, then open the temp inbox and click the link in the message that arrives.

The variable you’re capturing is the response shape. In your notes, record exactly one of these:

  1. Success state — a confirmation page, a redirect into an authenticated session, a “verified” badge.
  2. Expired or invalid error — a message telling you the link is dead, already used, or malformed.
  3. Re-verification prompt — the app treats the click as a request to verify again, perhaps with a “send a new link” button.

There is no universal default here. The supplied documentation does not state how reusing a clicked link behaves, so your job is to observe rather than predict.

Also note how the link opens. Keeping the two contexts distinct — and noting which one produced which result — is what makes the later comparison interpretable.

Now run the two follow-ups separately, in order.

Attempt A — reuse the original link. Copy the full URL from the first message and open it in a fresh browser context: a new profile, an incognito window, or a new Playwright context if you’re scripting this. Record the app’s response alongside the result from the first click. A response that changes between the two contexts is itself a finding.

Attempt B — request a new verification. Return to the application and trigger verification again: resubmit the form, hit a “resend” control, or start sign-up over with the same address. Then watch the inbox.

Attempt B is where you learn whether the application issues a fresh token for an address it has already seen, and whether it will send to an address that’s now marked verified. If your app rejects the second request outright with something like “this account is already verified,” that is a legitimate design choice — just confirm the error message tells the user what to do next instead of leaving them at a dead end.

Be explicit in your notes about which attempt you’re looking at. When two verification emails sit in the same inbox with near-identical subjects, it’s easy to click the older link and mislabel the result.

Check the Temp Inbox for a New Message

Refresh the temp inbox view and look for a second message from the application.

No source in front of me states that a disposable inbox will receive a second verification email after the first link has been consumed, so a missing message has at least three possible causes, and you should rule them out in this order:

  1. The application refused to send a second email (already-verified state, rate limit, resend cooldown).
  2. The email was delivered but the inbox view hasn’t been refreshed.
  3. The application or its mail provider suppressed delivery to this address.

If a second message does appear, click its link and record the response exactly as you did for the first. Three distinct outcomes are worth distinguishing in your notes:

  • When a fresh link works and confirms the account, the app accepts a new verification token for an address it has already verified. Check that the UI reflects the state change immediately.
  • When a fresh link returns an expired/invalid error, investigate token issuance, TTL configuration, or error messaging around dead links.
  • When a fresh link silently re-verifies without a new email, check idempotency of the verification endpoint and whether the success page honestly describes what happened.

If no second message arrives, retry the refresh once, then treat the absence as a finding about your app’s resend behavior rather than about the inbox.

Decision Tree for Retesting Verification Flows

Use the observed combination to decide what to build next:

  • Expired error on reuse, no new email on resend. Your app treats the link as single-use and does not offer a recovery path. Test how a real user in that position gets unblocked — is there a visible “resend” affordance, or does the error page strand them?
  • Expired error on reuse, new email arrives and works. The common case. Verify the new link is genuinely distinct from the old one, that the success page shows correct state, and that repeated resends don’t produce unbounded messages.
  • App allows re-verification without a new email. Investigate idempotency: does the endpoint return a stable result, and does the UI ever claim a fresh verification occurred when none did?
  • First click already fails. Debug the issuance path before you test reuse. A dead-on-arrival link tells you nothing about second-click behavior.

Whatever you find, write it down as an explicit expectation, because nothing in the reference material pins it down for you.

Caveats

Be careful generalizing from a controlled test environment. Clerk’s test-mode email and phone guidance describes a setup where test mode simulates email verification flows without sending real emails, and test-mode addresses are excluded from monthly delivery limits and daily recipient caps. That’s genuinely useful when you’re exercising a Clerk-managed flow and don’t want mail delivery in the loop — but it applies to Clerk-managed verification flows, not to arbitrary third-party applications receiving disposable addresses. Similarly, Playwright’s authentication guide describes saving browser state after login so tests can reuse authenticated sessions without re-authenticating in every test; that saves you from re-running sign-up in every test, but it also means a later test can silently inherit a verified session and mask the very reuse behavior you’re trying to observe. Clear state when the reuse test is the test.

At the policy level, the OWASP Authentication Cheat Sheet states that users should be permitted to use their email address as a username, provided the email is verified during sign-up. That makes the verification step load-bearing for identity — which is exactly why the reuse and resend edges deserve deliberate testing rather than incidental coverage.

Pankaj Kumawat

About the author

Pankaj Kumawat

Software Engineer & Backend Lead at Codaipro

Software Engineer and Backend Lead at Codaipro specializing in Python, distributed architecture, and email testing infrastructure. Researches E2E QA automation and ephemeral systems.

Tempmail is the product this team builds. Our editorial policy covers sourcing, testing, corrections, and how we disclose that relationship.

Sources & further reading

  1. 01Authentication - OWASP Cheat Sheet Series (opens in a new tab)
  2. 02Authentication | Playwright (opens in a new tab)
  3. 03Documentation — Setup, Deploy & Configure Tempmail (opens in a new tab)
  4. 04Test emails and phones - Testing with Clerk | Clerk Docs (opens in a new tab)
  5. 05API Reference — Free Developer Temp Mail REST & SSE Endpoints (opens in a new tab)
  6. 06Initial Setup - SuperTokens Docs (opens in a new tab)
Share

Try it without signing up

The address on the home page is ready in a second. Copy it, use it anywhere, and read the reply here — no account, no ads.

Keep reading

All guides