---
title: "List and retrieve"
description: "Find messages, and see what became of one."
url: "https://nextmail.sh/docs/api/emails/list"
area: "API"
category: "Emails"
---

# List and retrieve

Find messages, and see what became of one.

**Also documents:** `GET /emails`, `GET /emails/{id}`, `GET /emails/{id}/events`

## Listing

`GET /emails`, newest first. Filter with `status` (comma-separated), `from`, and `broadcastId`, which keeps the copies of one broadcast, one per person it reached. Pagination is keyset, not offset: pass the `nextCursor` you were given. Offset paging silently skips rows when new messages arrive while you page.

**GET /emails?status=failed&limit=10**

```
{ "object": "list", "data": [ … ], "hasMore": true, "nextCursor": "msg_01j8…" }
```

A row that was tracked also carries a compact `tracking` object: `opens`, `clicks`, `opened`, `clicked`, `openCount`, `clickCount`, `firstOpenAt`. A row that was not carries no `tracking` key at all: `openCount: 0` on a message that never held a pixel reads as "nobody opened it", which is a claim we are in no position to make.

`scheduledFrom` and `scheduledTo`, ISO 8601 instants with a zone, keep the messages scheduled inside a window. With `status=scheduled,queued` that is what is waiting to go out, as the calendar of the app shows it.

A bounce moves a message on after it was sent: it reads `bounced` once every recipient has bounced, so nobody has it, and `partial` when only some did. `status=bounced,partial` finds every message that did not reach everybody, and retrieving one shows which recipient bounced and why.

`since` and `until` keep the messages made inside a window, `recipient` keeps the ones that went to one address as a to, cc or bcc recipient, and `tag` keeps the ones sent with a tag: `plan` for any value, `plan:pro` for one. Tags are stored encrypted and matched through a keyed index, so the match is exact and case-sensitive. Every email webhook carries the `tags` of its send too.

## Retrieving one

`GET /emails/{id}` returns the message with per-recipient delivery state, and the FULL tracking report rather than the list summary, since one retrieve can afford the per-recipient breakdown and the links. An id that does not exist is a `404`, never a fabricated success.

| Recipient status | Means |
| --- | --- |
| pending | Not yet transmitted. |
| delivered | Handed to the transport for this address. |
| failed | The transport refused it. |
| uncertain | A transport failed part-way and cannot say which recipients it reached. Shown as itself rather than guessed either way. |
| bounced | The receiving server refused it after it left. `error` carries the reason. |

## Events

`GET /emails/{id}/events` returns the trail, oldest first: `email.accepted`, `email.queued`, `email.scheduled`, `email.sent`, `email.failed`, `email.cancelled`, `email.rescheduled`, and, on a tracked message, `email.opened`, `email.clicked` and `email.downloaded` as they happen. It pages like every other list, `limit` and `cursor` in and `hasMore` and `nextCursor` out, because a widely read message records an event for every counted open. To be told rather than to poll for them, register a webhook.

## Reference

- [`GET /emails`](https://nextmail.sh/docs/api/reference/emails#get-emails): full reference
- [`GET /emails/{id}`](https://nextmail.sh/docs/api/reference/emails#get-emails-id): full reference
- [`GET /emails/{id}/events`](https://nextmail.sh/docs/api/reference/emails#get-emails-id-events): full reference
