Skip to content
Skip to main content

Automate a sales pipeline

Sales reps spend hours logging activity in their CRM. Emails go untracked, meetings disappear from records, contact details rot. The reps know it’s busywork. They skip it whenever they can, which is most of the time.

This recipe replaces the busywork with three webhook-and-cron pipelines that keep your CRM honest without anyone touching it. Email threads with prospects log automatically when message.created fires. Meetings log when event.created fires. Contact phone numbers, job titles, and companies refresh on a nightly sync. The same code works against Google, Microsoft, and IMAP — Nylas normalizes the providers underneath.

┌─────────────────────────────────────────────────────────┐
│ │
inbound email ──▶ message.created webhook ──▶ match sender to CRM ──▶ log activity
calendar event ──▶ event.created/updated webhook ────────┘
shared CRM lookup function
nightly cron ──▶ list Nylas contacts ──▶ patch CRM with fresh phone/title/company

Three components, one shared CRM lookup function. Each component works independently — start with email tracking and add the others later.

Make sure you have the following before starting this tutorial:

  • A Nylas account with an active application
  • A valid API key from your Nylas Dashboard
  • At least one connected grant (an authenticated user account) for the provider you want to work with
  • Node.js 18+ or Python 3.8+ installed (depending on which code samples you follow)

You also need:

  • Connected grants for each sales rep whose email and calendar you want to monitor
  • A CRM with an API (Salesforce, HubSpot, Pipedrive, or any system that accepts HTTP requests)
  • A publicly accessible HTTPS endpoint to receive webhook notifications from Nylas

Start by creating a webhook subscription that listens for new messages and calendar events. This single subscription covers all grants in your Nylas application, so every connected sales rep is automatically included.

Nylas sends a GET request to your endpoint with a challenge query parameter to verify it. Your server must return the exact challenge value in a 200 response.

Once verified, Nylas begins delivering webhook notifications as POST requests to your endpoint.

When a new email arrives for any connected sales rep, Nylas sends a message.created webhook. Your handler receives the full message object, including sender, recipients, subject, snippet, and thread ID. The goal is to check whether the message involves a known prospect and, if so, log it to your CRM.

Here is the structure of a message.created notification payload:

The handler below receives the webhook, extracts the sender and recipients, checks them against your CRM’s prospect list, and logs a new activity if there is a match.

The thread_id field is especially useful here. It groups related messages into a single conversation, so your CRM can display the full email thread on a deal record instead of showing isolated messages.

Meeting activity is one of the strongest signals in a sales pipeline. When a rep schedules a call with a prospect, you want that logged immediately. The event.created webhook fires whenever a new calendar event appears for a connected grant.

Here is the structure of an event.created notification:

This handler checks whether any event participant is a known prospect. If so, it creates a meeting activity in your CRM with the title, time, duration, and conferencing link.

Webhooks handle real-time email and calendar signals. Contact data, on the other hand, works better with periodic sync. Run a scheduled job (every few hours or once a day) that pulls contacts from each grant and updates your CRM with fresh phone numbers, job titles, and company names.

Fetch contacts from the Nylas Contacts API:

The response includes structured contact fields you can map directly to your CRM:

This script iterates through all grants, paginates through their contacts, and upserts matching records in your CRM.

A raw webhook feed is noisy. Not every email or calendar event is a sales interaction. Here are four filtering strategies you should implement before pushing data to your CRM.

Emails between colleagues are not prospect activity. Compare the sender and recipient domains to your company’s domain and skip the message if they match.

Automated emails clutter the pipeline. Look for the List-Unsubscribe header, bulk sender patterns, and common no-reply addresses.

Nylas guarantees at-least-once delivery, which means you may receive the same notification more than once. Track processed webhook IDs to avoid duplicate CRM entries.

For production systems, use Redis or a database table with a TTL instead of an in-memory Set. The in-memory approach works for development but does not survive restarts.

Out-of-office messages trigger message.created webhooks just like real replies. Detect them by checking for common OOO patterns in the subject line or body snippet.

The three components fit together around a central webhook handler that acts as the routing layer between Nylas and your CRM.

Webhook-driven path (real-time): Nylas monitors every connected grant for new messages and calendar events. When a trigger fires, Nylas sends a POST request to your webhook endpoint. The handler validates the signature, checks the notification type, and routes it to the appropriate processor. The email processor matches sender/recipient addresses against your CRM’s contact and deal records. The meeting processor does the same with event participants. Both push activity records into your CRM through its API.

Scheduled sync path (periodic): A cron job or scheduled task runs on a fixed interval. It iterates through each grant, fetches contacts from the Nylas Contacts API, and compares them against existing CRM records. When it finds updated phone numbers, job titles, or company names, it patches the CRM record.

Shared CRM lookup layer: Both paths share the same function for matching email addresses to CRM prospects. This is the single point where you define what counts as a “known prospect.” You could match on email domain, on a specific deal stage, or on a tag in your CRM. Keep this logic centralized so you can tune it without updating multiple handlers.

The result is a pipeline where every meaningful email, every meeting, and every contact change flows into your CRM automatically. Sales reps see a complete activity timeline on each deal record without logging anything manually.

  • Don’t ship without dedup. At-least-once delivery means the same message.created notification can land twice, especially if your handler was slow. Track processed webhook IDs in Redis or a database table with a TTL — don’t trust an in-memory Set past development.
  • Filter internal email aggressively. A pipeline that logs every “lunch?” thread between colleagues becomes useless fast. Compare sender + recipient domains against your company’s domains and skip when every address is internal.
  • Use the folders field for direction. SENT means the rep wrote it; INBOX means the prospect replied. Don’t try to compare addresses against a roster — that breaks when reps change roles.
  • Out-of-office replies fire message.created like any other message. Detect them by subject patterns (out of office, automatic reply, auto-reply) and skip. Logging an OOO as prospect engagement is worse than missing a real reply.
  • Meeting updates create duplicates if you don’t key on event ID. Meetings get rescheduled constantly. Use the event id as the unique key in your CRM so updates overwrite the original record instead of creating a new row.
  • Per-application rate limits matter at scale. If you’re syncing contacts for hundreds of grants on a nightly cron, sequence the requests with a concurrency cap. Burst sync jobs are how you trip your own rate limit.