---
title: "$client->liveEvents"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://nextmail.sh/docs/php/reference/live-events"
area: "PHP"
category: "Reference"
---

# $client->liveEvents

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

Follow the mailbox as it changes, without polling: one event each time a message arrives or is sent, each time a conversation changes or is deleted, and each time the delivery of a sent email moves on, resumed where it left off after a dropped connection.

### `liveEvents->stream`

Follow the mailbox as it changes

```php
stream(
    array|string|null $types = null,
    ?string $address = null,
    ?string $lastEventId = null,
    ?string $apiKey = null,
): Generator
```

Returns a `Generator` that opens the live event stream, `GET /live-events` as server-sent events, and yields one event per step for as long as you read it: `message.received` when a message is filed for an address, `message.sent` when a message sent from an address is filed in its Sent folder, `thread.changed` when a conversation gains or loses labels (read, starred, archived, moved, snoozed or labelled), `thread.deleted` when one is deleted for good, and `message.status_changed` when the delivery of an email sent from an address moves on, with its `status`: `delivered`, `delivery_delayed`, `bounced`, `complained`, `failed`, `suppressed` or `cancelled`. Each event is an array with `id`, `type`, `occurredAt` and `data`, where `data['addresses']` names the addresses it concerns and `threadId` and `messageId` the conversation and the message, where there is one. No content travels in an event, so read the conversation with `threads->get` or the message with `threads->getMessage` when you need it. `Nextmail\Constants\LiveEventTypes` and `Nextmail\Constants\LiveSendStatuses` name the types and the statuses.

Nothing is sent until the loop starts, and the loop never ends by itself. The server closes the stream after 30 minutes, when the credential stops being valid, or when the connection drops, and the generator opens it again and resumes where it left off through `Last-Event-ID`: at once after the server closes it, though never sooner than the server's `retry` hint after the previous attempt began, and with backoff after a failure. When the server can no longer replay from that point, which happens once the event is more than 10 minutes or 1,000 events back, the generator yields an event whose `type` is `reset` before the next events: anything may have changed in between, so list again what you keep in sync. Break out of the loop to close the connection.

The built-in cURL client hands each event over as soon as it arrives. A client you pass as `httpClient:` has to implement `Nextmail\Http\StreamingHttpClient` to stream. `Psr18HttpClient` does not, so with it the first step of the loop throws an `InvalidArgumentException`.

A key or an app limited to particular addresses gets only the events of the addresses it reaches, enforced on the server for every event.

Scopes: `threads:read`.

**Parameters**

- `types` (`string|string[]`): Only these kinds of event, as `Nextmail\Constants\LiveEventTypes` values: `message.received`, `message.sent`, `thread.changed`, `thread.deleted` and `message.status_changed`. An array is sent comma separated. Left out, all of them. A reset always comes.
- `address` (`string`): Only the events of this address. One the key does not reach delivers nothing rather than failing.
- `lastEventId` (`string`): Resume after this event id, the `id` of the last event an earlier stream yielded, sent as the `Last-Event-ID` header. Left out, the stream starts with what happens from now on.
- `apiKey` (`string`): Overrides the client's API key for this stream, on every reconnection too.

**Returns**

A `Generator` that yields one array per event, with `id`, `type`, `occurredAt` and `data`. `data` always holds `addresses`, `threadId` and `messageId`, and by type `labelIds` (received), `emailId` (sent), `addedLabelIds` and `removedLabelIds` (changed), or `emailId`, `status` and `recipients` (status changed, where `threadId` may be null). A reset yields `id`, `type` set to `reset`, `occurredAt` and `data` with `reason`, `expired` or `unknown` as in `Nextmail\Constants\LiveResetReasons`.

**Example**

```php
use Nextmail\Constants\LiveEventTypes;

$resumeFrom = null;

foreach ($client->liveEvents->stream(types: [LiveEventTypes::MESSAGE_RECEIVED], address: 'support@example.com') as $event) {
    if ($event['type'] === 'reset') {
        echo 'Some events were missed, so list the inbox again', PHP_EOL;

        continue;
    }

    $resumeFrom = $event['id'];
    $thread = $client->threads->get($event['data']['threadId']);

    echo 'New mail in ', $thread['id'], PHP_EOL;

    break;
}

echo 'Carry on later with lastEventId: ', $resumeFrom, PHP_EOL;
```

**Notes**

- One key, app or session holds at most 5 open streams, and a workspace at most 50. Past that the stream is refused with 429 `too_many_streams`, which the generator waits out like any 429.
- The server sends a keepalive every 25 seconds and a `retry` hint of 3 seconds. Events are kept for resuming for 10 minutes and at most 1,000 per workspace.
- A network failure, a 408, a 429 and a 5xx answer are retried for as long as you read, waiting about a second at first and doubling up to 30 seconds, or longer when `Retry-After` asks, up to 5 minutes. The client's `maxRetries:` does not apply. When no byte arrives for 60 seconds, the generator drops the connection and opens it again.
- Any other error, such as a 400, 401, 403, 404 or 422, throws its `ApiException` instead of retrying, so an expired or revoked credential ends the loop the next time the stream opens. So does a 200 that is not `text/event-stream`, with the code `unrecognised_response`.
- The client's `timeout:` covers only the wait for the stream to open. Once it is open, only the 60 second limit on silence applies.

Also available in: API [`GET /live-events`](https://nextmail.sh/docs/api/reference/live-events#get-live-events); TypeScript [`liveEvents.stream()`](https://nextmail.sh/docs/sdk/reference/live-events#stream); Python [`live_events.stream()`](https://nextmail.sh/docs/python/reference/live-events#stream); Ruby [`live_events.stream`](https://nextmail.sh/docs/ruby/reference/live-events#stream); Go [`LiveEvents.Stream`](https://nextmail.sh/docs/go/reference/live-events#stream); Java [`liveEvents().stream`](https://nextmail.sh/docs/java/reference/live-events#stream); C# [`LiveEvents.StreamAsync`](https://nextmail.sh/docs/csharp/reference/live-events#stream); CLI [`nextmail live-events stream`](https://nextmail.sh/docs/cli/reference/live-events#live-events-stream).
