Skip to main content
import { readFile } from "node:fs/promises";
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

// This file is under chunk_bytes: one chunk, number 0.
const bytes = await readFile("order-10473.pdf");
const result = await client.drafts.attachments.putChunk(
  "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "dfa_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  0,
  bytes,
);
console.log(result);
{
  "id": "dfa_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "filename": "<filename>",
  "content_type": "<content_type>",
  "size": 0,
  "status": "uploading",
  "chunk_bytes": 0,
  "chunk_count": 0,
  "from_message_id": "<from_message_id>",
  "created_at": "2026-10-04T12:00:00.000Z",
  "storage": { "used_bytes": 0, "limit_bytes": 0 }
}

Upload a chunk of a draft's file

One chunk of the file, as the raw request body.
PUT/v1/drafts/{id}/attachments/{attachment_id}/chunks/{index}scope · manage or draft
import { readFile } from "node:fs/promises";
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

// This file is under chunk_bytes: one chunk, number 0.
const bytes = await readFile("order-10473.pdf");
const result = await client.drafts.attachments.putChunk(
  "dft_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "dfa_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  0,
  bytes,
);
console.log(result);
{
  "id": "dfa_01JZX8K3M9Q4P7VN2YB6RTDC0E",
  "filename": "<filename>",
  "content_type": "<content_type>",
  "size": 0,
  "status": "uploading",
  "chunk_bytes": 0,
  "chunk_count": 0,
  "from_message_id": "<from_message_id>",
  "created_at": "2026-10-04T12:00:00.000Z",
  "storage": { "used_bytes": 0, "limit_bytes": 0 }
}

Path Parameters

idstringrequired

Draft id.

attachment_idstringrequired

File id (dfa_…).

indexstringrequired

The chunk's number, from 0.

Every chunk is chunk_bytes long except the last, which is what is left of size; any other length is a 400. Until the file is finished, sending a chunk again replaces it, so a dropped connection can simply be retried; a chunk sent to a finished file is a 409 and changes nothing. The file turns ready when the last chunk arrives, in any order. A plan that has fallen below what the workspace's drafts hold refuses the chunk (402 resource_cap_exceeded).

Response

idstring

File id (dfa_…).

filenamestring

The file's name, as the recipient sees it.

content_typestring

The file's MIME type.

sizeinteger

The file's size in bytes.

statusstring

uploading: some chunks have not arrived, and the draft cannot be sent or scheduled. ready: every chunk is in.

One of: uploading, ready

chunk_bytesinteger

How long each chunk is, except the last, in bytes: 3 MiB.

chunk_countinteger

How many chunks the file is sent in, numbered from 0. 0 on a forward's file, which is read from the email.

from_message_idstring

On a forward's file: the received message it is read from when the draft is sent. Absent on a file that was uploaded.

created_atstring

When the file was added.

storageobject

On the answer to adding a file: how much room the workspace's drafts have left for files. Absent otherwise.

Show propertiesHide properties
used_bytesinteger

What the workspace's drafts hold of files, in bytes, this one included. A forward's own files are read from the email and do not count.

limit_bytesinteger

What the plan lets them hold, in bytes: 200 MB on Free, 2 GB on Pro, 10 GB on Scale.

Was this page helpful?