# Bulk mark-read, delete, apply or remove a label

Source: https://docs.maylee.app/api-reference/emails/bulk-update-emails

`POST https://api.maylee.app/api/v1/emails/bulk`

Scope: `write`.

Counts against the quota once per email processed, not once per request. Supports `Idempotency-Key`.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | A unique value per operation, such as a UUID. Replays the stored response for 24h. Reusing a key with a different body returns 409. 0 to 255 characters. |

## Request body

`application/json`, required.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `action` | string | yes | One of: `markRead`, `delete`, `applyLabel`, `removeLabel`. |
| `emailIds` | array of string | yes | At most 500 items. |
| `isRead` | boolean | no | Required when action is `markRead`. |
| `labelId` | string | no | Required when action is `applyLabel` or `removeLabel`. |

## Example request

```bash
curl -X POST "https://api.maylee.app/api/v1/emails/bulk" \
  -H "Authorization: Bearer $MAYLEE_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "markRead",
  "emailIds": [
    "cmemx1a2b3c4d5e6f7g8h9i0"
  ],
  "isRead": true
}'
```

## Responses

### 200

Per-id outcome, shaped by the action. Partial failures do not fail the batch.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `skippedIds` | array of string | yes | Unknown ids, or ids of another workspace. Never an error. |
| `unchangedIds` | array of string | yes | Already in the requested state. |
| `updatedIds` | array of string | yes |  |
| `isRead` | boolean | no |  |
| `deletedIds` | array of string | yes |  |
| `noTrashIds` | array of string | yes | In a mailbox without a trash folder: not moved. |
| `skippedIds` | array of string | yes | Unknown, of another workspace, already deleted or already in the trash. |
| `emailIds` | array of string | yes | Ids of the workspace that were processed, deduplicated. |
| `labelId` | string | yes |  |
| `skippedIds` | array of string | yes | Unknown ids, or ids of another workspace. Never an error. |
| `updatedCount` | integer | yes | Labels actually added or removed. An email that already had (or did not have) the label is not counted. |

```json
{
  "isRead": true,
  "skippedIds": [],
  "unchangedIds": [],
  "updatedIds": [
    "cmemx1a2b3c4d5e6f7g8h9i0"
  ]
}
```

### 400

Empty array, more than 500 ids, unknown action, or a missing `isRead` / `labelId`.

### 401

Missing, malformed, revoked or expired API key.

### 403

Key lacks the required scope, or outbound sending is not enabled on it.

### 404

`LABEL_NOT_FOUND`: the label is unknown or belongs to another workspace.

### 409

Idempotency key reused with a different body, or original call still in flight.

### 429

Per-minute rate limit (`RATE_LIMIT_EXCEEDED`) or monthly quota (`QUOTA_EXCEEDED`) exhausted.

Errors use the format `{ "code", "error", "details" }`: see [Errors](/errors.md).
