Work with attachments
Download received files for your agent to read, or attach a file to a message you send.
Read as Markdown ↗Download files you receive to read with your own tools, or attach files to mail you send.
Download a received file
Fetch the message and, once it's ready, pick a file from content.attachments and download it by its id.
With MCP, call read_attachment with message_id and attachment_id. It returns the file as base64 chunks: start at offset 0 and continue with the returned next_offset until it's null, decoding each chunk and joining them in order.
With HTTP, set MESSAGE_ID, ATTACHMENT_ID, DOWNLOAD_PATH and CHERAMI_API_KEY (get a credential):
curl --fail --silent --show-error \
"https://cherami.to/v1/messages/$MESSAGE_ID/attachments/$ATTACHMENT_ID" \
-H "Authorization: Bearer $CHERAMI_API_KEY" \
--output "$DOWNLOAD_PATH"If the message failed processing, download the original email and use your own MIME tools.
Need to extract information from invoices, receipts, reports, spreadsheets or presentations? Email hello@cherami.to and we can talk about your workflow.
Download with TypeScript
After SDK setup:
import { writeFile } from "node:fs/promises";
const { data: file } = await client.downloadAttachment({
message_id: messageId,
attachment_id: attachmentId,
});
await writeFile(outputPath, new Uint8Array(await file.arrayBuffer()));data is a standard Response. client.downloadRawMessage({ message_id: messageId }) returns the original email the same way.
Download with Python
After Python SDK setup:
import os
from cherami import Cherami
with Cherami(os.environ["CHERAMI_API_KEY"]) as client:
response = client.download_attachment({
"message_id": message_id, "attachment_id": attachment_id,
}).data
try:
with open(output_path, "wb") as file:
for chunk in response.iter_bytes():
file.write(chunk)
finally:
response.close()With an async client, await client.download_attachment, read with async for over response.aiter_bytes() and close with await response.aclose(). download_raw_message returns the original email the same way.
Attach a file to a send
Add an attachments array to your send request, with each file's name, MIME type and base64-encoded bytes (padded, with no whitespace). This attaches a text file containing Hello:
{
"attachments": [
{"filename": "notes.txt", "type": "text/plain", "content": "SGVsbG8="}
]
}A message, attachments included, can be up to 5 MiB after base64 encoding, which adds about a third, so about 3.5 MiB of files fit. A larger message is refused with 413 message_too_large.
With TypeScript, attachment encodes the bytes for you; it also accepts an ArrayBuffer or Blob:
import { readFile } from "node:fs/promises";
import { attachment } from "@cherami/sdk";
const file = await attachment("notes.pdf", await readFile(localPath), "application/pdf");
// Use attachments: [file] in the body passed to prepareSend.With Python, attachment accepts bytes, bytearray or memoryview:
from pathlib import Path
from cherami import attachment
file = attachment("notes.pdf", Path(local_path).read_bytes(), "application/pdf")
# Use "attachments": [file] in the body passed to prepare_send.To pass on a file you received, forward the message instead: a forward includes the original attachments.
Retrieve sent attachments
GET /v1/sent/MESSAGE_ID returns each file's base64 content in submission.attachments; with MCP, call get_sent_message with format: "full". Conversation detail lists attachments without their bytes.
To decode a file from a sent message or draft, use attachmentBytes(savedAttachment) from @cherami/sdk, which returns a Uint8Array, or attachment_bytes(saved_attachment) from cherami, which returns bytes.