Install
openclaw skills install @sendmux.ai/sendmux-attachmentsMove email attachments through Sendmux without putting file bytes in model context, using file paths, presigned URLs, CLI, SDKs, or MCP.
openclaw skills install @sendmux.ai/sendmux-attachmentsThis 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 whenever a Sendmux task involves attachment bytes.
Do not pipe real files through model context as base64 unless the file is tiny and agent-authored. Prefer paths or signed URLs.
| Mode | Use when | Token cost | Limit |
|---|---|---|---|
Local file_path | Local stdio MCP can read the user-shared file root. | tiny | Mailbox cap: 7,500,000 bytes; Sending upload cap: 18 MiB. |
| Presigned upload URL | Hosted MCP, shell-capable agents, or large local files. | tiny | Mailbox cap: 7,500,000 bytes; Sending upload cap: 18 MiB; exact size is signed. |
CLI --attach / SDK file helpers | Terminal or application code can read the file. | tiny | Mailbox cap for mailbox sends; Sending upload cap: 18 MiB and final message cap: 25 MB. |
| Inline base64 | Small generated text/files only. | high | MCP inline cap is 32 KiB decoded. |
Approximate base64 cost: 25 KB becomes about 11K generated tokens; 1 MB is impractical. A file path is usually under 100 tokens.
PUT has no Authorization header, but it only works with the unguessable short-lived signed URL and exact headers returned by Sendmux.Content-Type; let Sendmux return the real validation error if a file is rejected.PUT, send the exact Content-Type and Content-Length returned with the URL.Content-Length. CLI, SDK, and MCP file helpers calculate it for you.mailbox_read_attachment first. It returns inline text for text-like attachments and a link for binary or oversized files.download_url in attachment metadata promptly. If it expires, fetch the message or attachment metadata again.attachment_id refs returned by Sending upload endpoints. Mailbox sends use blob_id refs returned by mailbox upload endpoints. Do not mix them.Use mailbox_upload_attachment before mailbox_send_message.
Local stdio, cheapest path:
mailbox_upload_attachment
filename: report.pdf
content_type: application/pdf
file_path: /absolute/path/report.pdf
The file path must be inside a filesystem root shared by the MCP client. Hosted MCP rejects file_path.
Hosted or shell-capable path:
mailbox_upload_attachment
filename: report.pdf
content_type: application/pdf
size_bytes: 5242880
presign_upload_url: true
Then upload without an API key:
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
-H "Content-Length: 5242880" \
--data-binary @./report.pdf
Use the returned blob_id in mailbox_send_message:
{
"attachments": [
{
"blob_id": "blob_...",
"filename": "report.pdf",
"content_type": "application/pdf"
}
]
}
For tiny generated content only, use content_base64. If the tool rejects size, switch to file_path, presigned upload, CLI, or SDK file helpers.
To read inbound attachments, call mailbox_read_attachment with message_id and attachment_id.
mailbox_read_attachment
message_id: msg_...
attachment_id: att_...
Use returned text directly for text-like files. If the tool returns resource_link / download_url, fetch the link promptly outside model context. Use mailbox_get_attachment only when metadata is enough or you need to refresh an expired link. Do not construct attachment URLs manually.
Local stdio, cheapest path:
sending_upload_attachment
filename: report.pdf
content_type: application/pdf
file_path: /absolute/path/report.pdf
Use the returned attachment_id in sending_send_email or sending_send_email_batch:
{
"attachments": [{ "attachment_id": "att_..." }]
}
Hosted or shell-capable path:
sending_create_attachment_upload
filename: report.pdf
content_type: application/pdf
size_bytes: 5242880
Then PUT the file bytes to the returned upload_url with the returned headers, including X-Sendmux-Upload-Token; do not add a Sendmux API key:
curl -X PUT "$UPLOAD_URL" \
-H "X-Sendmux-Upload-Token: $UPLOAD_TOKEN" \
-H "Content-Type: application/pdf" \
-H "Content-Length: 5242880" \
--data-binary @./report.pdf
Use the attachment_id from the upload response in the send request. Use sending_get_attachment only for metadata checks.
Mailbox send with a local attachment in one command:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:send-message \
--idempotency-key "$IDEMPOTENCY_KEY" \
--attach ./report.pdf \
--body '{
"to": [{ "email": "user@example.com", "name": null }],
"subject": "Report",
"text_body": "Attached."
}' \
--json
Sending API with a local attachment:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux sending:send \
--idempotency-key "$IDEMPOTENCY_KEY" \
--attach ./report.pdf \
--body-file ./email.json \
--json
Upload a Sending attachment first, then send by attachment_id:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux sending:upload-attachment \
--body-file ./report.pdf \
--query filename=report.pdf \
--query content_type=application/pdf \
--json
Presigned mailbox upload from a local file:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:upload-attachment \
--file ./report.pdf \
--via-presigned \
--json
Mint only:
SENDMUX_API_KEY="$SENDMUX_MBX_KEY" sendmux mailbox:create-attachment-upload \
--file ./report.pdf \
--json
Override MIME type with --content-type only when inference is wrong.
Sending API direct upload with an API key:
SIZE_BYTES="$(wc -c < ./report.pdf | tr -d '[:space:]')"
curl -X POST "https://smtp.sendmux.ai/api/v1/emails/attachments?filename=report.pdf&content_type=application/pdf" \
-H "Authorization: Bearer $SENDMUX_MBX_KEY" \
-H "Content-Type: application/pdf" \
-H "Content-Length: $SIZE_BYTES" \
--data-binary @./report.pdf
Sending API delegated upload:
curl -X POST "https://smtp.sendmux.ai/api/v1/emails/attachment-uploads" \
-H "Authorization: Bearer $SENDMUX_MBX_KEY" \
-H "Content-Type: application/json" \
-d '{"filename":"report.pdf","content_type":"application/pdf","size_bytes":5242880}'
Then PUT to the returned upload_url with returned headers and no Sendmux API key. Use GET /emails/attachments/{attachment_id} only for metadata checks.
Node file helpers live under Node subpaths so browser bundles stay clean.
Mailbox:
import { createMailboxClient } from "@sendmux/mailbox";
import {
readMailboxTextAttachment,
sendMailboxMessageWithFiles,
} from "@sendmux/mailbox/node";
const client = createMailboxClient({ apiKey: process.env.SENDMUX_API_KEY! });
await sendMailboxMessageWithFiles({
client,
files: ["./report.pdf"],
headers: { "Idempotency-Key": idempotencyKey },
body: {
to: [{ email: "user@example.com", name: null }],
subject: "Report",
text_body: "Attached.",
},
});
const text = await readMailboxTextAttachment({
client,
messageId: "msg_...",
attachmentId: "att_...",
});
Sending API:
import { createSendingClient } from "@sendmux/sending";
import { sendEmailWithFiles } from "@sendmux/sending/node";
const client = createSendingClient({ apiKey: process.env.SENDMUX_API_KEY! });
await sendEmailWithFiles({
client,
files: ["./report.pdf"],
headers: { "Idempotency-Key": idempotencyKey },
body: {
from: { email: "sender@example.com" },
to: { email: "user@example.com" },
subject: "Report",
html_body: "<p>Attached.</p>",
},
});
The combined package also exposes @sendmux/sdk/node.
Mailbox:
from sendmux_mailbox import create_mailbox_client, read_mailbox_text_attachment, send_mailbox_message_with_files
client = create_mailbox_client(api_key=api_key)
send_mailbox_message_with_files(
client,
files=["./report.pdf"],
body={
"to": [{"email": "user@example.com", "name": None}],
"subject": "Report",
"text_body": "Attached.",
},
idempotency_key=idempotency_key,
)
text = read_mailbox_text_attachment(
client,
message_id="msg_...",
attachment_id="att_...",
)
Sending API:
from sendmux_sending import create_sending_client, send_email_with_files
client = create_sending_client(api_key=api_key)
send_email_with_files(
client,
files=["./report.pdf"],
body={
"from": {"email": "sender@example.com"},
"to": {"email": "user@example.com"},
"subject": "Report",
"html_body": "<p>Attached.</p>",
},
idempotency_key=idempotency_key,
)
sendmux-send-email.sendmux-mailbox-agent.sendmux-cli.sendmux-mcp-setup.sendmux-token-efficient-usage.