How it works
A testing mailbox receives mail at addresses your test controls and lets the test read it through an API:- Get an address that belongs to this test and no other.
- Trigger the email: submit a sign-up form, request a password reset.
- Wait for the message to arrive at that address.
- Read and assert: the subject, the recipient, the one-time code, the link.
Three kinds of mailbox
A DevHelm testing mailbox and the email alert channel are separate features: one receives mail for tests, the other sends notifications to people.
Messages in a public disposable-inbox service are readable by anyone with the address, which is the wrong place for one-time codes and password-reset links, even in staging. A testing mailbox accepts mail from anyone, like any address, but reading it needs access to your workspace.
Assigned domain or your own
Every address needs a domain whose MX record points at the testing mailbox.
Start with the assigned domain. Move to your own when your app only accepts sign-ups from certain domains, or when addresses have to look like yours. Receive on your own domain covers the DNS.
On either domain, every local part is its own inbox. There is nothing to create per address, so a test can use a fresh address on every run.
Inject or real delivery
Inject runs the same parsing as real mail, including OTP and link extraction, so a test written against inject keeps working when you switch to real delivery. Use inject for fast tests and tutorials. Use real delivery for the end-to-end test that proves users actually get the email.
Why “the provider returned 250” is not proof
When your app hands a message to a mail provider, the provider answers right away: an SMTP250 or an HTTP 200 or 202. That answer means accepted for delivery. It does not mean delivered. Between the two, the message can be:
- held by a sandbox or test mode that accepts mail and never sends it,
- dropped because the address is on the provider’s suppression list after an earlier bounce,
- queued behind rate limits, or retried after a temporary failure at the receiving server,
- sent to the wrong address by a template or configuration bug.
202 when it accepts the message, before the message is stored. A message accepted right at the organization’s monthly quota can still be dropped.
The proof is the message itself, readable in the mailbox. That is why a test waits for the message instead of checking the send call’s status.
Waiting for the message
A wait call blocks until a matching message is stored, then returns it, or fails with408 WAIT_TIMEOUT. It matches messages received at or after a start time, so take that time before the trigger:
Reading what is inside
Each message comes with the codes and links already extracted. A code labelled in the email, as in “Your verification code is 482913”, appears inotp, and each link appears in links with its text. Click tracking from your mail provider rewrites links to the provider’s redirect host, and the testing mailbox keeps them as written. Read OTP codes and links covers several codes and tracked links.
Keep it to test data
A testing address receives any mail sent to it. Use it for test accounts only, never for real users, real accounts, or customer data. Security and data lists who can read what.DevHelm email testing
Your first test email
Get an address, inject a message, and assert on the code.
How testing mailboxes work
Domains, stored fields, and every way to read a message.