OTP codes and sign-up flows
Use ephemeral or catch-all inboxes to receive verification codes and magic links during sign-ups, extract them safely from the trust report, and let the inbox expire afterwards.
Agents often need an address for one job: sign up for a service, receive a one-time code or a magic link, and move on. MachineMail handles this with ephemeral inboxes that delete themselves, and with catch-all domains that create an address on first delivery.
Note
MachineMail does not extract codes for you. It classifies the message (trust.classification.category is otp for one-time codes and magic sign-in links) and gives you clean text and resolved
links. The extraction itself is a regex in your code, shown below.
Pick an address
Ephemeral inbox
Create an inbox with ttl_seconds. It is deleted, with its messages and attachments, once expires_at passes. Every new inbound message pushes expires_at out to now plus ttl_seconds. Passing "ephemeral": true without a TTL uses 3600 seconds.
Without a username you get a random 12-character local part, which is hard to guess. Use it for sign-ups.
Catch-all address on your own domain
If you have a verified custom domain with catch_all: true, any address at that domain works without an API call. The inbox is created when the first message arrives, with created_by: "catch_all". Set catch_all_ttl_seconds on the domain to make those inboxes ephemeral.
This is useful when the agent must hand out an address before it can call the API, for example signup-7f3k@agents.acme.dev. See Use a custom domain.
Warning
machinemail.dev domain, mail to an address that does not exist is rejected, so create the inbox first.Trigger the email and wait
Note the time just before you submit the sign-up form, then wait for the first new message. Choose the waiting method that fits your runtime.
| Method | Notes |
|---|---|
MCP wait_for_message | Blocks up to 60 seconds and returns the message in agent-safe form. Pass after as the time you triggered the email. Quarantined, spam and unauthenticated mail does not wake it. See MCP. |
| SSE | GET /v0/events/stream?inbox_id=...&event_types=message.received. See Realtime events. |
| Polling | GET /v0/inboxes/{inbox_id}/messages every couple of seconds until a message appears. |
A fresh ephemeral inbox has no other mail, so polling for the first inbound message is enough:
Check the message before using it
A code is only worth using if it came from the service you signed up with. Before extracting anything, check:
trust.levelis notsuspiciousorquarantined. Quarantined mail is hidden from default lists anyway.trust.sender.domainis the domain you expect, for examplegithub.com.trust.classification.categoryisotp. Other categories (transactional,notification) can still carry a confirmation link, so treat this as a hint, not a gate.
Extract a code
Read trust.content.text. It has hidden text, zero-width characters, quoted history and signatures removed, so a code hidden in invisible HTML cannot fool your regex. Fall back to extracted_text when there is no trust report.
Some services use alphanumeric codes such as K7Q-2PX. Adjust the pattern per service rather than widening it for all of them.
Extract a magic link
Do not parse links out of the raw HTML. Use trust.links. Every link in the message is listed with its target domain and flags:
Pick the link whose domain matches the service, and skip anything with display_mismatch (the visible text names a different site than the target), shortener or suspicious set.
Clean up
Ephemeral inboxes delete themselves. A reaper runs every minute, removes inboxes past expires_at with all their messages, raw MIME and attachments, and emits inbox.expired with the inbox and the number of deleted messages.
If you are done early, delete the inbox yourself:
If the account turns out to matter, keep the inbox by clearing its TTL:
Warning
Once an ephemeral inbox is deleted its address can be created again by anyone. Do not use ephemeral addresses for accounts you need to recover later; password resets would go to whoever holds the address next.