mail.md
title: "Mail workflow" description: "The MachineMail CLI mail commands: send a message, read one with its trust verdict, wait for a message or a verification code, and tail events live." canonical: "https://machinemail.dev/docs/cli/commands/mail"
Mail workflow
The MachineMail CLI mail commands: send a message, read one with its trust verdict, wait for a message or a verification code, and tail events live.
Source: https://machinemail.dev/docs/cli/commands/mail
Top-level commands for the jobs agents and people do most: send a message, read one with its trust verdict, wait for a message or a verification code, and follow events live.
| Command | Summary |
|---|---|
send |
Send an email from an inbox |
read |
Show a message: headers, trust verdict and agent-safe text |
wait |
Wait for a message to arrive (and extract a code or magic link with --otp) |
tail |
Follow live events (messages, deliveries, inboxes) as they happen |
send
Send an email from an inbox.
Sends through POST /v0/inboxes/{inbox_id}/messages/send. The body comes from --text, --html or --file (a .html/.htm file is sent as HTML, anything else as text); pass - to any of them to read stdin. Stdin is never read unless you ask. --from defaults to MACHINEMAIL_INBOX, the profile inbox from machinemail register, or the inbox of an inbox-scoped key.
machinemail send [flags]
Flags
| Field | Type | Description | |
|---|---|---|---|
--from <inbox-id> |
string |
Inbox to send from. | |
--to <address> |
string[] |
Recipient (repeat or comma-separate). Repeat the flag for several values. | |
--cc <address> |
string[] |
CC recipient. Repeat the flag for several values. | |
--bcc <address> |
string[] |
BCC recipient. Repeat the flag for several values. | |
-s, --subject <text> |
string |
Subject. | |
| `--text <text | ->` | string |
|
| `--html <html | ->` | string |
|
| `-f, --file <path | ->` | string |
|
--attach <path> |
string[] |
Attach a file (10 MB of files per message in total). Repeat the flag for several values. | |
--reply-to <address> |
string[] |
Reply-To address. Repeat the flag for several values. | |
--label <label> |
string[] |
Label for the sent message. Repeat the flag for several values. | |
--header <Name: value> |
string[] |
Extra header. Repeat the flag for several values. |
Examples
machinemail send --from agent@machinemail.dev --to ada@acme.dev -s "Hello" --text "Hi Ada"
echo "Build passed" | machinemail send --to ops@acme.dev -s "CI" --text -
machinemail send --to ada@acme.dev -s "Report" --file report.html --attach report.pdf
read
Show a message: headers, trust verdict and agent-safe text.
Shows one message with its trust report summary (verdict, score, authentication, flags) and the agent-safe body (trust.content.text: hidden text, zero-width characters, quotes and signatures removed). --original shows the text as the sender wrote it, labelled untrusted; --raw prints the raw RFC 5322 source.
Piped (or with --json) it prints the agent view: headers, the trust verdict, untrusted: true unless the sender authenticated (verified or known), and body: the agent-safe text (body_source says where it came from; quarantined mail is withheld, as the MCP server does). --full prints the whole API object instead, with the original text and HTML. The inbox can be given as --inbox or as the first argument; without it the CLI finds it.
machinemail read <message-id> [flags]
Arguments
| Field | Type | Description | |
|---|---|---|---|
<message-id> |
string |
required | Message id (msg_...), optionally preceded by its inbox |
Flags
| Field | Type | Description | |
|---|---|---|---|
--inbox <inbox-id> |
string |
Inbox the message is in (found automatically when omitted). | |
--original |
boolean |
Show the original text instead of the agent-safe text (untrusted). | |
--full |
boolean |
JSON output: the whole API message (original text and HTML included, untrusted) instead of the agent view. | |
--raw |
boolean |
Print the raw RFC 5322 message. |
Examples
machinemail read msg_01m4g46p1y0000bqmf6m6yv7h5
machinemail read agent@machinemail.dev msg_01m4...
machinemail read msg_01m4... --json | jq -r .body
machinemail read msg_01m4... --json --full | jq .trust
wait
Wait for a message to arrive (and extract a code or magic link with --otp).
Blocks until a new inbound message matching the filters arrives in the inbox, then prints it. Listens on the SSE event stream and polls as a fallback. Only mail received after the command starts counts; --since 5m also accepts mail from the last five minutes (use it when you triggered the email before calling wait).
Piped (or with --json) it prints the agent view of the message: headers, the trust verdict, untrusted: true unless the sender authenticated, and the agent-safe body (withheld for quarantined mail); --full prints the whole API object instead, original text included.
--otp prints only the verification code (or the magic link when there is no code), read from the agent-safe text. It only uses mail whose sender authenticated (trust level verified or known, or a DMARC pass, or an aligned SPF or DKIM pass); --allow-unauthenticated also accepts unauthenticated mail and mail without a trust report, and suspicious or quarantined mail is never used. Unauthenticated mail does reach the inbox (labelled UNAUTHENTICATED), so this check matters. --from matches an address exactly, or a domain and its subdomains (github.com matches mail.github.com, not github.com.example.net). --json prints {code, link, message_id, ...} instead. Exits 8 on --timeout.
machinemail wait [flags]
Flags
| Field | Type | Description | |
|---|---|---|---|
--inbox <inbox-id> |
string |
Inbox to watch (default: MACHINEMAIL_INBOX or the profile inbox). Default: MACHINEMAIL_INBOX or the profile inbox. |
|
| `--from <address | domain>` | string[] |
|
--subject <text> |
string[] |
Subject contains this, case-insensitive (any of several matches). Repeat the flag for several values. | |
-t, --timeout <duration> |
string |
Give up after this long: 90, 90s, 5m (default 5m; 0 waits forever). Default: 5m. |
|
| `--since <duration | iso>` | string |
|
--otp |
boolean |
Print only the verification code, or the magic link when there is none. | |
--link |
boolean |
With --otp: print the magic link even when there is a code. | |
--pattern <regex> |
string |
With --otp: extract with this regex (first group, else the match). | |
--link-domain <domain> |
string |
With --otp: the magic link must be on this domain or a subdomain of it (default: the sender domain). Default: the sender domain. |
|
--allow-unauthenticated |
boolean |
With --otp: also use mail whose sender did not authenticate, or that has no trust report (never suspicious or quarantined mail). | |
--full |
boolean |
JSON output: the whole API message (original text and HTML included, untrusted) instead of the agent view. | |
--poll |
boolean |
Poll only; do not use the event stream. |
Examples
machinemail wait --inbox signup-7f3k@machinemail.dev --otp
CODE=$(machinemail wait --inbox "$ADDR" --from github.com --otp --timeout 2m)
machinemail wait --inbox "$ADDR" --subject invoice --json | jq .trust.level
machinemail wait --inbox "$ADDR" --otp --allow-unauthenticated # e.g. a test sender without SPF/DKIM
tail
Follow live events (messages, deliveries, inboxes) as they happen.
Streams GET /v0/events/stream. On a terminal: one line per event with the trust badge of inbound mail, and a status line. Piped: NDJSON, one {id, event, data} per line. Reconnects on its own and resumes with Last-Event-ID; pass --last-event-id to resume from an earlier run. Ctrl-C stops it (exit 0).
machinemail tail [flags]
Flags
| Field | Type | Description | |
|---|---|---|---|
--inbox <inbox-id> |
string[] |
Only these inboxes. Repeat the flag for several values. | |
--pod <pod-id> |
string[] |
Only these pods. Repeat the flag for several values. | |
-e, --event-types |
string[] |
Only these event types (comma-separated or repeated). Repeat the flag for several values. | |
--last-event-id <evt_...> |
string |
Replay events after this one first. | |
--max <n> |
integer |
Stop after n events. |
Examples
machinemail tail
machinemail tail --inbox agent@machinemail.dev -e message.received
machinemail tail -e message.bounced,message.complained | jq -c .data.message.to