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 and each time a conversation changes or is deleted, resumed where it left off after a dropped connection.
LiveEvents.StreamAsync
Follow the mailbox as it changes
IAsyncEnumerable<JsonObject> StreamAsync( IEnumerable<string>? types = null, string? address = null, string? lastEventId = null, string? apiKey = null, CancellationToken cancellationToken = default)Opens the live event stream, GET /live-events as server-sent events, and yields one event at a time 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, as in Nextmail.Constants.LiveEventTypes and LiveSendStatuses. Each event is a JsonObject with id, type, occurredAt and data, and data holds addresses, the addresses it concerns, with threadId and messageId, the conversation and the message where there is one. No content travels in an event, so read the conversation with Threads.GetAsync or the message with Threads.GetMessageAsync when you need it.
The stream never ends by itself. The server closes it after 30 minutes, when the credential stops being valid, or when the connection drops, and StreamAsync opens it again and resumes where it left off through Last-Event-ID: at once after the server closes it, 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, it yields an event whose type is reset before the next ones: anything may have changed in between, so list again what you keep in sync. Break out of the await foreach loop to close the stream, or cancel cancellationToken, which closes it and throws OperationCanceledException.
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.
Parameters
typesIEnumerable<string>?Only these kinds of event, such as
LiveEventTypes.MessageReceived:message.received,message.sent,thread.changed,thread.deletedandmessage.status_changed. Left out or empty, all of them. Aresetalways comes.addressstring?Only the events of this address. One the key does not reach delivers nothing rather than failing.
lastEventIdstring?Resume after this event id, the
idof an event an earlier stream yielded. It goes out as theLast-Event-IDheader. Left out, the stream starts with what happens from now on.apiKeystring?Overrides the client's API key for this stream, on every reconnect too.
cancellationTokenCancellationTokenCloses the stream. The loop then throws
OperationCanceledException, also while it waits to reconnect.
Returns
An IAsyncEnumerable<JsonObject> that yields one object per event, each with id, type, occurredAt and data. data 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 event has the id to resume from as its id, type set to reset, the moment the client read it as occurredAt, and reason in data: expired or unknown, as in LiveResetReasons.
Example
using Nextmail.Constants; await foreach (var change in client.LiveEvents.StreamAsync(types: new[] { LiveEventTypes.MessageReceived })){ if ((string?)change["type"] == "reset") { Console.WriteLine("Resync: the stream could not resume"); continue; } var thread = await client.Threads.GetAsync(change["data"]!["threadId"]!.GetValue<string>()); Console.WriteLine($"{thread["id"]} arrived for {change["data"]!["addresses"]![0]}"); break;}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, andStreamAsynckeeps trying.The server sends a keepalive every 25 seconds and a
retryhint 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-Afterasks, up to 5 minutes. When no byte arrives for 60 seconds,StreamAsyncdrops the connection and opens it again.MaxRetriesdoes not apply to the stream.A 400, 401, 403, 404 or 422 throws the
NextmailApiExceptioninstead of retrying, so an expired or revoked credential ends the stream on the next attempt to open it. A 200 that is not an event stream throws it too, withCodeset tounrecognised_response.The client's
Timeoutbounds only the wait for the response headers, so it never cuts an open stream short.
Google Workspace