# emcli agent command reference The five agent commands you may use. Each prints **one** JSON object to stdout and sets a matching exit code (0 success, non-zero error). All take `--account `; most take `--folder` (default `INBOX`). ## The JSON envelope ```json { "error": false, "error_detail": {}, "data": { } } ``` - `error` — boolean. Check it first. - `error_detail` — `{}` on success; `{ "code": "...", "message": "..." }` on failure. - `data` — command-specific payload (below). **Error codes:** `config` (key/config), `db`, `network`, `auth`, `policy` (blocked by a rule), `not_found` (missing **or** filtered/invisible mail), `usage` (bad/missing flag). --- ## `list` — headers, newest first ``` emcli list --account A [--folder F] [--new] [--limit N] [--before U] [--since U] ``` | Flag | Default | Meaning | |---|---|---| | `--folder` | `INBOX` | Mailbox | | `--new` | off | Only messages not yet `ack`ed | | `--limit` | `50` | Max results (capped at 500) | | `--before ` | — | Only UIDs lower than this (page to older mail) | | `--since ` | — | Only UIDs higher than this (page to newer mail) | `data`: ```json { "messages": [ { "uid": 70314, "from": "\"Boss\" ", "to": "", "subject": "Hello", "date": "Mon, 22 Jun 2026 17:00:30 +0000", "message_id": "abc@example.com", "has_attachments": false } ] } ``` Headers only — no body is downloaded. `data.messages` is `[]` when nothing matches. --- ## `get` — one full message ``` emcli get --account A [--folder F] --uid U ``` `data`: ```json { "uid": 70314, "from": "\"Boss\" ", "to": "", "subject": "Hello", "date": "Mon, 22 Jun 2026 17:00:30 +0000", "message_id": "abc@example.com", "body_text": "the decoded plain-text body…", "attachments": [ { "name": "report.pdf", "size": 20480, "mime": "application/pdf", "content_b64": "JVBERi0…" } ] } ``` - `body_text` is the decoded plain-text part. - Each attachment's bytes are base64 in `content_b64`; decode to recover the file (`echo "$b64" | base64 -d > report.pdf`). `size` is the decoded byte length. - `get` does **not** acknowledge the message. - A filtered/invisible or missing UID returns `error: true`, code `not_found`. --- ## `search` — server-side search (whole folder) ``` emcli search --account A [--folder F] [--from X] [--subject-contains X] [--text X] \ [--since-date D] [--before-date D] [--limit N] ``` | Flag | Meaning | |---|---| | `--from` | Sender contains | | `--subject-contains` | Subject contains | | `--text` | Full-text | | `--since-date` / `--before-date` | RFC 3339 bounds, e.g. `2026-06-01T00:00:00Z` | | `--limit` | Max results (default 50) | `data` shape is identical to `list` (`{ "messages": [ … ] }`). Searches the whole folder regardless of new/acked state. Filtered mail never appears. --- ## `ack` — mark message(s) processed ``` emcli ack --account A [--folder F] --uid-list U1,U2,U3 ``` `data`: ```json { "acked": [70314, 70315, 70320] } ``` - The **only** command that changes state. Call it after you've actually handled a message. - Idempotent and order-independent; batch multiple UIDs comma-separated. - After ack, those UIDs no longer appear under `list --new`. - You cannot ack a message you aren't allowed to see — returns `not_found`. --- ## `send` — send or reply (RW accounts only) ``` emcli send --account A --to X [--cc X] [--bcc X] --subject S --body B \ [--attach P]… [--reply-to U [--folder F]] ``` | Flag | Meaning | |---|---| | `--to` / `--cc` / `--bcc` | Recipients — repeat the flag or comma-separate (`--to a@x,b@x`) | | `--subject` | Subject | | `--body` | Plain-text body | | `--attach` | File path to attach (repeatable) | | `--reply-to ` | Thread the reply onto this source message | | `--folder` | Folder of the `--reply-to` source (default `INBOX`) | `data`: ```json { "sent": true, "recipients": ["alice@example.com", "boss@example.com"] } ``` Blocked sends return `error: true`, code `policy`: - `ro_mode` — the account is read-only; it cannot send. - `whitelist_out` — a recipient isn't on the outbound whitelist; the **whole** send is blocked and nothing was sent. Don't silently drop recipients — tell the user. `--reply-to` reads the source message's `Message-ID`/`References` so the reply threads. The source is subject to the inbound filter: a filtered/missing source returns `not_found`. --- ## Enforcement rules (set by the user; you can't change them) - **Mode:** `RO` accounts reject `send`. `RW` can read and send. - **Inbound whitelist / subject filter:** disallowed mail is invisible everywhere (`list`/`search` omit it; `get`/`ack` return `not_found`). You can't tell a filtered message from a non-existent one — by design. - **Outbound whitelist:** every recipient (to+cc+bcc) must match, or the send is blocked whole. - **Address matching:** case-insensitive; an entry `@domain.com` matches any address at that domain; otherwise an exact-address match. ## Parsing tips ```bash # Guard on success, then read data: out=$(emcli list --account gmail --new --limit 10) if echo "$out" | jq -e '.error == false' >/dev/null; then echo "$out" | jq -r '.data.messages[] | "\(.uid)\t\(.subject)"' else echo "$out" | jq -r '.error_detail | "\(.code): \(.message)"' >&2 fi # Save an attachment from get: emcli get --account gmail --uid 70314 \ | jq -r '.data.attachments[0].content_b64' | base64 -d > report.pdf ```