Sendmux token-efficient usage

SkillSearch

Choose the cheapest correct Sendmux surface and call. Use whenever a Sendmux task could be done through MCP, the sendmux CLI, an SDK, or direct HTTP and the user needs low-token, low-round-trip usage: batch sends, mailbox search/count/batch reads, sync deltas, cursor pagination, ETags, conditional requests, idempotency keys, attachment file transfer, or avoiding broad mailbox/log fetches.

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 token-efficient usage skill

What this skill tells your AI

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

Use this skill to choose the lowest-cost Sendmux route that still answers the task correctly.

Boundaries

  • Do not ask the user to paste an API key.
  • For API-key authentication, use send-capable smx_mbx_* keys or owner-approved Sending-resource smx_agent_* tokens for Sending calls, and smx_mbx_* keys for normal Mailbox calls.
  • For a self-registered agent, reuse one durable CLI profile for reads. Sending stays blocked until owner approval, then sending:* commands exchange and cache a one-hour delegated token automatically.
  • Its inbox is capped at 500 MiB before approval. Owner-approved sending raises it to at least 5 GiB first. Revoking sending does not itself change the current inbox storage allocation.
  • For API-key authentication, use smx_root_* for Management calls. REST OAuth profiles can use their approved surfaces, scopes and mailboxes; route login and refresh to sendmux-cli.
  • Do not default to MCP for every task. MCP is best when the required tool is curated; CLI and SDK cover broader surfaces.
  • Do not pipe real attachments through model context as base64. Route attachment transfer to sendmux-attachments; prefer file_path, presigned URLs, CLI --attach, or SDK file helpers. Mailbox uploads cap each attachment at 7,500,000 bytes; Sending uploads cap each file at 18 MiB; MCP inline base64 caps at 32 KiB decoded.
  • Do not read full mailbox bodies, every message, or every log row unless the user asks for full content and narrower calls cannot answer.

Validate credentials with the selected surface's get-connection CLI operation or MCP mailbox_get_connection, management_get_connection, or sending_get_connection. These checks need no mailbox selector and send no email; public OpenAPI discovery does not validate credentials.

Surface choice

SituationUseWhy
Connected agent and curated tool existsMCP toolSmall schema and no SDK boilerplate.
One-off terminal tasksendmux CLI with --jsonDirect, scriptable, exposes the full generated operation set.
Application code or repeated workflowSDK for the project already in useReuses client setup, pagination, headers, and retry helpers.
MCP lacks the needed operationCLI for terminal work, SDK for codeDo not invent uncurated MCP tools.
No package/tooling availableDirect HTTPKeep request bodies and headers aligned to OpenAPI.

Cheapest-call map

TaskCheapest correct default
Send one outbound emailsending_send_email, CLI sending:send, SDK sendingSendEmail; include Idempotency-Key.
Send multiple outbound emailssending_send_email_batch, CLI sending:send:batch, SDK sendingSendEmailBatch; do not loop single sends.
Send or read attachmentssendmux-attachments; use file_path, presigned upload/download URLs, CLI --attach, SDK file helpers, blob_id for mailbox sends, and attachment_id for Sending sends instead of inline base64.
Count matching mailbox messagesmailbox_count_messages, CLI mailbox:count-messages, SDK mailboxCountMessages.
Search mailbox textmailbox_search_message_snippets, CLI mailbox:search-message-snippets, SDK mailboxSearchMessageSnippets; then fetch selected IDs.
Read several known messagesmailbox_batch_get_messages, CLI mailbox:batch-get-messages, SDK mailboxBatchGetMessages.
Update/delete several messagesBatch update/delete after explicit confirmation.
Resume broad mailbox syncmailbox_get_changes, CLI mailbox:get-changes, SDK mailboxGetChanges.
Resume filtered mailbox syncCLI/SDK mailbox:query-message-changes / mailboxQueryMessageChanges; MCP does not curate it yet.
Watch live mailbox eventsCLI/SDK mailbox:stream-events / mailboxStreamEvents; MCP does not curate it yet.
Scan threadsList threads, then fetch one thread or its messages.
Manage domains/mailboxes/keysManagement MCP for curated create/list/get/update/suspend/resume/key tools; CLI/SDK for uncovered lifecycle work.
Manage sending accountsCLI/SDK; MCP does not curate provider tools yet.
Manage webhooksMCP for list/create/test; CLI/SDK for get/update/delete/rotate/delivery payloads.
Inspect spend, logs, metricsSummary/metrics first; filter log lists with small limit, then fetch one selected row.

For an agent with no key, avoid manual protocol calls and token copying:

sendmux agent:register my-agent --default --json
sendmux mailbox:me:get --profile my-agent --json
sendmux agent:invite-owner owner@example.com --profile my-agent --json

Register once, then reuse the durable profile across processes. After owner acceptance and sending approval, use the same profile with sending:*; the CLI handles the one-hour delegated token exchange and cache.

Read less

For mailbox questions, reduce the result set before reading content:

  1. Count when the user asks "how many" or when the query may be broad.
  2. Search snippets with a small limit when the user needs examples.
  3. Batch-get only selected message IDs.
  4. Request clean body/content only when message text affects the answer.

CLI:

sendmux mailbox:count-messages \
  --query q=invoice \
  --query is_unread=true \
  --json

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

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

Write fewer requests

Batch when there is more than one target.

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

sendmux mailbox:batch-update-messages \
  --body '{
    "ids": ["eml_abc", "eml_def"],
    "seen": true,
    "if_in_state": "state_from_prior_read"
  }' \
  --json

For batch sends, inspect every per-message result before reporting success. Batch can contain mixed outcomes.

Sync by delta

Use sync endpoints instead of re-listing stable data.

Broad mailbox sync:

sendmux mailbox:get-changes \
  --query messages_since_state="$MESSAGES_STATE" \
  --query folders_since_state="$FOLDERS_STATE" \
  --query threads_since_state="$THREADS_STATE" \
  --query limit=100 \
  --json

Filtered message sync:

sendmux mailbox:query-message-changes \
  --query since_query_state="$QUERY_STATE" \
  --query q=invoice \
  --query is_unread=true \
  --query limit=100 \
  --json

Store the returned state token. Continue with the same filters only while has_more is true and the next page is needed.

Transfer less

  • Use small limit values on list calls.
  • Follow pagination.next_cursor only until enough evidence has been gathered.
  • Prefer summary or metrics endpoints before log lists.
  • Use If-None-Match for repeated detail reads that previously returned an ETag.
  • Use If-Match for updates when the prior read returned an ETag.
  • For inbound attachments, fetch metadata and use the short-lived download_url; if it expires, re-fetch metadata instead of building URLs manually.
  • For outbound attachments, a file path or presigned URL is usually under 100 tokens, while base64 can burn thousands of tokens and corrupt large files.

CLI conditional examples:

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

sendmux management:update-mailbox \
  --path public_id=mbx_abc \
  --if-match "$ETAG" \
  --body '{"display_name":"Agent Inbox"}' \
  --json

SDK helpers:

import {
  conditionalHeaders,
  idempotencyHeaders,
  paginate,
  responseEtag,
} from "@sendmux/core";

const headers = conditionalHeaders({ ifNoneMatch: priorEtag });
const writeHeaders = {
  ...conditionalHeaders({ etag: priorEtag }),
  ...idempotencyHeaders(operationKey),
};

Retry safely

Use Idempotency-Key on supported mutations so retrying does not create duplicate work.

Good candidates:

  • sending:send and sending:send:batch.
  • mailbox:send-message.
  • Management creates, mailbox key creation, suspend/resume, provider mutations, webhook create/rotate/test.

When retrying application code, prefer SDK retry helpers only for safe reads or idempotent writes. Non-idempotent writes should fail rather than risk duplicate side effects.

Routing

  • Setup, key scopes, first call: sendmux-getting-started.
  • Email send bodies and SMTP-vs-HTTP choice: sendmux-send-email.
  • Attachment upload/download mechanics: sendmux-attachments.
  • Mailbox read/search/sync/triage/reply details: sendmux-mailbox-agent.
  • Management domains, mailboxes, webhooks, billing, logs: sendmux-management.
  • CLI syntax and profiles: sendmux-cli.
  • MCP installation and client config: sendmux-mcp-setup.

Signals

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