# Troubleshoot email and SMS waits

A wait succeeds when a message satisfies its conditions. If a test times out or receives the wrong code, check the delivery, resource and filters before increasing the timeout. Start with the [wait method reference and examples](/docs/wait-for/) when choosing an endpoint.

## Follow the delivery from the application

1. Confirm the browser or API action actually submitted the signup, reset or SMS request. Assert the application's response before waiting for mail.
2. Record the receiving inbox ID and address, or phone ID and number, used by this test. Compare them with the recipient submitted to the application.
3. Inspect that resource in MailSlurp. If the message is absent, check your application's sending logs and provider delivery result. If it is present, compare its timestamp, recipient, sender and subject or body against the wait conditions.
4. Check the error response. A completed wait with unmet conditions is different from a network connection closing, an authentication error or a usage restriction.

For a phone test, provision the number before the run and use its MailSlurp **phone ID** in the wait request. The recipient your application sends to is the **phone number**. See [SMS setup](/docs/txt-sms/) and [phone leases for parallel tests](/docs/phone-pools/).

## Match the symptom to the next check

| Symptom | What to check | What to change |
| --- | --- | --- |
| No message appears | The submitted recipient, successful application action and sending provider result | Correct delivery first; another wait cannot trigger the application's send |
| Message exists but wait times out | `since`, `unreadOnly`, sender, subject, recipient and count conditions | Compare each condition with the actual message, including sender display names and subject variations |
| An old OTP is returned immediately | A reused inbox or phone contains earlier matching messages | Capture `since` immediately before triggering delivery; add a run-specific subject or recipient condition where available |
| A second wait cannot find the same message | A previous full-message read changed its read state | Reuse the returned message or fetch it by ID; choose unread filtering deliberately |
| One worker receives another worker's SMS | Workers share a phone while testing concurrently | Acquire a separate phone lease for each flow and release it after completion |
| The message arrives but has no body in the response | The wait returned a preview rather than the full message | Fetch the email or SMS by its ID before extracting the code |
| The OTP is rejected by the application | An earlier resend invalidated it, it expired, or extraction selected the wrong digits | Select the correct delivery, use a contextual regex or AI extraction, and preserve leading zeroes |

For example, if a signup flow sends both a welcome email and a verification email, "latest email" may select the welcome email. Wait for the verification subject and intended recipient, then extract the code from that selected message. See [matching conditions](/docs/wait-for/#wait-for-matching-emails) and [Playwright extraction](/docs/playwright/#extract-email-codes-reliably).

## Keep three timeouts in order

The **message wait timeout** bounds MailSlurp's search. The **HTTP client timeout** must allow that request to finish, including network overhead. The **test runner timeout** must cover setup, browser actions, the wait, assertions and cleanup.

A 60-second message wait inside a 30-second test cannot finish reliably. Give the outer layers more time, but keep an overall deadline. Avoid fixed sleeps before a wait: the wait already returns when its conditions are met.

## Retry the flow deliberately

Inspect the existing delivery before resending. A resend can generate a new OTP and invalidate the previous one. If you restart the application flow, use a fresh inbox or a new phone lease and timestamp. Do not broaden filters until any message passes just to make the test green.

On failure, retain the operation name, HTTP status, resource ID, timestamp boundary and matching conditions. Redact API keys, message bodies, OTPs and personal information from shared logs. Use [API errors and retries](/docs/api-errors/) for request failures and [test resource lifecycle](/docs/test-resource-lifecycle/) for cleanup.
