Application and parser logic
Mock provider calls, validate template variables, and run extraction fixtures across languages and false-positive cases.
Keep fast parser and service unit tests, then add a smaller end-to-end suite that proves the real message reaches a real inbox and completes the user flow.
Use a unique test mailbox, trigger the real OTP request, wait for an inbound message after the trigger time, validate sender and recipient context, extract the current code, submit it once, and assert the verified state. The test should fail at a bounded timeout and record redacted delivery evidence instead of sleeping or reading a shared inbox.
Mocks and real email answer different questions
Mock provider calls, validate template variables, and run extraction fixtures across languages and false-positive cases.
Verify signed callbacks, delivery state mapping, suppression, retries, and idempotent event storage.
Send to an isolated inbox, retrieve the code, submit it, and assert the verified application state.
A unit test can prove that application code calls an email client with the expected template data. It cannot prove DNS, provider acceptance, routing, parsing, actual template output, link generation, or final user verification.
Keep many fast unit tests and a smaller number of real-message tests. The end-to-end suite should target critical account journeys and produce diagnostics precise enough to identify the failing layer.
Mock provider calls, validate template variables, and run extraction fixtures across languages and false-positive cases.
Verify signed callbacks, delivery state mapping, suppression, retries, and idempotent event storage.
Send to an isolated inbox, retrieve the code, submit it, and assert the verified application state.
Create an isolated mailbox and ensure no stale messages can match.
Trigger the real application endpoint and record the recipient and request time.
Filter inbound email after the trigger with an explicit deadline and expected sender context.
Parse the code, reject date-like or ambiguous candidates, and keep the message ID for diagnostics.
Use the code and assert the account or session becomes verified.
Request or retain a controlled code to prove old or reused values fail according to policy.
mails code --to "$TEST_EMAIL" --timeout 60Parser coverage and end-to-end coverage should share fixtures where possible, but the end-to-end test must still verify the actual application template and delivery path.
| Observation | Interpretation | Next check |
|---|---|---|
| No provider message ID | Application may not have sent. | Queue, template validation, provider request logs. |
| Provider accepted, no inbox mail | Delivery or routing issue. | Domain DNS, provider state, inbound route. |
| Message arrived, parser empty | Template or extraction mismatch. | Redacted content fixture and parser rules. |
| Code extracted, application rejects | Token state or timing issue. | Expiry, newest-code policy, recipient binding, replay. |
| Verification succeeds, UI stale | Frontend or session state issue. | API response, cache, cookie, and navigation. |
Run the critical paths on a cadence and environment that match their cost and stability. Do not make every unit test depend on external email, and do not hide provider outages by retrying indefinitely.
Track test volume, timeout rate, message latency, parser failures, and final verification separately. These metrics distinguish product bugs from provider or environment problems without collecting production mailbox content.
A passing assertion should prove that the current message completed the intended account state, not merely that a number appeared in an inbox. Bind every code to the recipient, request window, sender context, and final application outcome, then test expiry and replay separately.
Product behavior is verified against the mails0 source and documentation. External comparisons link to official vendor documentation checked on 2026-08-15.
No. Keep many unit and integration tests with mocks or fixtures, then use a smaller end-to-end suite for the real delivery and verification journey.
Use an isolated recipient, record the trigger time, match only messages after that boundary, and verify the application rejects older or reused codes.
The current parser includes common English, Chinese, Japanese, and Korean code patterns. Keep product-specific fixtures because template wording can still vary.
Log redacted message identifiers, timing, sender domain, recipient alias or hash, provider state, and parser outcome. Avoid full bodies, raw keys, and sensitive codes in broad artifacts.
Start with a receive-only temporary mailbox. Move to a permanent identity or self-hosted deployment only after the workflow reaches a real email value event.