---
title: "Live events"
description: "Follow a mailbox as it changes over one open stream, resume where you left off, and wait for a message such as a sign-in code."
url: "https://nextmail.sh/docs/knowledge/developers/live-events"
area: "Knowledge base"
category: "Developers"
---

# Live events

Follow a mailbox as it changes over one open stream, resume where you left off, and wait for a message such as a sign-in code.

## The stream

`GET /live-events` holds the response open as server-sent events and sends one event each time the mailbox changes, so a program stays in sync without polling. It is plain HTTP, so every Nextmail SDK reads it with the client it already has, and a browser can open it with `EventSource`. It needs `threads:read`.

| Event | When |
| --- | --- |
| `message.received` | A message was filed for an address. `labelIds` says where. |
| `message.sent` | A message sent from an address was filed in its Sent folder. `emailId` is the send. |
| `thread.changed` | A conversation gained or lost labels: read or unread, starred, archived, moved, snoozed or labelled, with `addedLabelIds` and `removedLabelIds`. |
| `thread.deleted` | A conversation was deleted for good. Moving it to the bin is a change that adds `TRASH`. |
| `message.status_changed` | An email sent from an address was delivered, delayed, bounced, complained of, failed, suppressed or cancelled, with `status` and the `recipients` it is about. |

Each event is `{ id, type, occurredAt, data }`, and `data` names the `addresses` it concerns, the `threadId` and the `messageId`. No content travels in the stream: read the conversation with `GET /threads/{id}` or the message with `GET /threads/{id}/messages/{messageId}` when you need it. `types` keeps only some kinds of event, comma separated, and `address` only one address.

**Terminal**

```
nextmail live-events stream --types message.received
```

## Resuming and resetting

Every event carries its `id` as the SSE id, a number that only grows. Send the last one you handled back as the `Last-Event-ID` header (or `lastEventId` in the query) and the events you missed are replayed first, then a `ready` event marks the switch to live ones. The SDKs and `EventSource` do this on every reconnect.

- Events can be replayed for 10 minutes and at most 1,000 back. Further back, or with an id the stream never sent, a `reset` event comes first: list again what you keep in sync, then carry on from the stream.
- A comment line keeps the connection open every 25 seconds. When events you filtered out moved the stream on, it carries an `id` too, so a quiet filter never falls behind.
- The server ends every stream after 30 minutes, and when the credential stops being valid, with an `end` event that says why. Open it again with `Last-Event-ID`.

## Who sees what

An API key, the access token of an app somebody connected, or a session can open the stream. A key or an app limited to particular addresses gets only the events of the addresses it reaches, checked on the server for every event, and its stream is checked again at most once a minute while events flow, so a revoked or narrowed key stops receiving within a minute.

> One key, app or session holds at most 5 open streams, and a workspace at most 50. Past that, opening one is refused with `429 too_many_streams`, so filter one stream by type and address rather than opening several.

## Waiting for a message

`GET /threads/wait` holds the request open for up to 60 seconds and answers the first message that arrives and matches: `from` the sender's address or name, `subject` text in the subject, `address` the address it was delivered to, and `since` the moment to look from. It is how a script or an agent waits for a sign-in code it asked a service to send. `message` is null when nothing matched in time, so ask again to keep waiting.

- In the SDKs it is `threads.waitForEmail`, and on the command line `nextmail threads wait-for-email --from service.example --subject code --timeout 60`.
- Over MCP and in the assistant it is the `waitForEmail` tool, read only, beside `readVerificationCode` for reading the code out of the message.
- The wait wakes on the live events of the mailbox and looks again at least every 10 seconds, so a match is answered within moments of arriving.

- [SDK methods](https://nextmail.sh/docs/sdk/reference/live-events.md): The `liveEvents` methods, with reconnects and resuming built in.
- [CLI commands](https://nextmail.sh/docs/cli/reference/live-events.md): The `nextmail live-events` commands, one JSON line per event.
- [MCP tools](https://nextmail.sh/docs/mcp/tools/reading.md): The tools that find and read mail, `waitForEmail` among them.
