How to Test Email Verification Flow
Email verification confirms the user owns the email they signed up with. Broken verification blocks account access. Too-easy verification invites abuse. This guide covers testing the flow end-to-end.
Email verification confirms the user owns the email they signed up with. Broken verification blocks account access. Too-easy verification invites abuse. This guide covers testing the flow end-to-end.
What to test
Triggering verification
- Signup sends verification email
- Resend option available (with rate limit)
- Can resend after 60 seconds / configurable
- Account creation succeeds even if email not yet verified (per design)
- Some features may be gated behind verification
- Arrives within expected time (<5 min typically)
- From correct sender (verified: SPF, DKIM, DMARC)
- Subject line clear ("Verify your email for MyApp")
- Body identifies user
- Link prominent and clickable
- Link is unique per user
- Link has expiration (often 24-48 hours)
Link
- Tap / click opens verification
- Deep link opens app (mobile)
- URL also works in browser
- Single-use: second click expired
- Invalid / corrupted URL graceful error
- Expired URL offers resend
Post-verification
- Status updates: user.email_verified = true
- UI reflects verified state
- Welcome flow continues (or user redirected appropriately)
- Feature unlocks apply
Edge cases
- User clicks link while unauthenticated → login first, then verify
- User clicks link on different device — user associated correctly
- Multiple verification attempts — one succeeds, others expired
- User unsubscribes from verification emails — design decision (block or allow)
- Email typo at signup → user never receives → needs change-email flow
- Mailbox full → bounce → retry logic
- Spam filter → user cannot find → "check spam" messaging
Security
- Link cannot be guessed (cryptographically random)
- Link bound to specific user ID
- Rate limit on resend (prevent email bombing)
- No sensitive data in email link (signed token, not password)
- Verification action requires no login (link alone should suffice)
- Cross-account risk: user A's link works for user B? No.
Change email
- If user changes email, old email sent "Your email was changed" notification
- New email receives verification link
- Until verified, old email still the account email (or both temporarily)
- Abandoned change expires
- Re-change before verification overwrites
Accessibility
- Email subject / preview renders in screen-reader-friendly clients
- Verification page accessible
- Keyboard navigable
Multi-client
- Link works in Gmail mobile, Outlook, Apple Mail, web Gmail, etc.
- Link not clipped / truncated
- Link wrapped URL (some clients wrap) still functional
Localization
- Email in user's locale (if offered)
- Time zone respectful ("Link expires Feb 15")
- Currency / locale formatting if relevant
Testing approach
Manual
- Test email client matrix: Gmail mobile / web, Apple Mail, Outlook, GSuite
- Real devices for deep-link test
- Test expired link (wait, or time-travel in test env)
- Test resend rate limit
- Test with email providers known for aggressive spam filtering (Yahoo, AOL)
Automated
- Backend integration test: verify email record created, token generated
- Capture email via test SMTP sink (Mailtrap, MailHog)
- Script navigates to link, asserts verified state
End-to-end
def test_verification(page, test_inbox):
# signup
page.goto("/signup")
page.fill("#email", test_inbox.address)
# ... fill rest
page.click("text=Sign up")
# fetch email
email = test_inbox.wait_for_email(subject_contains="Verify")
link = email.extract_link()
page.goto(link)
# verify success state
expect(page.locator("text=Email verified")).to_be_visible()
Fix patterns
Idempotent verification
Verification endpoint can be called multiple times with same token without error (second is no-op).
Graceful expiry
Expired link → user lands on "Link expired. [Resend]" page with one-click resend.
Visible status
User's account dashboard shows "Email verified" or "Pending verification — resend" clearly.
Progressive disclosure
Non-verified users can use basic features; high-trust actions (withdraw, post publicly) require verification.
Common production bugs
- Link in email wraps across lines, breaks when pasted in browser
- Deep link works on iOS but not Android — intent filter missing
- Resend spams user without rate limit
- Link remains valid after verification — reuse could re-trigger actions
- Email change not propagated to all systems — verified in auth, old email in newsletter
How SUSA handles verification
SUSA drives the signup → wait for verification → deep link handling. For email capture, pair with test inbox. Findings include:
- Deep link failures
- Form accessibility on verification page
- Resend UX (does rate limit show in UX?)
- Missing verified badge in UI post-verification
susatest-agent test myapp.apk --username test+{uuid}@testinbox.example --persona curious
Email verification is deceptively simple and has many failure modes. Test every client and every edge case.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free