Sendmux token-efficient usage
Use this skill to choose the lowest-cost Sendmux route that still answers the task correctly.
When to Use This Skill
- Use when a Sendmux task could use MCP, CLI, SDK, or direct HTTP and the user needs the cheapest correct route.
- Use when choosing batch sends, mailbox search/count/batch reads, sync deltas, cursor pagination, ETags, or idempotency keys.
- Use when avoiding broad mailbox body reads, full mailbox scans, or broad log fetches.
Copy-Paste Example
User: "Find unread invoice mail with as few Sendmux calls as possible; count, search snippets, then batch-get selected IDs."
Boundaries
- Do not ask the user to paste an API key.
- 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.
- Use scoped
smx_agent_* only for the calls its scopes and resource allow. Pre-claim agent tokens cannot send.
- 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.
- Do not read full mailbox bodies, every message, or every log row unless the user asks for full content and narrower calls cannot answer.
Surface choice
| Situation |
Use |
Why |
| Connected agent and curated tool exists |
MCP tool |
Small schema and no SDK boilerplate. |
| One-off terminal task |
sendmux CLI with --json |
Direct, scriptable, exposes the full generated operation set. |
| Application code or repeated workflow |
SDK for the project already in use |
Reuses client setup, pagination, headers, and retry helpers. |
| MCP lacks the needed operation |
CLI for terminal work, SDK for code |
Do not invent uncurated MCP tools. |
| No package/tooling available |
Direct HTTP |
Keep request bodies and headers aligned to OpenAPI. |
Cheapest-call map
| Task |
Cheapest correct default |
| Send one outbound email |
sending_send_email, CLI sending:send, SDK sendingSendEmail; include Idempotency-Key. |
| Send multiple outbound emails |
sending_send_email_batch, CLI sending:send:batch, SDK sendingSendEmailBatch; do not loop single sends. |
| Count matching mailbox messages |
mailbox_count_messages, CLI mailbox:count-messages, SDK mailboxCountMessages. |
| Search mailbox text |
mailbox_search_message_snippets, CLI mailbox:search-message-snippets, SDK mailboxSearchMessageSnippets; then fetch selected IDs. |
| Read several known messages |
mailbox_batch_get_messages, CLI mailbox:batch-get-messages, SDK mailboxBatchGetMessages. |
| Update/delete several messages |
Batch update/delete after explicit confirmation. |
| Resume broad mailbox sync |
mailbox_get_changes, CLI mailbox:get-changes, SDK mailboxGetChanges. |
| Resume filtered mailbox sync |
CLI/SDK mailbox:query-message-changes / mailboxQueryMessageChanges; MCP does not curate it yet. |
| Watch live mailbox events |
CLI/SDK mailbox:stream-events / mailboxStreamEvents; MCP does not curate it yet. |
| Scan threads |
List threads, then fetch one thread or its messages. |
| Manage domains/mailboxes/keys |
Management MCP for curated create/list/get/update/suspend/resume/key tools; CLI/SDK for uncovered lifecycle work. |
| Manage sending accounts |
CLI/SDK; MCP does not curate provider tools yet. |
| Manage webhooks |
MCP for list/create/test; CLI/SDK for get/update/delete/rotate/delivery payloads. |
| Inspect spend, logs, metrics |
Summary/metrics first; filter log lists with small limit, then fetch one selected row. |
Read less
For mailbox questions, reduce the result set before reading content:
- Count when the user asks "how many" or when the query may be broad.
- Search snippets with a small
limit when the user needs examples.
- Batch-get only selected message IDs.
- 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.
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, attachments, SMTP-vs-HTTP choice:
sendmux-send-email.
- 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.
Limitations
- Does not invent uncurated MCP tools when CLI or SDK is the broader supported surface.
- Does not read full mailbox bodies, every message, or every log row unless narrower calls cannot answer the task.
- Some recommended routes can send or mutate state, so user confirmation and idempotency still matter.
1---2name: sendmux-token-efficient-usage3description: Choose low-token Sendmux routes with batching, snippets, sync deltas, pagination, ETags, and idempotency.4---5
6# Sendmux token-efficient usage
7
8Use this skill to choose the lowest-cost Sendmux route that still answers the task correctly.
9
10## When to Use This Skill
11
12- Use when a Sendmux task could use MCP, CLI, SDK, or direct HTTP and the user needs the cheapest correct route.
13- Use when choosing batch sends, mailbox search/count/batch reads, sync deltas, cursor pagination, ETags, or idempotency keys.
14- Use when avoiding broad mailbox body reads, full mailbox scans, or broad log fetches.
15
16## Copy-Paste Example
17
18```text
19User: "Find unread invoice mail with as few Sendmux calls as possible; count, search snippets, then batch-get selected IDs."
20```
21
22## Boundaries
23
24- Do not ask the user to paste an API key.
25- 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.
26- Use scoped `smx_agent_*` only for the calls its scopes and resource allow. Pre-claim agent tokens cannot send.
27- Use `smx_root_*` for Management calls.
28- Do not default to MCP for every task. MCP is best when the required tool is curated; CLI and SDK cover broader surfaces.
29- Do not read full mailbox bodies, every message, or every log row unless the user asks for full content and narrower calls cannot answer.
30
31## Surface choice
32
33| Situation | Use | Why |
34| --------------------------------------- | ----------------------------------- | ------------------------------------------------------------- |
35| Connected agent and curated tool exists | MCP tool | Small schema and no SDK boilerplate. |
36| One-off terminal task | `sendmux` CLI with `--json` | Direct, scriptable, exposes the full generated operation set. |
37| Application code or repeated workflow | SDK for the project already in use | Reuses client setup, pagination, headers, and retry helpers. |
38| MCP lacks the needed operation | CLI for terminal work, SDK for code | Do not invent uncurated MCP tools. |
39| No package/tooling available | Direct HTTP | Keep request bodies and headers aligned to OpenAPI. |
40
41## Cheapest-call map
42
43| Task | Cheapest correct default |
44| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
45| Send one outbound email | `sending_send_email`, CLI `sending:send`, SDK `sendingSendEmail`; include `Idempotency-Key`. |
46| Send multiple outbound emails | `sending_send_email_batch`, CLI `sending:send:batch`, SDK `sendingSendEmailBatch`; do not loop single sends. |
47| Count matching mailbox messages | `mailbox_count_messages`, CLI `mailbox:count-messages`, SDK `mailboxCountMessages`. |
48| Search mailbox text | `mailbox_search_message_snippets`, CLI `mailbox:search-message-snippets`, SDK `mailboxSearchMessageSnippets`; then fetch selected IDs. |
49| Read several known messages | `mailbox_batch_get_messages`, CLI `mailbox:batch-get-messages`, SDK `mailboxBatchGetMessages`. |
50| Update/delete several messages | Batch update/delete after explicit confirmation. |
51| Resume broad mailbox sync | `mailbox_get_changes`, CLI `mailbox:get-changes`, SDK `mailboxGetChanges`. |
52| Resume filtered mailbox sync | CLI/SDK `mailbox:query-message-changes` / `mailboxQueryMessageChanges`; MCP does not curate it yet. |
53| Watch live mailbox events | CLI/SDK `mailbox:stream-events` / `mailboxStreamEvents`; MCP does not curate it yet. |
54| Scan threads | List threads, then fetch one thread or its messages. |
55| Manage domains/mailboxes/keys | Management MCP for curated create/list/get/update/suspend/resume/key tools; CLI/SDK for uncovered lifecycle work. |
56| Manage sending accounts | CLI/SDK; MCP does not curate provider tools yet. |
57| Manage webhooks | MCP for list/create/test; CLI/SDK for get/update/delete/rotate/delivery payloads. |
58| Inspect spend, logs, metrics | Summary/metrics first; filter log lists with small `limit`, then fetch one selected row. |
59
60## Read less
61
62For mailbox questions, reduce the result set before reading content:
63
641. Count when the user asks "how many" or when the query may be broad.
652. Search snippets with a small `limit` when the user needs examples.
663. Batch-get only selected message IDs.
674. Request clean body/content only when message text affects the answer.
68
69CLI:
70
71```bash
72sendmux mailbox:count-messages \
73 --query q=invoice \
74 --query is_unread=true \
75 --json
76
77sendmux mailbox:search-message-snippets \
78 --query q=invoice \
79 --query is_unread=true \
80 --query limit=10 \
81 --json
82
83sendmux mailbox:batch-get-messages \
84 --body '{
85 "ids": ["eml_abc", "eml_def"],
86 "body_mode": "clean_json",
87 "max_body_chars": 4000,
88 "strip_quotes": true,
89 "strip_signature": true,
90 "include_attachments": "metadata"
91 }' \
92 --json
93```
94
95## Write fewer requests
96
97Batch when there is more than one target.
98
99```bash
100sendmux sending:send:batch \
101 --idempotency-key "$IDEMPOTENCY_KEY" \
102 --body-file ./messages.json \
103 --json
104
105sendmux mailbox:batch-update-messages \
106 --body '{
107 "ids": ["eml_abc", "eml_def"],
108 "seen": true,
109 "if_in_state": "state_from_prior_read"
110 }' \
111 --json
112```
113
114For batch sends, inspect every per-message result before reporting success. Batch can contain mixed outcomes.
115
116## Sync by delta
117
118Use sync endpoints instead of re-listing stable data.
119
120Broad mailbox sync:
121
122```bash
123sendmux mailbox:get-changes \
124 --query messages_since_state="$MESSAGES_STATE" \
125 --query folders_since_state="$FOLDERS_STATE" \
126 --query threads_since_state="$THREADS_STATE" \
127 --query limit=100 \
128 --json
129```
130
131Filtered message sync:
132
133```bash
134sendmux mailbox:query-message-changes \
135 --query since_query_state="$QUERY_STATE" \
136 --query q=invoice \
137 --query is_unread=true \
138 --query limit=100 \
139 --json
140```
141
142Store the returned state token. Continue with the same filters only while `has_more` is true and the next page is needed.
143
144## Transfer less
145
146- Use small `limit` values on list calls.
147- Follow `pagination.next_cursor` only until enough evidence has been gathered.
148- Prefer summary or metrics endpoints before log lists.
149- Use `If-None-Match` for repeated detail reads that previously returned an `ETag`.
150- Use `If-Match` for updates when the prior read returned an `ETag`.
151
152CLI conditional examples:
153
154```bash
155sendmux management:get-email-log \
156 --path public_id=dlog_abc \
157 --if-none-match "$ETAG" \
158 --json
159
160sendmux management:update-mailbox \
161 --path public_id=mbx_abc \
162 --if-match "$ETAG" \
163 --body '{"display_name":"Agent Inbox"}' \
164 --json
165```
166
167SDK helpers:
168
169```
170import {
171 conditionalHeaders,
172 idempotencyHeaders,
173 paginate,
174 responseEtag,
175} from "@sendmux/core";
176
177const headers = conditionalHeaders({ ifNoneMatch: priorEtag });
178const writeHeaders = {
179 ...conditionalHeaders({ etag: priorEtag }),
180 ...idempotencyHeaders(operationKey),
181};
182```
183
184## Retry safely
185
186Use `Idempotency-Key` on supported mutations so retrying does not create duplicate work.
187
188Good candidates:
189
190- `sending:send` and `sending:send:batch`.
191- `mailbox:send-message`.
192- Management creates, mailbox key creation, suspend/resume, provider mutations, webhook create/rotate/test.
193
194When 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.
195
196## Routing
197
198- Setup, key scopes, first call: `sendmux-getting-started`.
199- Email send bodies, attachments, SMTP-vs-HTTP choice: `sendmux-send-email`.
200- Mailbox read/search/sync/triage/reply details: `sendmux-mailbox-agent`.
201- Management domains, mailboxes, webhooks, billing, logs: `sendmux-management`.
202- CLI syntax and profiles: `sendmux-cli`.
203- MCP installation and client config: `sendmux-mcp-setup`.
204
205## Limitations
206
207- Does not invent uncurated MCP tools when CLI or SDK is the broader supported surface.
208- Does not read full mailbox bodies, every message, or every log row unless narrower calls cannot answer the task.
209- Some recommended routes can send or mutate state, so user confirmation and idempotency still matter.