--- title: Emails and attachments | Lightfield description: Retrieve synced emails, send emails, create drafts, and work with email attachments. --- Use the Email API to retrieve synced emails, send new emails, and create drafts from connected mailboxes. Use the File API to upload attachments for sends and drafts, or to download attachments from synced emails. ## Before you begin You will need: - A valid [API key](/using-the-api/api-keys/index.md) - The `emails:create` scope to send emails or create drafts - The `emails:read` scope to retrieve emails - The `files:create` scope to upload attachments for sends or drafts - The `files:read` scope to download synced email attachments - A user-backed API key, or a workspace key whose creator resolves to a user - A connected Google or Microsoft mail account for the `from` address Send and draft requests use these headers: ``` Authorization: Bearer YOUR_API_KEY Lightfield-Version: 2026-03-01 Content-Type: application/json ``` The `from` value must be a bare email address for a connected mail account owned by the API key user. Direct sends and drafts create new messages only; replies and forwards are not supported yet. ## Retrieve an email by ID Use [`GET /v1/emails/{id}`](/api/resources/email/methods/retrieve/index.md) to fetch a synced email. The response includes the body when the caller has full access. Terminal window ``` curl https://api.lightfield.app/v1/emails/$EMAIL_ID \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" ``` A successful response looks like: ``` { "id": "eml_abc123", "objectType": "email", "createdAt": "2026-05-01T16:00:00.000Z", "updatedAt": "2026-05-01T16:10:00.000Z", "httpLink": null, "fields": { "$subject": { "valueType": "TEXT", "value": "Re: Renewal next steps" }, "$from": { "valueType": "EMAIL", "value": ["alex@customer.com"] }, "$to": { "valueType": "EMAIL", "value": ["sam@example.com"] }, "$cc": { "valueType": "EMAIL", "value": [] }, "$bcc": { "valueType": "EMAIL", "value": [] }, "$privacySetting": { "valueType": "TEXT", "value": null }, "$body": { "valueType": "HTML", "value": "
Thanks for the recap...
" } }, "relationships": { "$attachment": { "cardinality": "HAS_MANY", "objectType": "file", "values": ["fil_def456"] } }, "accessLevel": "FULL" } ``` Email retrieval is privacy-filtered. With metadata-only access, sensitive fields such as `$subject` and `$body` are `null`, `relationships.$attachment` is omitted, and `accessLevel` is `METADATA`. ## List emails Use [`GET /v1/emails`](/api/resources/email/methods/list/index.md) to fetch a paginated list of emails. Only emails the caller has full access to are returned; rows omit `fields.$body` — use `GET /v1/emails/{id}` for the message body. See [List methods](/using-the-api/list-endpoints/index.md) for shared pagination and filtering parameters. Terminal window ``` curl https://api.lightfield.app/v1/emails \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" ``` ## Send an email directly Use [`POST /v1/emails/send`](/api/resources/email/methods/send/index.md) to send a new email from the connected mailbox for `from`. Terminal window ``` curl https://api.lightfield.app/v1/emails/send \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: send-renewal-123" \ -d '{ "from": "sam@example.com", "to": ["alex@customer.com"], "subject": "Renewal next steps", "messageBody": { "contentType": "TEXT", "content": "Hi Alex, here are the next steps..." } }' ``` A successful response returns when the provider accepts the send: ``` { "sentAt": "2026-05-01T16:06:00.000Z" } ``` ### Request fields | Field | Send | Notes | | ------------------------- | -------- | ------------------------------------------------------- | | `from` | required | Bare email address for the connected sender mailbox. | | `to` | required | Array of bare recipient email addresses. | | `cc` | optional | Array of bare recipient email addresses. | | `bcc` | optional | Array of bare recipient email addresses. | | `subject` | required | Send subjects must be non-empty. | | `messageBody.contentType` | optional | `HTML` or `TEXT`. Defaults to `HTML`. | | `messageBody.content` | required | Send body content must be non-empty. | | `attachments` | optional | Array of completed File API IDs. Maximum 5 attachments. | Each recipient list may contain up to 500 addresses, and the combined total across `to`, `cc`, and `bcc` may not exceed 500. ## Create a draft directly Use [`POST /v1/emails/draft`](/api/resources/email/methods/draft/index.md) to create a draft in the connected mailbox for `from`. Draft requests use the same shape as [`POST /v1/emails/send`](/api/resources/email/methods/send/index.md): `from`, `to`, `cc`, `bcc`, `subject`, `messageBody`, and `attachments`. Only `from` is required. Drafts must include at least one of `to`, `cc`, `bcc`, `subject`, `messageBody.content`, or `attachments`; creating a draft with only `from` returns `400`. Recipient and attachment limits match sends. Terminal window ``` curl https://api.lightfield.app/v1/emails/draft \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: draft-renewal-123" \ -d '{ "from": "sam@example.com", "to": ["alex@customer.com"], "subject": "Renewal next steps", "messageBody": { "contentType": "TEXT", "content": "Hi Alex, here are the next steps..." } }' ``` A successful response returns when the provider creates the draft: ``` { "draftedAt": "2026-05-01T16:06:00.000Z" } ``` ## Upload attachments for sends and drafts Attachments are completed file IDs from the [file upload lifecycle](/using-the-api/file-uploads/index.md). For email attachments, use `purpose: "email_attachment"` when creating the upload session. Terminal window ``` curl https://api.lightfield.app/v1/files \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" \ -H "Content-Type: application/json" \ -d '{ "purpose": "email_attachment", "filename": "renewal-summary.pdf", "mimeType": "application/pdf", "sizeBytes": 240000 }' ``` After uploading and completing the file, pass the file ID in `attachments` on a send or draft request: ``` { "from": "sam@example.com", "to": ["alex@customer.com"], "subject": "Renewal summary", "messageBody": { "content": "Attached is the summary.
" }, "attachments": ["fil_abc123"] } ``` Limits: maximum 5 attachments, 3 MB per attachment, and 15 MB total per send or draft. Attachment IDs must be completed File API uploads in the same workspace. ## Download attachments from synced emails Synced emails return attachment file IDs in `relationships.$attachment` on `GET /v1/emails/{id}`. Each value is a completed file ID (`fil_...`) pointing at a Document in the File API. Read the attachment IDs from the email response, then request a temporary download URL for each file: Terminal window ``` curl https://api.lightfield.app/v1/emails/$EMAIL_ID \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" ``` Use `GET /v1/files/{id}/url` with one of the IDs from `relationships.$attachment.values`: Terminal window ``` curl https://api.lightfield.app/v1/files/$FILE_ID/url \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Lightfield-Version: 2026-03-01" ``` A successful response looks like: ``` { "url": "https://...", "expiresAt": "2026-05-01T17:00:00.000Z" } ``` For synced email attachments, Lightfield fetches the bytes from the remote email provider on first download, caches them, and returns a signed URL. If the mailbox that synced the attachment is disconnected or needs reconnecting, the download returns `400` with code `mail_attachment_mailbox_disconnected` until the mailbox owner reconnects it in Lightfield. ## Idempotency `POST /v1/emails/send` and `POST /v1/emails/draft` support the `Idempotency-Key` header. Use the same key when retrying the same send or draft creation after a timeout. Mail operations call a remote email provider, and those providers do not natively support Lightfield idempotency keys. Lightfield applies the key on a best-effort basis before and after the remote call. See [Idempotency](/using-the-api/idempotency/index.md) for general retry behavior and conflict handling. ## Common errors Returned by any `/v1/emails` endpoint. `400` responses include a `code` field; `403`, `404`, `429`, and `503` use the standard envelope without one. | Status | Code | Meaning | | ------ | -------------------------------------- | --------------------------------------------------------------------------------------------------------- | | `400` | `mail_no_connected_account` | `from` is not a connected mail account that can send or create drafts. | | `400` | `mail_reconnect_required` | Connected account is missing required scopes. Reconnect it. | | `400` | `mail_send_failed` | Mail provider rejected the send or draft creation. | | `400` | `mail_attachment_not_found` | Attachment ID is missing, duplicated, or not an eligible upload. | | `400` | `mail_attachment_empty` | Attachment file is 0 bytes. Re-upload via the Files API and verify the upload completed before attaching. | | `400` | `mail_attachment_mailbox_disconnected` | Source mailbox is disconnected. Owner must reconnect. | | `400` | `mail_attachment_provider_unavailable` | Provider could not fetch the attachment. Retry later. | | `400` | `file_too_large` | Attachment exceeds 3 MB per file or 15 MB total. | | `400` | `invalid_configuration` | Attachment downloads unsupported for this workspace or provider. | | `403` | n/a | User actor required, or provider denied attachment access. | | `404` | n/a | Synced attachment not found or not accessible. | | `429` | n/a | Provider rate-limited the request. Retry later. | | `503` | n/a | Provider temporarily unavailable. | See [Errors](/using-the-api/errors/index.md) for the standard error envelope. ## End-to-end flow ### Send an email 1. If attaching files, upload and complete them via the Files API (use `purpose: "email_attachment"` to apply the 3 MB per-file cap at upload time). 2. `POST /v1/emails/send` with required `from`, `to`, `subject`, `messageBody`, and optional `cc`, `bcc`, `attachments`. 3. If the request fails or times out, retry with the same `Idempotency-Key` to avoid duplicates. See [Idempotency](/using-the-api/idempotency/index.md). ### Create a draft 1. If attaching files, upload and complete them via the Files API (use `purpose: "email_attachment"` to apply the 3 MB per-file cap at upload time). 2. `POST /v1/emails/draft` with required `from` and at least one draft field: `to`, `cc`, `bcc`, `subject`, `messageBody.content`, or `attachments`. 3. If the request fails or times out, retry with the same `Idempotency-Key` to avoid duplicate drafts. See [Idempotency](/using-the-api/idempotency/index.md). ### Download a synced attachment 1. `GET /v1/emails/{id}` and read `relationships.$attachment.values`. 2. `GET /v1/files/{id}/url` for each attachment file ID. ## Next steps - **[File uploads](/using-the-api/file-uploads/index.md)** - Upload files that can be used as email attachments. - **[Scopes](/using-the-api/scopes/index.md)** - Learn which scopes to grant to your API key. - **[API Reference](/api/index.md)** - Full endpoint reference for email and other resources.