# list_site_email_sends

Source: https://modulify.ai/docs/api/emails/list-site-email-sends

Lists the emails a site has sent, 30 to a page, with each one's recipients, status, source and opens and clicks.

- Title: List the emails a site sent
- Scope: `config:read`
- Access: Read only
- Endpoint: `POST /v1/list_site_email_sends`

The answer carries `items` and `nextCursor`. Pass `nextCursor` back as `cursor` for the next page, with the same filters and sort, and it is null once there is nothing more. Rows are kept until the history is cleared.

Each item carries its `id`, the `subject`, `to`, `cc`, `bcc` and `replyTo`, the address it was sent from (`from`), how many recipients it went to (`recipientCount`), its `tags` and `attachmentCount`, its timestamps and its `status`. `source` says where it was sent from: `site` for the site's own code, `dashboard`, `chat`, `mcp` for an MCP client, or `api` for the API. `test` says whether it was a test, which is free and counts for no sends.

The status is `pending` while the message is still on its way, `sent` once the provider took it, `delayed` while delivery is being retried, `delivered` once every receiving server accepted it, `partial` when some recipients got it and some did not, `bounced` when an address refused it, `complained` when somebody marked it as spam, and `rejected` or `failed` when it never went out, with the reason in `error`.

`tracked` says whether the message went out with open and click tracking on. A tracked message carries `opens` and `clicks`, every open and every link click on the whole message, with `firstOpenedAt` and `firstClickedAt`. They are never per recipient, opens are approximate because some mail apps load images automatically and others block them, and neither ever changes the status.

It answers whether an email went out and why somebody did not get it, and `get_site_email` reads one message with every recipient's own status, the delivery events and the body. The site sends its own mail from its own code, which posts the message to the `EMAIL_URL` endpoint with its `EMAIL_PRIVATE_KEY` key, and `send_site_email` sends one message for you when you explicitly ask for it. See [The history](https://modulify.ai/docs/automations/emails#the-history).

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/list_site_email_sends`, sending the inputs below as a JSON object. The token needs the `config:read` scope.

It only reads and changes nothing, so retrying it is safe.

```bash
curl -X POST https://api.modulify.ai/v1/list_site_email_sends \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID"}'
```

Over MCP, the same method is the [list_site_email_sends tool](https://modulify.ai/docs/mcp/emails/list-site-email-sends).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id. |
| `filter` | string | No | Which messages to keep: `all`, `delivered` for the ones every inbox accepted, `pending` for the ones still on their way, or `failed` for everything that did not fully arrive, meaning partly delivered, bounced, marked as spam, rejected or never left. Defaults to `all`. |
| `status` | string | No | Keeps only the messages with exactly this status: `pending`, `sent`, `delayed`, `delivered`, `partial`, `bounced`, `complained`, `rejected` or `failed`. It takes precedence over `filter`. |
| `recipient` | string | No | Keeps only the messages sent to an address containing this text, whether it was in `to`, `cc` or `bcc`. A full address matches exactly, and part of one matches every address containing it. |
| `engagement` | string | No | Keeps only messages sent with open and click tracking on: `opened` for the ones opened at least once, `clicked` for the ones with at least one link click, or `not-opened` for the ones delivered and never opened, even if a spam report or bounce came later. It combines with `filter`, `status` and `recipient`. Defaults to `all`, which keeps every message. |
| `sort` | string | No | `newest` first, the default, or `oldest` to walk the history forwards from the beginning. |
| `cursor` | string | No | The `nextCursor` from the previous page, sent with the same `filter`, `status`, `recipient`, `engagement` and `sort`. Leave it out for the first page. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.