Sendmux CLI

SkillAI & models

Use when a user wants Sendmux terminal commands for agent inbox registration, owner invites, profiles, key-scope preflight, JSON output, or Management, Mailbox, and Sending operations.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Sendmux CLI skill

What this skill tells your AI

The instructions your AI receives, as published by sendmux/skills in skills/sendmux-cli/SKILL.md and read by ahel’s review.

Use this skill when the terminal is the right Sendmux surface.

Boundaries

  • Do not ask the user to paste API keys.
  • For API-key profiles, use smx_root_ for management:* and smx_mbx_ or scoped smx_agent_ for mailbox:*.
  • OAuth profiles require the operation's approved surface, scopes and mailbox access. REST OAuth tokens authenticate HTTP, not SMTP or IMAP.
  • Durable agent profiles can read and receive mail while active, but cannot send until an invited owner accepts and approves sending.
  • After owner approval, sending:* commands with an agent profile automatically exchange and cache a one-hour delegated token.
  • Do not run destructive commands without explicit confirmation.
  • Use --json for agent-readable output.
  • Prefer task-specific Sendmux skills when the user needs strategy; use this skill for exact CLI mechanics.

Install

npm install -g @sendmux/cli
sendmux --help

The package exposes the sendmux binary.

OAuth login and connection checks

For an existing user's account, create a new named OAuth profile with the required scopes:

sendmux auth:login work --scope mailbox.read --scope email.send
sendmux mailbox:get-connection --profile work --json

The CLI opens browser consent and receives the callback on the same computer. --no-browser prints the authorisation URL for manual opening. It preserves existing profiles and stores tokens with restricted file permissions. Expiring tokens refresh automatically with concurrent refreshes serialised; an uncertain refresh requires a new login.

Use sending:get-connection, mailbox:get-connection, or management:get-connection for the selected surface. These checks require no mailbox selector and send no email. Use data.label for the connection name and data.team.id for its stable team identifier.

Run sendmux auth:logout work to revoke the connection and remove its profile. A failed revocation keeps the profile for retry; logout also clears an interrupted login reservation.

For externally managed tokens, inject SENDMUX_ACCESS_TOKEN through the environment. The CLI does not refresh that token. Supplying it alongside an API key is an error. See OAuth for REST APIs for grant scopes and refresh rules.

Agent inbox onboarding

No existing Sendmux account or API key is required:

sendmux agent:register my-agent \
  --mailbox-local-part my-agent \
  --client-name "My agent" \
  --default \
  --json

Add --owner-email owner@example.com to invite the owner during registration. Otherwise invite later:

sendmux agent:invite-owner owner@example.com --profile my-agent --json

The CLI persists registration idempotency before the network request, stores the durable credential in the local profile with restricted permissions, never prints it, reloads it from disk, and waits up to 10 minutes for readiness. Rerun registration with the same profile and options to resume safely.

Use the profile for later reads:

sendmux mailbox:messages:list --profile my-agent --query limit=25 --json

Read/receive access has no expiry date while the registration remains active. Sending remains blocked until the owner accepts and approves it. After approval, a command such as sending:send --profile my-agent automatically exchanges the durable credential for a one-hour email.send token and caches it until near expiry. Full registration revocation removes read access and every delegated token.

The inbox is capped at 500 MiB before approval. Enabling owner-approved sending first raises it to at least 5 GiB. Revoking sending does not itself change the current inbox storage allocation.

Profiles

Create separate profiles for root and mailbox keys.

sendmux profiles:set default --api-key "$SENDMUX_ROOT_KEY" --default --json
sendmux profiles:set mailbox --api-key "$SENDMUX_MBX_KEY" --json
sendmux profiles:set sending --api-key "$SENDMUX_MBX_KEY" --json
sendmux profiles:list --json
sendmux profiles:show default --json

Profile reads mask stored API keys and never reveal agent credentials. profiles:set reports key_kind as root or mailbox; agent:register creates a discriminated agent profile.

Authentication resolution: SENDMUX_ACCESS_TOKEN takes precedence and rejects a simultaneous API key. Otherwise:

  1. --api-key, then SENDMUX_API_KEY.
  2. If no direct key is present, --profile / -p, then SENDMUX_PROFILE, then the configured default profile.
  3. Base URL comes from --base-url, then SENDMUX_BASE_URL, then the selected profile.

Preflight

For API-key authentication, the CLI infers key kind from the prefix before sending a request. OAuth profiles use their approved grants instead of API-key prefix checks.

Command surfaceRequired key
management:*smx_root_
mailbox:*smx_mbx_ or scoped smx_agent_
sending:*Send-capable smx_mbx_ key or owner-approved Sending-resource smx_agent_ token

For an agent profile, mailbox:* uses the durable read credential. sending:* obtains a delegated token only after owner approval. management:* rejects agent profiles before the request.

Wrong-key examples fail before network:

Command requires a root API key, but --api-key contains a mailbox API key.
Command requires a send-capable `smx_mbx_` key or owner-approved Sending-resource `smx_agent_` token, but --api-key contains a root API key.

Command catalogue

The CLI exposes generated operation commands:

SurfaceCountExamples
Management54management:domains:list, management:create-domain, management:create-mailbox, management:get-spend-summary, management:create-webhook
Mailbox42mailbox:search-message-snippets, mailbox:batch-get-messages, mailbox:query-message-changes, mailbox:send-message, mailbox:list-granted-mailboxes
Sending8sending:get-open-api-spec, sending:send, sending:send:batch, sending:upload-attachment, sending:create-attachment-upload, sending:complete-attachment-upload, sending:get-attachment
OAuth2auth:login, auth:logout
Profiles3profiles:list, profiles:set, profiles:show
Agent2agent:register, agent:invite-owner

Use command-level help to discover accepted path, query, header, and body fields:

sendmux management:create-domain --help
sendmux mailbox:search-message-snippets --help
sendmux sending:send:batch --help
sendmux sending:upload-attachment --help

Operation flags

Operation commands share these flags:

FlagUse
--api-keyDirect key; overrides profile/env profile lookup.
--base-urlOverride API base URL.
--profile, -pSelect a local profile.
--bodyInline JSON request body, or text bytes for byte-oriented operations.
--body-fileRead a JSON request body or byte payload from a file.
--attachAttach a local file to supported send commands. Repeat for multiple files.
--fileRead a local file for mailbox attachment upload convenience commands.
--via-presignedUpload a mailbox --file through a short-lived signed URL instead of API bytes.
--content-typeOverride inferred MIME type for --attach or --file.
--path name=valuePath parameters. Repeat for multiple path params.
--query name=valueQuery parameters. Repeat for filters and pagination.
--header name=valueHeaders accepted by the operation. Repeat for multiple headers.
--idempotency-keyShortcut for Idempotency-Key. Works only when the operation supports it.
--if-matchShortcut for If-Match. Works only when the operation supports it.
--if-none-matchShortcut for If-None-Match. Works only when the operation supports it.
--jsonMachine-readable output.

--path, --query, and --header require name=value. Booleans use true or false. Repeat an array-valued parameter rather than comma-joining it.

Pass either --body or --body-file, not both.

Use sendmux-attachments for attachment-heavy flows and size/token trade-offs.

Examples

Create a domain:

sendmux management:create-domain \
  --profile default \
  --idempotency-key "$IDEMPOTENCY_KEY" \
  --body '{"domain":"example.com","mode":"send_receive"}' \
  --json

Get domain DNS records:

sendmux management:get-domain-zone-file \
  --profile default \
  --path public_id=mdom_abc \
  --json

Search a mailbox without reading full messages:

sendmux mailbox:search-message-snippets \
  --profile mailbox \
  --query q=invoice \
  --query is_unread=true \
  --query limit=10 \
  --json

Batch-read selected mailbox messages:

sendmux mailbox:batch-get-messages \
  --profile mailbox \
  --body '{
    "ids": ["eml_abc", "eml_def"],
    "body_mode": "clean_json",
    "max_body_chars": 4000
  }' \
  --json

Send a batch:

sendmux sending:send:batch \
  --profile sending \
  --idempotency-key "$IDEMPOTENCY_KEY" \
  --body-file ./messages.json \
  --json

Send through the Sending API with a local attachment:

sendmux sending:send \
  --profile sending \
  --idempotency-key "$IDEMPOTENCY_KEY" \
  --attach ./report.pdf \
  --body '{"from":{"email":"sender@example.com"},"to":{"email":"user@example.com"},"subject":"Report","html_body":"<p>Attached.</p>"}' \
  --json

sending:send --attach uploads the file first and injects an attachment_id reference; it does not place base64 in the send body.

Upload a Sending attachment separately:

sendmux sending:upload-attachment \
  --profile sending \
  --body-file ./report.pdf \
  --query filename=report.pdf \
  --query content_type=application/pdf \
  --json

Send a mailbox message with a local attachment:

sendmux mailbox:send-message \
  --profile mailbox \
  --idempotency-key "$IDEMPOTENCY_KEY" \
  --attach ./report.pdf \
  --body '{"to":[{"email":"user@example.com","name":null}],"subject":"Report","text_body":"Attached."}' \
  --json

Mailbox attachment upload commands share the 7,500,000 byte per-attachment cap. For larger files, split the file or host it externally and send a link.

Upload a mailbox attachment by presigned URL:

sendmux mailbox:upload-attachment \
  --profile mailbox \
  --file ./report.pdf \
  --via-presigned \
  --json

Poll one unchanged-safe delivery log:

sendmux management:get-email-log \
  --profile default \
  --path public_id=dlog_abc \
  --if-none-match "$ETAG" \
  --json

Routing

  • First setup/auth check: sendmux-getting-started.
  • Sending strategy and body shape: sendmux-send-email.
  • Attachment file paths and presigned upload/download: sendmux-attachments.
  • Mailbox read, search, sync, triage, or reply: sendmux-mailbox-agent.
  • Account-level management strategy: sendmux-management.
  • MCP connection setup: sendmux-mcp-setup.
  • Cheapest-call doctrine: sendmux-token-efficient-usage.

Signals

GitHub stars
20
Forks
1
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
sendmux-cli
Source
github.com/sendmux/skills