---
title: "How to build your own email client on Nextmail"
description: "What you need to build your own email client on Nextmail: OAuth sign-in for your users, typed SDKs in seven languages, live events, webhooks and raw messages."
url: "https://nextmail.sh/blog/build-your-own-email-client"
---

[Blog](https://nextmail.sh/blog.md)[Developers](https://nextmail.sh/blog/tags/developers.md)

# How to build your own email client on Nextmail

What you need to build your own email client on Nextmail: OAuth sign-in for your users, typed SDKs in seven languages, live events, webhooks and raw messages.

Arta Nextmail team

October 31, 2026 6 min read

TL;DR

- Everything the Nextmail app does is also an API call, so a client you build can read, search, send and organise mail the way the app does.
- People sign in to your client with OAuth and PKCE, and they choose the workspace, addresses and permissions it gets.
- Typed SDKs in seven languages, one live event stream and signed webhooks cover the hard parts of a client: sync, push and sending.

Most email products are closed. You get their app, their idea of what an inbox should be, and an export button for the day you leave. Nextmail was built the other way round: every screen in its app is drawn from the same API anyone can call, so the app is one client among many, and yours can be the next.

That makes Nextmail a base for building. Some teams want a client shaped around one kind of work. Some want email inside a product they already run. Some want an agent that handles mail for them. This guide covers what you get to build with, and how the pieces fit.

## What people build on Nextmail

- **A client for one kind of work.** A recruiting inbox that shows each candidate's stage beside the thread, a support desk, or an intake queue for a law firm, each with its own views and shortcuts.
- **Email inside your product.** A CRM, a marketplace or a booking tool that shows the conversation with a customer next to their record and replies from the user's own address.
- **Agents and automations.** Code that reads invoices as they arrive, answers routine questions, or files mail by rules that live in your codebase.
- **A personal client.** Your own keyboard, your own layout, on your own domain.

Teams already build this way. [Website](https://nextmail.sh/customers/website.md) gives every site it makes for a business a working inbox, with the mail in the owner's dashboard and replies in the same thread, and [Ip2Geo](https://nextmail.sh/customers/ip2geo.md) sends its usage alerts and billing email through the API.

## The building blocks

| What a client needs | What Nextmail gives you |
| --- | --- |
| Sign people in | OAuth with PKCE, found at `/.well-known/oauth-authorization-server`, with the person choosing what your app may reach |
| Read and search mail | Threads and messages over REST, paged for you by the SDKs |
| Stay in sync | One live event stream for every change in a mailbox, resumable after a disconnect |
| React on a server | Signed webhooks for received mail, opens and clicks |
| Send and reply | One send call, `threadId` to answer inside a conversation, and an idempotency key so a retry never sends twice |
| Keep the original | Any message as an `.eml` file, byte for byte when the address keeps originals |
| Reach Gmail and Outlook | Connected mailboxes: the same API over a mailbox that stays at Google, Microsoft, Yahoo or iCloud |
| Work with AI | An MCP server that takes the same sign-in and the same limits |

The REST API is described by an OpenAPI 3.1 document that needs no key to read, and the SDKs for TypeScript, Python, Ruby, PHP, Go, Java and C# are held to it by parity checks, so a method does not drift from the endpoint behind it.

## Sign people in with OAuth

A client used by other people should never ask them to paste a key. Nextmail speaks standard OAuth: your app registers itself from the discovery document and signs people in with PKCE, the flow built for apps that cannot keep a secret, such as a desktop or mobile client.

The person stays in charge of what your app gets. The consent screen names your app and the address its token goes to. Then they choose one workspace, a preset (read only, read and send, or everything their role allows) or a set of permissions, all of their addresses or only some, and how long the access lasts. Their own role is the ceiling, and if they narrow or remove your app under Connected apps, the change applies on its next call. The same token works on the REST API and on the MCP server. The details are in [OAuth for third-party clients](https://nextmail.sh/docs/knowledge/developers/oauth.md).

It is worth comparing this with building on a big provider's mailbox. Reading whole Gmail mailboxes, for example, uses scopes Google classes as restricted, which means passing its OAuth verification, plus a security assessment if your servers store or pass on that data.

## Read and page through mail

The [typed SDKs](https://nextmail.sh/docs/knowledge/developers/sdk.md) have one method for every operation the API serves. The TypeScript client has no dependencies and runs on Node 20 and later, Workers, Deno, Bun and the browser. With the token from the OAuth flow, listing a mailbox looks like this:

ts

```
import { Nextmail } from '@nextmail/sdk' const client = new Nextmail({ accessToken }) for await (const thread of client.threads.iterate()) {  const messages = await client.threads.listMessages(thread.id)  console.log(thread.id, messages.at(-1)?.subject)}
```

`iterate()` follows the pages for you, and a script that runs for your own workspace can pass an `apiKey` instead of an `accessToken`. Keys are scoped and revocable, and every call they make is logged.

## Stay in sync with live events

The hardest part of any client is staying current without hammering the server. `GET /live-events` holds one connection open as [server-sent events](https://nextmail.sh/docs/knowledge/developers/live-events.md) and sends an event each time the mailbox changes: a message received or sent, a thread read, starred, archived or labelled, or a delivery status that changed.

ts

```
for await (const event of client.liveEvents.stream({ types: ['message.received'] })) {  const thread = await client.threads.get(event.data.threadId)  showInInbox(thread)}
```

Every event carries an id. After a disconnect the stream picks up from the last one you handled and replays what you missed, and when you have been away too long it tells you to list again rather than leaving a gap. Events carry ids, not content, so your client fetches only what changed.

If your code only needs to wait for one message, such as a sign-in code it asked a service to send, `GET /threads/wait` holds the request open for up to a minute and answers with the first match.

## Send, reply and keep the thread together

Sending is one call. Pass the `threadId` of a conversation and the reply lands in that thread. Pass an idempotency key, and a retry after a timeout never sends the message twice.

ts

```
await client.emails.send(  {    from: 'support@example.com',    to: 'ada@example.org',    subject: 'Re: your order',    html: '<p>It shipped this morning.</p>',    threadId,  },  { idempotencyKey: `reply-${threadId}` },)
```

Every error has a fixed `type` and a more specific `code` to branch on, and every rate-limit answer says in `Retry-After` how long to wait.

## Webhooks for the server side

A client in the browser listens to the live stream. A server listens to [webhooks](https://nextmail.sh/docs/knowledge/developers/webhooks.md): signed POSTs for received mail, opens, clicks and the rest, retried when your endpoint is down and kept as dead letters you can send again. An endpoint can ask for the message content and a link to the original source in every event, and an address can even skip the inbox and [hand its mail straight to your server](https://nextmail.sh/docs/knowledge/developers/webhook-routing.md).

## Keep the original, and reach the mailboxes people already have

Any message can be downloaded as its [source](https://nextmail.sh/docs/knowledge/developers/raw-messages.md), the `.eml` file a mail app shows under Show original. With Keep original on, an address stores every message byte for byte, signatures and `Received` lines included, which matters if your product archives mail or checks it.

Your users do not have to move their mail to use your client. With [connected mailboxes](https://nextmail.sh/docs/knowledge/addresses/connected-mailboxes.md), a Gmail, Outlook, Yahoo or iCloud mailbox stays where it is while your client works it through the same API, and the people on your own domains get mailboxes Nextmail hosts.

## Your brand, and the agents around it

If you would rather not build every screen, you do not have to. A workspace can carry its own logo, fonts and sign-in page, and the Nextmail web app can be served at an address on your own domain, such as `mail.example.com`, so the parts you did not build still look like yours. Mail apps such as Apple Mail and Outlook connect to the same addresses over [IMAP](https://nextmail.sh/blog/what-is-imap.md) and [SMTP](https://nextmail.sh/blog/what-is-smtp.md).

And because the [MCP server](https://nextmail.sh/docs/knowledge/developers/mcp.md) uses the same sign-in and the same limits, an AI agent working beside your client can read, search and draft in the same mailbox, but only within what the person approved.

## Where to start

1. Try a few calls from the [API playground](https://nextmail.sh/docs/knowledge/developers/api-playground.md), which hands you a temporary key scoped to one request.
2. Install the SDK for your language and list a mailbox.
3. Add OAuth when other people will sign in, and the live event stream when the screen has to stay current.

The full API, the SDKs and MCP are on every plan, the free one included, and Nextmail prices the workspace rather than each seat, so a client used by a whole team does not get more expensive as the team grows. If you want the protocol background first, read our guide to [JMAP](https://nextmail.sh/blog/what-is-jmap.md), the open standard for syncing mail as JSON over HTTPS, and our case for treating [email as a mailbox](https://nextmail.sh/blog/email-as-a-mailbox.md) rather than a send pipe.

- [Developers](https://nextmail.sh/blog/tags/developers.md)
- [Email API](https://nextmail.sh/blog/tags/email-api.md)
- [Email clients](https://nextmail.sh/blog/tags/email-clients.md)

## References

1. 1 [RFC 8414: OAuth 2.0 Authorization Server Metadata](https://www.rfc-editor.org/rfc/rfc8414) IETF
2. 2 [RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol](https://www.rfc-editor.org/rfc/rfc7591) IETF
3. 3 [RFC 7636: Proof Key for Code Exchange by OAuth Public Clients](https://www.rfc-editor.org/rfc/rfc7636) IETF
4. 4 [Server-sent events](https://html.spec.whatwg.org/multipage/server-sent-events.html) WHATWG
5. 5 [OpenAPI Specification v3.1.0](https://spec.openapis.org/oas/v3.1.0) OpenAPI Initiative
6. 6 [Choose Gmail API scopes](https://developers.google.com/workspace/gmail/api/auth/scopes) Google

Keep reading

## Related articles

Oct 31, 2026 6 min read

### What is JMAP? The JSON email protocol, explained

JMAP is the IETF standard for email, contacts and calendars over JSON and HTTPS. How it works, how it differs from IMAP, and who supports it in 2026.

Arta Developers

Oct 31, 2026 5 min read

### Email as a mailbox: why AI agents need a real inbox

Most email APIs only send. What a real mailbox adds for apps and AI agents, the four ways to get one in 2026, and how much code each leaves you.

Benjamin AI

Oct 31, 2026 9 min read

### Resend pricing in 2026: what it costs, how to pay less

What Resend costs at 50,000 to 1,000,000 emails a month, with every plan, overage rate and add-on, and what the same mail costs on Nextmail.

Benjamin Comparisons

Try it yourself

## Your email, on your own domain.

Nextmail puts your domains, sending and inbox in one place, with the full API on every plan, the free one included.

[Open mail](https://nextmail.sh/mail/inbox) [Get Started](https://nextmail.sh/signup.md)[All articles](https://nextmail.sh/blog.md)
