Install
openclaw skills install @sendmux.ai/sendmux-mailbox-agentLet an OpenClaw agent read, search, count, sync, triage, file, delete, thread, and reply from one Sendmux mailbox efficiently.
openclaw skills install @sendmux.ai/sendmux-mailbox-agentThis ClawHub skill connects OpenClaw agents to Sendmux. Some workflows require a Sendmux account and an appropriate Sendmux API key or agent token. Sendmux account usage is external to ClawHub; do not ask users to paste secrets into chat.
Use this skill for mailbox-scoped workflows with an smx_mbx_ key or scoped smx_agent_ token: read, search, triage, reply when allowed, and sync one mailbox.
sendmux-management.smx_agent_ tokens as read/receive only. They do not have email.send; owner-approved app-resource smx_agent_ tokens may send from their assigned mailbox when the token includes email.send.mailbox_id on mailbox calls; otherwise omit it.| Task | Preferred call |
|---|---|
| Identify the mailbox | mailbox_get_me, CLI mailbox:me:get, SDK mailboxGetMe. |
| Count matching messages | mailbox_count_messages, CLI mailbox:count-messages, SDK mailboxCountMessages. |
| Search text | mailbox_search_message_snippets, CLI mailbox:search-message-snippets, SDK mailboxSearchMessageSnippets. |
| Read known IDs | mailbox_batch_get_messages, CLI mailbox:batch-get-messages, SDK mailboxBatchGetMessages. |
| Mark, flag, or label many messages | mailbox_batch_update_messages, CLI mailbox:batch-update-messages, SDK mailboxBatchUpdateMessages. |
| Delete many messages | mailbox_batch_delete_messages, CLI mailbox:batch-delete-messages, SDK mailboxBatchDeleteMessages. |
| Reply/send from this mailbox | mailbox_send_message, CLI mailbox:send-message, SDK mailboxSendMessage. |
| Upload/read attachments | mailbox_upload_attachment, mailbox_get_attachment, and sendmux-attachments for zero-context files. |
| Threads | mailbox_list_threads, mailbox_get_thread, mailbox_list_thread_messages. |
| Folders | mailbox_list_folders; inspect folders before filing or moving messages. |
| Broad sync | mailbox_get_changes, CLI mailbox:get-changes, SDK mailboxGetChanges. |
| Filtered message sync | CLI/SDK mailbox:query-message-changes / mailboxQueryMessageChanges. MCP does not curate this yet. |
| Live mailbox events | CLI/SDK mailbox:stream-events / mailboxStreamEvents. MCP does not curate this yet. |
Use this sequence for most "find messages about X" tasks:
limit.CLI:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:count-messages \
--query q=invoice \
--query is_unread=true \
--json
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:search-message-snippets \
--query q=invoice \
--query is_unread=true \
--query limit=10 \
--json
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" 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
Use the same commands by putting a scoped smx_agent_ token in SENDMUX_API_KEY when the operation is within its scopes.
SDK:
import {
createMailboxClient,
mailboxBatchGetMessages,
mailboxCountMessages,
mailboxSearchMessageSnippets,
} from "@sendmux/mailbox";
const client = createMailboxClient({ apiKey: process.env.SENDMUX_API_KEY! });
const count = await mailboxCountMessages({
client,
query: { q: "invoice", is_unread: true },
});
const snippets = await mailboxSearchMessageSnippets({
client,
query: { q: "invoice", is_unread: true, limit: 10 },
});
const messages = await mailboxBatchGetMessages({
client,
body: {
ids: snippets.data.snippets.map((item) => item.message_id),
body_mode: "clean_json",
max_body_chars: 4000,
strip_quotes: true,
strip_signature: true,
include_attachments: "metadata",
},
});
Use batch mutations for more than one message. Get user confirmation first.
Mark or label messages:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:batch-update-messages \
--body '{
"ids": ["eml_abc", "eml_def"],
"seen": true,
"flagged": false,
"keywords": {
"agent_triaged": true,
"needs_reply": false
},
"if_in_state": "state_from_prior_read"
}' \
--json
Delete messages only after explicit confirmation:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:batch-delete-messages \
--body '{
"ids": ["eml_abc", "eml_def"],
"permanent": false,
"if_in_state": "state_from_prior_read"
}' \
--json
permanent: false moves messages to Trash. Treat permanent: true as irreversible and ask for explicit confirmation.
Before composing, read the identity:
mailbox_get_identity
Then send from the authenticated mailbox. Use Idempotency-Key for retries.
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:send-message \
--idempotency-key "$IDEMPOTENCY_KEY" \
--body '{
"to": [{ "email": "user@example.com", "name": null }],
"subject": "Re: Your message",
"html_body": "<p>Thanks for the update.</p>",
"text_body": "Thanks for the update."
}' \
--json
Mailbox send uses to as an array. subject and to are required. from is optional when sending from the authenticated mailbox identity.
For attachments, route to sendmux-attachments.
Prefer zero-context file flows:
mailbox_upload_attachment with file_path, then send with the returned blob_id.PUT the file without an API key, then send with the returned blob_id.sendmux mailbox:send-message --attach ./report.pdf.Mailbox upload paths share a 7,500,000 byte per-attachment cap. For larger files, split them or send a link to externally hosted content.
Inline base64 is only for tiny generated files. If you already have a blob, send it as:
{
"filename": "report.pdf",
"content_type": "application/pdf",
"blob_id": "blob_..."
}
mailbox_list_threads with small limit for conversation-level scanning.mailbox_get_thread for one thread summary.mailbox_list_thread_messages for message summaries in a known thread.mailbox_list_folders before moving or filing messages.CLI examples:
sendmux mailbox:list-threads --query q=renewal --query limit=10 --json
sendmux mailbox:list-thread-messages --path thread_id=thr_abc --query limit=20 --json
sendmux mailbox:folders:list --query limit=100 --json
Use sync endpoints instead of re-listing the mailbox.
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
Filtered message-list sync:
sendmux mailbox:query-message-changes \
--query since_query_state="$QUERY_STATE" \
--query q=invoice \
--query is_unread=true \
--query calculate_total=true \
--query limit=100 \
--json
Store the returned new state token. Follow has_more with the same filters when more changes remain.
401: missing, invalid, or revoked key.403: wrong key surface or missing mailbox permission.404: selected message, thread, or folder does not exist in this mailbox.409: stale state or idempotency conflict; re-read state before mutating.429 or 503: retry according to response headers.sendmux-getting-started.sendmux-send-email.sendmux-attachments.sendmux-management.sendmux-cli.sendmux-token-efficient-usage.