Skip to content
Skip to main content

Send large attachments

Last updated:

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

Send a large attachment with an upload session

Your app uploads a large file to Nylas first, then sends an email that points to it. Upload sessions are in beta, work only for Microsoft grants, and take files from 25 MB up to 150 MB. Finish every step within 1 hour of creating the session. For smaller files on any provider, use multipart form data as shown in Choose how to attach files on the Attachments page.
Diagram as text
  • Exchange admin: Let the mailbox send large messages: Exchange Online tenants only. Exchange Online allows 35 MB per message by default, so an admin raises the limit above your largest file. Settings: MaxSendSize and MaxReceiveSize.
  • Your app: Ask Nylas for a place to upload the file: Your app tells Nylas the file's name, type, and size (up to 150 MB). Nylas returns an ID for the attachment and a private upload address that works for 1 hour.
    • Request details: POST /v3/grants/{grant_id}/attachment-uploads with filename, content_type, and size.
    • Request details: The response has an attachment_id, an upload url with its headers, and expires_at, 1 hour later.
    • Not a Microsoft grant, or no mail permission → Request rejected: The grant must be a Microsoft account with permission to send or edit mail. Returns 401 if the grant lacks Mail.Send, Mail.ReadWrite, or Mail.ReadWrite.Shared.
  • Your app: Upload the file: Your app sends the file straight to the upload address. Don't add your Nylas API key to this request. Request: PUT the file bytes to the returned url with the returned headers, and no Nylas Authorization header. (Status uploading)
  • Your app: Tell Nylas the upload is done: Nylas checks that the whole file arrived and matches the size you declared. Then the attachment is ready to send. Request: POST /v3/grants/{grant_id}/attachment-uploads/{attachment_id}/complete with an empty body. (Upload finished)
    • File missing or wrong size → Upload not accepted: The session stays open (status uploading), so you can upload the file again and retry. Returns 422.
    • More than 1 hour later (past expires_at) → Session expired: The session can't be used any more (status expired). Create a new session. Returns 410.
  • Your app: Send the email with the file attached: Your app sends the email as usual and refers to the uploaded file by its ID, instead of including the file. To show it inline, also give it a content ID and reference it in the body. (Status ready)
    • Request details: POST /v3/grants/{grant_id}/messages/send with { "id": "<attachment_id>" } in attachments.
    • Request details: Inline: add content_id to the attachment and a matching cid: reference in the body.
  • Nylas: Delete the file after 1 hour: Nylas deletes the uploaded file at expires_at. Until then, you can attach the same file to more emails with the same attachment_id.

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.

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.

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.

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.

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.

An upload session moves through one of the following statuses during its lifecycle.

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.

The Create Upload Session response returns the initial state. The Complete Upload Session response returns ready once Nylas has verified the upload.

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 complete endpoint.
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. The session record is kept for observability after the file is deleted.