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