Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ description: "New features, improvements, and fixes across the Sendmux platform.
rss: true
---

<Update label="8 July 2026" tags={["Bug fixes", "Improvements"]} rss={{ title: "Attachment uploads keep exact file sizes across tools" }}>
## Sending API

Binary attachment uploads now require the exact `Content-Length` header in the OpenAPI spec, Postman collection, SDKs, CLI, and MCP guidance. Sendmux file helpers calculate it from local files, so agents can upload attachments without placing file bytes in prompts.

</Update>

<Update label="7 July 2026" tags={["Improvements"]} rss={{ title: "Attachments are easier for agents to move and read" }}>
## Sending API

Expand Down
4 changes: 2 additions & 2 deletions guides/attachments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: "Send, upload, and download attachments with Sendmux."
keywords: ["attachments", "file uploads", "file downloads", "base64", "MIME types", "size limits"]
---

For the Sending API, upload file bytes first and send by `attachment_id`. Inline base64 attachments remain supported for small generated content and older integrations, but uploaded refs are the preferred path for normal files.
For the Sending API, upload file bytes first and send by `attachment_id`. Inline base64 attachments remain supported for small generated content and older integrations, but uploaded refs are the preferred path for normal files. Direct and delegated binary uploads require the exact `Content-Length`; Sendmux SDK and CLI file helpers calculate it from the local file.

## Limits

Expand Down Expand Up @@ -66,7 +66,7 @@ curl -X POST https://smtp.sendmux.ai/api/v1/emails/attachment-uploads \
}"
```

The response includes an `upload_url` and required `headers`. Send a `PUT` request to that URL with the exact file bytes and returned headers. The upload token can write only that attachment, expires quickly, and does not grant send access.
The response includes an `upload_url` and required `headers`, including `Content-Type` and exact `Content-Length`. Send a `PUT` request to that URL with the exact file bytes and returned headers. The upload token can write only that attachment, expires quickly, and does not grant send access.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clarify browser handling for Content-Length

Because this delegated-upload section explicitly includes browsers, telling clients to send the returned headers including Content-Length gives browser callers an instruction they cannot follow: Fetch/XHR treats Content-Length as a forbidden request header, so a browser implementation that copies these headers cannot set it directly and may either drop it or fail validation. Please separate browser guidance from shell/agent guidance, e.g. tell browsers to use a Blob/File body and let the user agent supply the length while only setting the allowed returned headers.

Useful? React with 👍 / 👎.


## Agent and MCP workflows

Expand Down
24 changes: 24 additions & 0 deletions openapi-sending.json
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,18 @@
"type": "string"
}
},
{
"description": "Exact number of bytes in the binary request body.",
"example": 20480,
"in": "header",
"name": "Content-Length",
"required": true,
"schema": {
"format": "int64",
"minimum": 1,
"type": "integer"
}
},
{
"description": "Upload intent ID returned by POST /emails/attachment-uploads.",
"in": "path",
Expand Down Expand Up @@ -953,6 +965,18 @@
"type": "string"
}
},
{
"description": "Exact number of bytes in the binary request body.",
"example": 20480,
"in": "header",
"name": "Content-Length",
"required": true,
"schema": {
"format": "int64",
"minimum": 1,
"type": "integer"
}
},
{
"description": "Filename to associate with the uploaded attachment.",
"example": "analysis.pdf",
Expand Down
12 changes: 12 additions & 0 deletions postman/sendmux-sending.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@
"key": "X-Sendmux-Upload-Token",
"value": "<string>"
},
{
"description": "(Required) Exact number of bytes in the binary request body.",
"disabled": false,
"key": "Content-Length",
"value": "<long>"
},
{
"key": "Content-Type",
"value": "application/octet-stream"
Expand Down Expand Up @@ -408,6 +414,12 @@
"key": "Idempotency-Key",
"value": "<string>"
},
{
"description": "(Required) Exact number of bytes in the binary request body.",
"disabled": false,
"key": "Content-Length",
"value": "<long>"
},
{
"key": "Content-Type",
"value": "application/octet-stream"
Expand Down
2 changes: 1 addition & 1 deletion sending-api/introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Single-resource `GET` responses return a weak `ETag`. Send it back in an `If-Non
- **Public IDs only**. Private numeric IDs are never exposed.
- **`Cache-Control: no-store`** on all authenticated responses (the OpenAPI spec endpoint uses `public, max-age=3600`)
- JSON endpoints use `Content-Type: application/json`.
- Binary attachment upload endpoints use `Content-Type` for the file MIME type and send raw bytes with `application/octet-stream` or the file's MIME type.
- Binary attachment upload endpoints use `Content-Type` for the file MIME type and require the exact `Content-Length` for the raw byte body.

## OpenAPI specification

Expand Down