Skip to content
Skip to main content

Send large attachments

The standard Send Message endpoint accepts attachments as base64-encoded content inside the JSON body, which caps the entire request at 3 MB (or 25 MB using multipart form data). For files larger than that, use the attachment-uploads API to upload the file directly to Nylas-managed storage, then reference it by ID when you send the message. This flow supports attachments up to 150 MB.

Supported providers: Microsoft (Outlook and Exchange Online via Microsoft Graph).

Google, IMAP, Yahoo, iCloud, and EWS grants are rejected with 401 Unauthorized. For these providers, use the standard attachment flow with its 25 MB multipart limit.

You need the following before sending large attachments:

  • A Microsoft grant with at least one of these scopes: Mail.Send, Mail.ReadWrite, or Mail.ReadWrite.Shared. See Create an Azure app for how to configure the auth app.
  • An Exchange Online tenant with message size limits raised to accommodate your largest attachment (see below).

Raise the Exchange Online message size limit

Section titled “Raise the Exchange Online message size limit”

Exchange Online defaults to a 35 MB maximum message size. If your attachment plus message overhead exceeds this, the send fails and recipients on Exchange-based mailboxes do not receive the message.

Raise the limit using Exchange Online PowerShell as an Exchange administrator. Set the value to match your expected maximum attachment size. Changes can take up to 60 minutes to propagate.

Per-mailbox (recommended for a targeted rollout):

Set-Mailbox -Identity "[email protected]" -MaxSendSize 150MB -MaxReceiveSize 150MB

Organization-wide:

Set-TransportConfig -MaxSendSize 150MB -MaxReceiveSize 150MB

Instead of embedding the file in the send request, you:

  1. Create an upload session. Nylas returns a direct-upload URL.
  2. Upload the file bytes. PUT the file directly to the returned URL. No Nylas auth header required.
  3. Complete the session. Nylas verifies the upload and marks the attachment as ready.
  4. Send the email. Reference the attachment_id in the attachments array of your send request.

Make a Create Upload Session request to start the flow.

FieldRequiredNotes
filenameYesName of the file as it appears in the email.
content_typeYesMIME type (for example, application/pdf, image/png). Any non-empty string is accepted.
sizeNoExpected file size in bytes. Recommended. When provided, Nylas verifies the uploaded bytes match this value during completion. Maximum: 157286400 (150 MB).

Save the attachment_id from the response. You need it for steps 3 and 4.

PUT the file bytes to the url returned in step 1. This is a Google Cloud Storage resumable upload URL, so no Nylas authorization header is required on this request.

Set Content-Type to match the value you declared in step 1. A successful upload returns HTTP 200 or 201.

curl -X PUT "{url from step 1}" \
-H "Content-Type: application/pdf" \
-H "Content-Length: 5242880" \
--data-binary @quarterly-report.pdf

Once the file is uploaded, notify Nylas so it can verify the upload and mark the attachment ready to send. See the Complete Upload Session reference.

The request body is empty. Once status is ready, the attachment can be referenced in a send request.

Pass the attachment_id as id inside the attachments array of your Send Message or Create Draft request. Do not include content or content_type. Nylas fetches the file from storage and attaches it at send time.

curl --request POST \
--url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"to": [{ "name": "Jane Smith", "email": "[email protected]" }],
"subject": "Q1 Report",
"body": "Please find the report attached.",
"attachments": [
{ "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
]
}'

If the referenced attachment is not ready at send time (for example, it is still uploading, has failed, or has expired), the send fails. Nylas deletes the draft in both the synchronous and use_draft=true scheduled paths, and the synchronous send returns a 500 to the caller. Verify status with the Get Upload Session endpoint before you send if you aren’t sure the upload completed.

To embed a large image or file inline in the email body, set content_id on the attachment entry and reference it in the HTML body using a cid: URI.

curl --request POST \
--url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"to": [{ "name": "Jane Smith", "email": "[email protected]" }],
"subject": "Q1 Report",
"body": "<p>See chart below:</p><img src=\"cid:chart1\">",
"attachments": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content_id": "chart1"
}
]
}'

Nylas treats the attachment as inline when the content_id value appears as cid:{content_id} inside the message body. If you include a content_id but the body does not reference it, the file is still attached but is displayed as a regular attachment rather than inline. See Working with inline attachments for the full rules.

Use the Get Upload Session endpoint to check the status of an upload at any time.

StatusMeaning
uploadingSession created; Nylas is waiting for the file upload.
readyUpload verified and complete. The attachment can be referenced in a send or draft.
failedUpload initiation failed (for example, Nylas could not create the storage URL during session creation). Create a new session.
expiredSession was not completed within 1 hour. Create a new session.

All error responses follow the standard Nylas error shape:

{
"request_id": "5fa64c92-e840-4357-86b9-2aa364d35b88",
"error": {
"type": "invalid_request",
"message": "file_size exceeds maximum allowed size of 157286400 bytes"
}
}
HTTP statusWhen it occurs
400 Bad Requestfilename or content_type is missing, size is negative or zero, size exceeds 150 MB, or the request body is not valid JSON.
401 UnauthorizedGrant cannot be resolved, the provider is not Microsoft, the grant lacks the required Microsoft scopes, or the grant_id in the path does not match the session on the GET or complete endpoints.
404 Not FoundThe attachment_id does not exist.
409 Conflict/complete was called on a session that is already ready or has failed.
410 Gone/complete was called on an expired session, or the session was already past expires_at.
422 Unprocessable EntityThe file is not in storage, the uploaded size does not match the declared size, or no size was declared and the object is empty.
500 Internal Server ErrorStorage or database failure. Retry the operation.

Rate limiting is not enforced at the attachment-uploads service itself. Any 429 Too Many Requests response is returned by the upstream API gateway. See Sending errors for general troubleshooting.

ParameterLimit
Maximum file size150 MB (157286400 bytes)
Session expiry1 hour from creation
Supported providersMicrosoft (Graph)
Exchange Online default message size35 MB. Raise via PowerShell (see Before you begin).
File retention after readyUntil expires_at (1 hour after creation). Send before the window closes.
Metadata retention60 days. You can call GET /attachment-uploads/{attachment_id} for observability after the file is gone.