A support ticket lands in a shared inbox. A vendor sends an invoice. A customer replies to confirm an order. In each case you want code to run the moment the message arrives, not the next time someone checks the inbox. Polling for new mail every minute wastes requests and adds latency, and it scales badly once you watch dozens of accounts at once.
This guide builds an inbound email automation with the Nylas Email API: a webhook fires when a message arrives, your handler fetches the full message, extracts what it needs, and triggers an action. The same pattern works across Google, Microsoft, iCloud, Yahoo, and IMAP through one code path.
How do I create a system that automatically parses email and triggers actions?
Section titled “How do I create a system that automatically parses email and triggers actions?”You subscribe to the message.created webhook trigger, receive a small notification when any connected inbox gets new mail, fetch the full message through GET /v3/grants/{grant_id}/messages/{message_id}, then run your parsing and action logic. This event-driven flow replaces polling, so your code reacts within seconds across every provider behind a single grant.
The architecture has three moving parts. First, a webhook destination registered with the API tells it where to send notifications. Second, your HTTPS endpoint receives each message.created payload, which carries the grant_id and message_id but not always the full body. Third, a fetch-and-extract step pulls the complete message and feeds it to your business logic. Notification payloads cap at 1 MB; anything larger gets truncated with a .truncated suffix, which is the main reason you fetch the message by ID rather than trusting the webhook to carry everything.
How can I trigger actions from incoming email with AI?
Section titled “How can I trigger actions from incoming email with AI?”Route each inbound message through a parsing step before you act: fetch the body, send the subject and body to a model or rules engine, and branch on the extracted fields. The webhook supplies the trigger and message ID, the fetch supplies the content, and your extraction layer turns unstructured email into structured data your action can use.
The extraction loop sits between the webhook and the action. A model reads the message and returns fields like intent, order number, or sentiment, and your code routes on those values: create a ticket, update a CRM record, or send a reply. The dedicated extract structured data from email guide covers prompt design and JSON output for this step. Keep the AI call idempotent: providers occasionally redeliver a notification, so dedupe on message_id before you spend a token or fire a side effect. A short-lived cache keyed by message ID, expiring after roughly 24 hours, prevents double-processing without unbounded growth.
Register a webhook for the message.created trigger
Section titled “Register a webhook for the message.created trigger”The POST /v3/webhooks endpoint creates a webhook destination. You pass the trigger_types you want, a public webhook_url, and optional notification_email_addresses that get alerted if the destination starts failing. For inbound automation, message.created is the trigger that fires on every newly synced message. Keep destinations few: a retry fans out to every destination registered for a trigger type.
curl --request POST \ --url 'https://api.us.nylas.com/v3/webhooks' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data-raw '{ "trigger_types": ["message.created"], "webhook_url": "https://example.com/webhooks/nylas", "description": "Inbound email automation", "notification_email_addresses": ["[email protected]"] }'When you create the destination, the API responds with a webhook_secret. Store it: every notification arrives with an x-nylas-signature header, an HMAC-SHA256 of the raw request body keyed with that secret. Verify it on every request and reject mismatches before parsing. For the full registration and verification walkthrough, see handle a new email webhook.
Handle the webhook and fetch the full message
Section titled “Handle the webhook and fetch the full message”Each message.created notification carries the grant_id and the message id, but the body may be absent or truncated past the 1 MB payload limit. So the handler’s job is small: validate the signature, acknowledge fast, then fetch the complete message through GET /v3/grants/{grant_id}/messages/{message_id}. Return a 200 quickly; slow handlers risk redelivery.
The request below retrieves one message by ID and returns the subject, from, to, body, and any attachments metadata in the same JSON shape across all providers. Do the heavy work after you respond to the webhook, ideally on a queue, so a slow model call never holds the connection open.
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/<MESSAGE_ID>' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'from nylas import Client
nylas = Client(api_key="<NYLAS_API_KEY>")
def handle_message_created(grant_id, message_id): message = nylas.messages.find(grant_id, message_id).data # Hand off to your extraction and action layer process(message.subject, message.body, message.from_)The unified from, subject, and body fields mean you write one parser. The same handler works whether the message came from Gmail, Outlook, or an IMAP server, which is the difference from wiring up Gmail push notifications and Microsoft Graph subscriptions separately.
Webhook triggers vs polling for new email
Section titled “Webhook triggers vs polling for new email”You can find new mail two ways: subscribe to webhooks, or poll GET /v3/grants/{grant_id}/messages on a timer. Webhooks push you a notification within seconds of a message syncing, while polling trades latency and wasted requests for control over timing. For most inbound automation, the message.created webhook wins on both speed and cost.
| Concern | Polling the messages endpoint | message.created webhook |
|---|---|---|
| Latency | As long as your poll interval | Seconds after sync |
| Request cost | One call per inbox per interval | One notification per new message |
| Scaling to many inboxes | Grows linearly, hits rate limits | Push, no per-inbox polling |
| Setup | A scheduler and cursor tracking | One destination, verify the signature |
Polling is the right call in two cases: when your endpoint can’t accept inbound HTTPS (a locked-down backend), or when you process a daily batch and second-level latency doesn’t matter. Otherwise the push model is simpler to operate. Note that the API blocks Ngrok tunnels as webhook destinations, so use a stable public URL or a different tunneling tool during local development.
Things to know about inbound email triggers
Section titled “Things to know about inbound email triggers”Inbound email automation has a few sharp edges worth knowing before you ship. The message.created trigger fires on newly synced messages, which includes mail your own app sends through a connected account, so filter on the from address or a header if you only want truly inbound mail. Notifications can arrive more than once: the platform retries failed deliveries, and a retry fans out to every destination registered for that trigger type.
Three operational facts shape a reliable handler. Payloads truncate at the 1 MB limit and gain a .truncated suffix, so never assume the body is present. The x-nylas-signature header must be verified with HMAC-SHA256 against your stored secret on every request. And processing must be idempotent: dedupe on message_id before triggering any side effect. For a worked end-to-end example that turns inbound mail into tickets, see monitor an inbox for support tickets.
How do I build inbox automation into a customer-facing SaaS tool?
Section titled “How do I build inbox automation into a customer-facing SaaS tool?”Connect each customer’s mailbox once through OAuth, store the returned grant_id, and register one webhook destination that serves every grant. A single message.created subscription covers all connected accounts, so onboarding a new customer adds a grant, not a new integration. Your handler routes each notification by its grant_id to the right tenant.
The multi-tenant pattern is straightforward because the grant model does the isolation for you. Each notification names its grant_id, so you look up the owning customer, apply their rules, and act within their account, all through one webhook and one API key. Adding Microsoft, iCloud, or Yahoo customers later costs nothing extra: the same trigger and the same message shape cover all six providers. Watch the grant lifecycle triggers too, grant.expired in particular, so you can prompt a customer to re-authenticate before their automation silently stops. Subscribe to grant.expired alongside message.created in the same destination.
What’s next
Section titled “What’s next”- Handle a new email webhook for the full registration and signature verification walkthrough
- Extract structured data from email for the AI parsing step in your trigger loop
- Monitor an inbox for support tickets for a complete inbound-to-action example
- Getting started with Nylas to create a project, connector, and your first grant