These commands manage testing mailboxes that receive mail. To have DevHelm send alert emails, use an email alert channel: see
alert-channels.Setup
The testing API needs an API key and a workspace ID. Export the key, look up the workspace, then export its ID:DEVHELM_WORKSPACE_ID and takes the key in its constructor. With curl, send the workspace as a header:
--api-token and --api-url override DEVHELM_API_TOKEN and DEVHELM_API_URL per command. There is no workspace flag. Without DEVHELM_WORKSPACE_ID the CLI sends workspace 1 and fails with 404 Workspace doesn't exist.
Every command takes -o table|json|yaml (default table) and -v. JSON and YAML print the bare object, without the API’s data envelope.
Message commands take the mailbox as --to <address>, the full address (local@domain). The domain part selects the mail domain; the local part selects the mailbox.
Commands
email address
Print a fresh address. Any local part on a domain receives mail, so no mailbox is created; use one address per test.CLI
- Table output prints the address only. JSON prints
{email, domain, localPart}. - Without
--domain, the CLI lists the workspace’s domains and uses the active assigned one, creating it if there is none. No call is made for the address itself. - The domain cap counts every domain in the organization. On Free or Developer, a second workspace gets 403
INBOUND_EMAIL_DOMAIN_LIMIT_REACHED. - Read the domain from this output or
email domains list. Do not build it by hand.
email receive
Inject a message without a mail provider. It runs the same parsing as real mail, including OTP codes and links.CLI
- The API answers 202 with
eventId,inbox, andreceivedAt: accepted, not yet stored. Useemail waitto see the message. - The CLI has no headers flag. To set
Message-ID,Date, or custom headers, inject through the SDK or the API. - Inject cannot add attachments.
- A disabled domain returns 400
INBOUND_INJECT_DOMAIN_DISABLED. A custom domain still pending DNS accepts inject.
email wait
Block until a message to the address has been stored, then print it.CLI
- Wait returns the oldest match and does not consume it. For the next message, pass the previous
receivedAtplus 1 ms. - The result has
otp,links,bodyPreview, and headers.textandhtmlarenull; runemail messages getwith the message ID for the body. - The CLI matches the full address only. To wait on a local part plus a domain, use the SDK or the API.
- With no match before the timeout, the CLI prints
No matching inbound item arrived before timeout (<address>)and exits with code11. A wait on a disabled domain times out the same way. - All waits in the organization share 40 requests per minute, across email, inboxes, and every workspace. Over the limit returns 429.
jq -r '.otp[0].value' when the email has one code. See Wait for an email in a test and Read OTP codes and links.
email clear
Delete every message for one address, in teardown.CLI
The CLI cannot delete a single message. Use
message.delete() in the SDKs, or DELETE /api/v1/email/domains/<domain>/messages/<message-id>.
email messages list
List messages for one address, newest first. The table showsID, FROM, SUBJECT, OTP, and RECEIVED.
CLI
The CLI prints the rows of one page and not the next cursor. Page through with the SDK or the API. As with
wait, text and html are null in list rows.
email messages get
Get one message. Use-o json for the body; the table shows only the summary columns.
CLI
textandhtmlare clipped at 256 KB;bodyTruncatedsays whether they were cut.htmlis returned unsanitized. Render it only in a sandboxed frame.links[].hrefkeeps&from the HTML today. Replace&with&before you open a link.
email messages source
Print the stored message as RFC822 text, clipped at 256 KB. Table output prints the source and warns when it was cut; JSON prints{source, truncated}.
CLI
email messages raw
Download the full message as.eml. The signed link lasts 60 seconds; the CLI downloads it at once. The file’s SHA-256 matches the message’s sha256.
CLI
email attachments get
Download one attachment by ID.CLI
Inject cannot add attachments, and the
attachments list is not filled for real mail today.
email domains list
List the workspace’s mail domains. The table showsNAME, KIND (assigned or custom), STATUS, and MX.
CLI
email domains get
Table output prints the DNS records;-o json prints the whole domain, including status and each record’s found.
CLI
email domains create
Create a custom domain and print the two DNS records to publish: a TXT record at_devhelm-verification.<domain> and an MX record to mx.devhelmmail.com at priority 10.
CLI
- Custom domains need the Team testing plan or above. Otherwise create returns 403
INBOUND_CUSTOM_MX_PLAN_REQUIRED. - The domain starts as
pending_dns. createmakes custom domains only. The assigned domain comes fromemail address.
email domains verify
Check the DNS records now. Prints<name> <status>, then any records that still do not match.
CLI
active. Verify also re-enables a disabled custom domain whose records match.
email domains update
Disable a domain.disabled is the only status the CLI accepts.
CLI
A disabled domain refuses inject, and waits on it time out. To turn it back on, run
email domains verify for a custom domain. For the assigned domain, PATCH {"status": "active"} through the SDK or the API.
email domains delete
Delete a domain and every message on it.CLI
email domains activity
Message counts in 24 hourly UTC buckets. The table shows the total per domain; JSON has the buckets. Get domain IDs fromemail domains list -o json.
CLI
Common errors
Every code and limit is in Limits, quotas, and errors.
Next steps
Email testing
Domains, addresses, inject, and real mail.
Wait for an email in a test
One address per test, waits that do not flake.
Read OTP codes and links
Pull the code or link out of a message.
inboxes commands
The CLI for webhook testing inboxes.