Files
emcli/skills/emcli/SKILL.md
T
steve 7087533644 docs(skill): split setup into AGENTIC-MANUAL.md; keep SKILL.md lean
The SKILL.md body loads into context on every activation, so one-time install/
setup prose was wasted context once emcli is running. Move it out:

- New AGENTIC-MANUAL.md: get-the-files bootstrap, binary install (incl. options
  and build-from-source, folding in the old references/install.md), EMCLI_KEY,
  account discovery. Fetched only during first-time setup.
- SKILL.md trimmed (182→~145 lines) to the recurring path: security model, a short
  "Files & first run" pointer + per-session preflight, the list/get/ack/send
  workflow, JSON envelope, command table, enforcement, do/don't.
- Remove references/install.md (folded in); fix RELEASING.md pointer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:01:46 +01:00

7.1 KiB


name: emcli description: Read and send email through emcli, a guard-railed CLI gateway that mediates IMAP/SMTP so the agent never holds mail credentials. Use when a task involves checking or reading an inbox, listing or searching messages, fetching a message or its attachments, marking mail as processed, or sending or replying to email on the user's behalf. Works with Gmail and any IMAP/SMTP account; every command prints a single JSON object. Triggers include: check my email, read the inbox, list/search messages, get or download a message, reply to that email, send an email, process new mail. compatibility: Requires the emcli binary (run scripts/install.sh to fetch it; needs curl or wget and a Linux/macOS/Windows shell) and the EMCLI_KEY environment variable, which the orchestrator provides. Needs network access to the configured mail server. metadata: author: steve version: "0.4.0" homepage: "https://gitea.dcglab.co.uk/steve/emcli"

emcli — email for agents

emcli is a command-line gateway for email. You (the agent) call its agent commands to read and send mail; the program holds the credentials and enforces the user's rules, so you never see a password and cannot bypass the limits. Every agent command prints exactly one line of JSON and sets its exit code to match.

Security model — read this first

  • You only run agent commands: list, get, search, ack, send. Account setup, passwords, whitelists, and config are the user's job (admin commands) — do not run or suggest running account, whitelist, config, init, or doctor unless the user explicitly asks you to help administer.
  • Never touch the secret key. EMCLI_KEY is supplied in the environment by whoever launched you. Do not read it, print it, log it, pass it as an argument, or try to generate one. If it is missing, stop and tell the user (see "Files & first run").
  • Some mail is intentionally invisible. The user may restrict which senders you can see and who you can email. Blocked or filtered results are normal — handle them, don't try to work around them (see Enforcement).

Files & first run

This skill ships more than this file. Paths like AGENTIC-MANUAL.md and references/commands.md are relative to this skill's directory; if one isn't on disk, fetch it from the raw base URL + path:

https://gitea.dcglab.co.uk/steve/emcli/raw/branch/main/skills/emcli/
  • First-time setup — installing the binary, the EMCLI_KEY, finding accounts: read AGENTIC-MANUAL.md. Only needed when emcli isn't set up yet.
  • Full command detail — every flag, JSON shapes, error codes: references/commands.md.

Per-session preflight (quick): run emcli version; if it's not found, set up via AGENTIC-MANUAL.md. Confirm EMCLI_KEY is set without printing it (test -n "$EMCLI_KEY"); if empty, tell the user their orchestrator must provide it. Then get the account name from the user.

How to read every result

Each command prints one JSON object:

{ "error": false, "error_detail": {}, "data": { } }

Always check error first.

  • error: false → use data.
  • error: true → read error_detail.code and error_detail.message. The exit code is also non-zero.

With jq:

out=$(emcli list --account gmail --new) || true
echo "$out" | jq -e '.error == false' >/dev/null && echo "$out" | jq '.data.messages'

Error codes you may get back: config, db, network, auth, policy, not_found, usage. A policy error means the user's rules blocked the action; not_found is returned both for missing mail and for mail you are not allowed to see — treat them the same.

The core workflow: process new mail

ACC=gmail   # the account name the user gave you

# 1. See what's new (unprocessed). Headers only — cheap.
emcli list --account "$ACC" --new --limit 20

# 2. For a message of interest, fetch the full body + attachments.
emcli get --account "$ACC" --uid 70314

# 3. Do the work (summarize, extract, draft a reply, etc.).

# 4. Mark it processed so it stops showing under --new. This is deliberate — do it
#    only when you've actually handled the message.
emcli ack --account "$ACC" --uid-list 70314

Acking is the only command that changes state; list/get/search never do. Ack is safe to repeat and order-independent (you can ack several UIDs: --uid-list 70314,70315,70320).

Sending mail

emcli send --account "$ACC" \
  --to alice@example.com --subject "Hello" --body "Plain-text body."

# multiple recipients (repeat or comma-separate), cc/bcc, attachments:
emcli send --account "$ACC" --to a@x.com --to b@x.com --cc boss@x.com \
  --subject "Report" --body "see attached" --attach ./report.pdf

# reply that threads correctly off a message you can see:
emcli send --account "$ACC" --to a@x.com --subject "Re: Hi" --body "thanks" \
  --reply-to 70314 --folder INBOX

Sending only works on read-write accounts. If you get policy / ro_mode, the account is read-only — tell the user; do not attempt another account without their say-so.

Command quick reference

Command Purpose
emcli list --account A [--folder F] [--new] [--limit N] [--before U] [--since U] Message headers, newest first
emcli get --account A [--folder F] --uid U One full message (body + attachments)
emcli search --account A [--folder F] [--from X] [--subject-contains X] [--text X] [--since-date D] [--before-date D] Server-side search
emcli ack --account A [--folder F] --uid-list U1,U2 Mark message(s) processed
emcli send --account A --to X [--cc X] [--bcc X] --subject S --body B [--attach P]… [--reply-to U] Send / reply

Defaults: --folder INBOX, --limit 50 (max 500). Dates are RFC 3339 (e.g. 2026-06-01T00:00:00Z). UIDs come from list/search output.

Full reference (every flag, exact JSON shapes for each command, attachment encoding, error codes, and the enforcement rules): references/commands.md — read it from disk, or fetch it from the raw base URL in "Files & first run" above if you don't have it locally.

Enforcement awareness — work with the rules

The user configures these; you cannot change them and shouldn't try.

  • Read-only (RO) accounts reject send (policy / ro_mode).
  • Inbound whitelist / subject filter: mail from disallowed senders (or non-matching subjects) is invisible — it won't appear in list/search, and get/ack on it return not_found.
  • Outbound whitelist: if any recipient isn't allowed, the whole send is blocked (policy / whitelist_out) — nothing is sent. Don't retry by dropping recipients silently; surface it to the user.

Do / Don't

  • Check error on every call; report policy/not_found/auth outcomes plainly to the user.
  • get to read, then ack only after you've truly processed a message.
  • Ask the user for the account name; keep bodies plain text.
  • Don't read, print, or invent EMCLI_KEY or any password.
  • Don't run admin commands (account/whitelist/config/init) unless asked to help set up.
  • Don't treat a blocked send or filtered message as a bug to route around — it's the user's policy.