--- title: Emails and attachments | Lightfield description: Retrieve synced emails, send emails, and work with email attachments. --- Use the Email API to retrieve synced emails and send new emails from connected mailboxes. Use the File API to upload attachments for sends, 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 - The `emails:read` scope to retrieve emails - The `files:create` scope to upload attachments for sends - 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 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. 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 (coming soon) Draft creation is coming soon. ## Upload attachments for sends 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`: ``` { "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. 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` supports the `Idempotency-Key` header. Use the same key when retrying the same send after a timeout. Send 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. | | `400` | `mail_reconnect_required` | Connected account is missing required scopes. Reconnect it. | | `400` | `mail_send_failed` | Mail provider rejected the send. | | `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). ### 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.