Guide
Add Email Sync to Your App Without IMAP
Building email sync usually means a persistent IMAP IDLE connection per mailbox, OAuth refresh, and reconnect handling at scale. This guide shows the pattern that replaces all of it — webhooks for new mail, on-demand reads for backfill — and prototypes the whole thing from the terminal.
Written by Caleb Geene Director, Site Reliability Engineering
Reviewed by Qasim Muhammad
Why is building IMAP sync infrastructure hard?
IMAP sync is hard because real-time delivery needs a persistent IDLE connection held open for every single mailbox. Per RFC 2177, a client must re-issue IDLE at least every 29 minutes or the server can drop it, so 10,000 users means 10,000 long-lived sockets you keep alive, reconnect, and rebalance across processes.
On top of the sockets sit OAuth token refresh per account, XOAUTH2 authentication, per-provider quirks, and reconnect storms when a node restarts and thousands of mailboxes re-handshake at once. This is weeks of infrastructure before you parse a single message — and it's the part that pages you at 3 a.m., not the feature you set out to build.
What replaces IMAP sync?
What replaces it is a push-plus-pull model: a webhook delivers a small notification when new mail arrives, and your app reads the message on-demand only when it needs the content. You hold zero persistent connections. The provider tells you when something changed; you fetch just that, which is how Gmail's and Microsoft Graph's push models work underneath.
This inverts the cost. Instead of paying to keep thousands of idle sockets warm, you pay one cheap webhook per new message plus the reads you actually use. A mailbox that gets 50 messages a day costs 50 notifications, not 24 hours of held connection.
How do I prototype email sync without IMAP?
You prototype the whole pattern from the terminal in two commands. Register a message.created webhook so your endpoint is notified on every new message, then run the built-in receiver to watch payloads land. No server framework, no socket pool — you see the exact push shape your app will handle.
# 1. Push new mail to your endpoint
nylas webhook create \
--url https://your-app.example.com/inbound \
--triggers message.created \
--description "email sync"
# 2. Watch payloads locally while you build the handler
nylas webhook server --port 9000When a notification arrives, fetch the message body on demand. The nylas email read command takes the message ID from the webhook and returns the full content as JSON — the only fetch you make, and only when you need it.
# In your handler: fetch just the message the webhook pointed at
nylas email read "$MESSAGE_ID" --json | jq '{from: .from, subject: .subject}'How do I backfill existing mail?
You backfill history with on-demand search rather than a full sync. The nylas email search command queries the mailbox directly, and the --after date filter scopes the import to a recent window so you don't pull years of mail you don't need. Most apps only need the last 30–90 days at onboarding.
# One-time backfill of the last 30 days at user onboarding
nylas email search "*" --after 2026-05-10 --json > backfill.json
jq 'length' backfill.jsonWhen do I still need IMAP?
You still need IMAP when a mailbox has no modern API — a self-hosted Dovecot server, a legacy host, or a niche provider that exposes only IMAP. In those cases there's no webhook to subscribe to, so a polling or IDLE client is unavoidable. The honest trade-off: the push model needs a provider that supports notifications.
Even then, the CLI connects to generic IMAP accounts through the same command surface, so you get the unified read model without writing the IMAP client yourself. Most teams find the no-IMAP path covers Gmail, Outlook, and the major providers — which is the bulk of real users — and reserve a polling fallback for the long tail.
Next steps
- IMAP IDLE Explained (RFC 2177) — How IMAP IDLE works under RFC 2177
- Email API for SaaS startups — the build-vs-buy decision behind this pattern
- Parse inbound email webhooks — turn the message.created payload into structured data
- Receive inbound email from the terminal — the receive side end to end
- Test email webhooks locally — tunnel events to your machine during development
- Command reference — every flag, subcommand, and example
- RFC 2177 — IMAP IDLE — the spec behind the 29-minute connection-keepalive rule
- Gmail API push notifications — the provider-native push model the webhook path uses