Die Oberfläche ist lokalisiert; Skill-Beschreibungen und -Dokumente werden per KI automatisch in Ihre Sprache übersetzt. Code, Befehle, Pfade und Fachbegriffe bleiben im Original, maßgeblich ist das Dokument des Autors.
Skills entdecken
Entwicklung · SKILL.md

sendmux-token-efficient-usage

sendmux-token-efficient-usage

Use when the question is about *how to call* Sendmux cheaply, not what to send: choosing batch vs. looped sends, mailbox search/count/batch-read vs. full fetches, sync deltas, cursor pagination, ETags/conditional requests, idempotency keys, or picking between MCP, the sendmux CLI, an SDK, or direct HTTP. Trigger for reducing token/round-trip/API-call cost, …

Independent GitHub snapshot · Automated classification · Original documentation governs

SSendmux / skillsApache-2.0

Skill-Dokumentation

GitHub

name: sendmux-token-efficient-usage description: "Use when the question is about how to call Sendmux cheaply, not what to send: choosing batch vs. looped sends, mailbox search/count/batch-read vs. full fetches, sync deltas, cursor pagination, ETags/conditional requests, idempotency keys, or picking between MCP, the sendmux CLI, an SDK, or direct HTTP. Trigger for reducing token/round-trip/API-call cost, avoiding broad mailbox or log fetches, or optimising a polling/sync loop.\n\nThis is a routing/cost-decision skill, never a content-authoring one. If the request asks to write, draft, compose, or format the actual JSON body, subject, text, or attachment bytes of an email — even a single email, even one with an attachment, even inside a larger batch — do NOT use this skill; route that to sendmux-send-email or sendmux-attachments instead. Ask yourself: is the user asking "what's the cheapest way to call Sendmux," or "what should this email/attachment contain"? Only the former belongs here." license: Apache-2.0 metadata: author: sendmux version: "1.0"

Sendmux token-efficient usage

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 smx_mbx_* keys for normal Mailbox calls.
  • For a self-registered agent, reuse one durable CLI profile. Mailbox reads become available after provisioning, before owner approval; Sending stays blocked until owner approval.
  • For API-key authentication, use smx_root_* for Management calls.
  • Do not default to MCP for every task. MCP is best when the required tool is curated; CLI and SDK cover broader surfaces.
  • Keep real attachment bytes outside model context and route their mechanics to sendmux-attachments; use the attachment route reference below.
  • Do not read full mailbox bodies, every message, or every log row unless the user asks for full content and narrower calls cannot answer.

Choose the authentication connection, then its already-approved product surface. For an existing OAuth profile, use the already-known approved surface from its granted permissions or setup context. If that surface is unknown, show the surface-specific alternatives below and ask which one the profile grants; there is no universal Mailbox default.

Authentication connectionValidate withOwnership boundary
Existing CLI or REST OAuth profileThe selected CLI operation: mailbox:get-connection, management:get-connection, or sending:get-connectionExplain that the check stays within the profile's approved surface, scopes, and mailboxes. sendmux-cli owns login and refresh.
SDK application credentialsThe selected SDK operation: mailboxGetConnection, managementGetConnection, or sendingGetConnectionThe application supplies SDK credentials; this is not a CLI profile check.
Already-connected MCP sessionThe selected MCP operation: mailbox_get_connection, management_get_connection, or sending_get_connectionThis validates only that MCP session. sendmux-mcp-setup owns hosted MCP OAuth setup; it is not an alternate view of a REST profile.

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.

Credential ownership follows the surface. For a durable CLI agent profile, the CLI automatically exchanges and caches the one-hour delegated token for sending:* commands. SDK callers supply a compatible apiKey or accessToken (or their own provider callback); SDK helpers do not read or update CLI profile state.

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 attachmentsUse the attachment route reference below.
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, metricsMetrics first; use management:list-email-logs / managementListEmailLogs for filtered summaries, then management:get-email-log / managementGetEmailLog for one selected row.

Attachment route reference

sendmux-attachments owns the detailed upload/download procedures and current direct-upload limits.

When comparing local-file routes, state how bytes move and which size authority applies for each alternative below, then recommend the one matching the user's environment:

  1. Terminal: recommend CLI --attach for a one-off task. It uploads directly outside model context; server-enforced direct-upload limits apply. There is no presign-limit response.
  2. Application code: name sendEmailWithFiles or uploadAttachmentFromFile from @sendmux/sending/node, or uploadMailboxAttachmentFromFile from @sendmux/mailbox/node. These helpers upload directly outside model context; server-enforced direct-upload limits apply, with no presign-limit response.
  3. Connected MCP: name sending_create_attachment_upload for Sending, or mailbox_upload_attachment with presign_upload_url=true for Mailbox. Both use presigned external transfer outside model context. For Sending, obey the upload intent's returned max_size_bytes; Mailbox accepts requested size_bytes up to 7,500,000.

For tiny agent-authored content, MCP inline content_base64 is available only after measuring the decoded content at no more than 32,768 bytes; a filename or file type cannot establish eligibility.

For presigned Sending uploads, the intent returns a temporary upload_id; take the final attachment_id from the successful external PUT response. A successful external Mailbox upload returns the blob_id for Mailbox sends. Never use MCP file_path or real-file inline base64.

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. For this self-registered agent, sending has two owner gates: the owner accepts the invitation, then explicitly approves sending. Once both are complete, use the same profile with sending:*; the CLI handles the one-hour delegated token exchange and cache.

Explain the storage boundary alongside this setup: the 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.

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; choose from the returned message_id, subject, and preview fields.
  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.

For API-key or delegated-token authentication, name the Sending authority alongside the recommended call: a send-capable smx_mbx_* key or owner-approved Sending-resource smx_agent_* token. This applies to both single and batch sends.

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.

Choose the sync route that matches the requested view: broad mailbox state uses mailbox:get-changes / mailboxGetChanges; a filtered message view uses mailbox:query-message-changes / mailboxQueryMessageChanges.

Broad mailbox sync:

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

This multi-resource sync requires types=messages,folders,threads; omitting types deliberately selects the legacy message-only response. Before the next call, persist each returned resource's new_state and has_more. Map data.types.messages.new_state, data.types.folders.new_state, and data.types.threads.new_state to the matching *_since_state input. Continue each resource whose saved has_more is true independently with its saved state; a narrower response updates only the resource it requested.

For a message-only continuation, use the selected resource's fields exactly:

sendmux mailbox:get-changes \
  --query types=messages \
  --query messages_since_state="$NEXT_MESSAGES_STATE" \
  --query limit=100 \
  --json

After every response, replace the current response, set NEXT_MESSAGES_STATE from its data.types.messages.new_state, and repeat only while that same latest response's data.types.messages.has_more is true.

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

After every response, set QUERY_STATE from its data.new_query_state, and continue with the same filters only while that same latest response's data.has_more is true and the next page is needed.

A polling-loop answer must distinguish sync continuation from cursor-paginated list calls. For the latter, preserve the same filters and a small bounded limit, count matches cumulatively across pages, stop immediately when the local threshold is reached even mid-page, and follow the returned pagination.next_cursor only while another list page is needed. At the start of every polling tick, call each enabled sync route once with its saved state and perform each enabled conditional-log read once, even when the prior sync response had has_more=false; within that tick, add one call for every requested continuation page.

Use the public delivery-log seams exactly:

  • For filtered summary pages, use CLI management:list-email-logs or SDK managementListEmailLogs. Preserve only supported filters (status, from_date, to_date, provider_id, search), and map the returned pagination.next_cursor to the next cursor input.
  • For repeated reads of one known log, CLI management:get-email-log --if-none-match "$ETAG" can send an ETag supplied from elsewhere, but CLI output is the API JSON body—not an HTTP status/header envelope. It cannot acquire or refresh the ETag or branch on 304.
  • For the first metadata-bearing read and every later 304-aware read, use the supported SDK packages directly; priorEtag is absent on the first call:
import { responseEtag } from "@sendmux/core";
import { createManagementClient, managementGetEmailLog } from "@sendmux/management";

const client = createManagementClient({ apiKey: process.env.SENDMUX_API_KEY! });

const result = await managementGetEmailLog({
  client,
  path: { public_id: logId },
  headers: priorEtag ? { "If-None-Match": priorEtag } : {},
  throwOnError: false,
});

if (result.response?.status === 304) {
  // Unchanged representation; there is no response body.
} else if (result.error) {
  // Handle the unsuccessful response.
} else {
  const log = result.data?.data;
  const nextEtag = responseEtag(result.response);
}

The terminal delivery statuses are sent, failed, and rejected. A 304 means the representation is unchanged; it does not establish a terminal delivery status.

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, follow the attachment route reference above.

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.
Gespeicherte Skills