Guide

Send and Parse Email with One API

Most stacks bolt SendGrid onto a separate inbound-parse product. This guide wires both directions through one grant: nylas email send outbound, nylas email search for replies, one OAuth connection.

Written by Pouya Sanooei Software Engineer

Reviewed by Qasim Muhammad

VerifiedCLI 3.1.17 · Gmail, Outlook · last tested June 9, 2026

Command references used in this guide: nylas email send, nylas email search, and nylas webhook create.

Why do sending and parsing email usually need two products?

Most email stacks split the two directions. A sending API such as SendGrid moves mail out over HTTP, but reading replies requires its separate Inbound Parse webhook — a distinct product with its own DNS setup. An email API that does send and parse together avoids that split: one reply loop, one integration, one auth system.

The split has real setup costs. SendGrid's Inbound Parse documentation requires an MX record at priority 10 pointing to mx.sendgrid.net, on a hostname that “should serve no other purpose other than parsing your incoming email.” Replies then arrive at your endpoint as a multipart/form-data POST your code unpacks field by field. None of that touches the mailbox people actually reply to — mail sent to your normal address still lands in Gmail or Outlook, governed by SMTP routing rules that date to RFC 5321 and its 1982 predecessor. A bidirectional email API reads that real mailbox instead, so there's no parsing subdomain to operate.

ConcernSending API + inbound parseOne bidirectional grant
Products to integrate2 (send + parse)1
DNS setupMX record on a dedicated subdomainNone
Inbound payloadmultipart/form-data POSTStructured JSON fields
Reads the real mailboxNoYes
Auth systemsAPI key + webhook signing keyOne OAuth grant

How do I send email through an API that also reads the inbox?

The nylas email send command delivers mail over the same grant that lists, searches, and replies. One OAuth connection to Gmail or Outlook covers both directions, so there's no sending domain to verify and no API key per product. Setup is two commands and takes about 2 minutes.

Install with Homebrew and run nylas init to connect an account — other install methods are in the getting started guide. The OAuth token lands in your system keyring and refreshes automatically, so the connection survives unattended cron runs.

brew install nylas/nylas-cli/nylas
nylas init   # browser OAuth, one time

Sending takes one command. The --metadata flag attaches up to 50 key=value pairs to the outbound message, and --track-opens reports when the recipient opens it — useful when the reply you're waiting for never comes. The --yes flag skips the confirmation prompt for scripted runs, and --schedule 2h defers delivery without a queue of your own.

nylas email send --to customer@example.com \
  --subject "Order 4812 update" \
  --body "Your order shipped today. Reply with any questions." \
  --metadata order=4812 --track-opens --yes

How do I parse replies with the same API?

The nylas email search command reads inbound mail on the grant that sent the original message. Filters cover sender, recipient, subject, folder, date range, and attachment status. The default page size is 20 results, and the CLI auto-paginates when --limit goes above 200.

There's no MIME to unpack. The search wraps each provider's native message API (the Gmail API for Google accounts, the Microsoft Graph message resource for Outlook), and --json returns sender, subject, date, and body as structured fields. Compare that with an inbound-parse payload, where your code splits a multipart POST into 15-plus form fields before it can read one address.

Attachments stay one command away too. When a reply carries files, nylas email attachments list shows them and nylas email attachments download saves them locally — the inbound-parse equivalent is base64-decoding form fields yourself. Folder scoping works with --in INBOX, and --has-attachment narrows a search to messages that actually carry files.

# Replies about order 4812 since June 1, newest first
nylas email search "Order 4812" --from customer@example.com \
  --after 2026-06-01 --unread --json \
  | jq '.[] | {from: .from[0].email, subject: .subject, date: .date}'

How do I get pushed inbound email instead of polling?

The nylas webhook create command registers an HTTPS endpoint on the same application that sends. The message.created trigger fires for every new message on the grant, and thread.replied fires when a thread you sent gets an answer — no MX record changes and no polling loop.

Webhook payloads arrive as JSON matching the published Nylas notification schemas, and each delivery is signed so nylas webhook verify can check the signature before your handler trusts it. For local development, nylas webhook server --port 8080 runs a receiver on your machine. Run nylas webhook triggers to list every available trigger by category; the Message category alone has 8 triggers, covering creation, opens, link clicks, bounces, and send success or failure.

nylas webhook create --url https://example.com/hooks/email \
  --triggers message.created --triggers thread.replied \
  --description "Inbound mail for order workflows"

# Local testing without deploying anything
nylas webhook server --port 8080

Two maintenance commands round out the inbound side. nylas webhook rotate-secret replaces the signing secret if it ever leaks, and nylas webhook verify --payload-file --signature replays a captured delivery to confirm your handler rejects forged payloads. Compared with a polling loop on a 5-minute cron, a push registration cuts reply latency from minutes to seconds.

How do I close the send-and-parse loop in one script?

A full send-and-parse round trip is a 15-line bash script on one grant: send with a searchable subject, find the unread reply, answer it with nylas email reply. Both directions ride one OAuth token, so the script needs zero stored credentials beyond the keyring entry nylas init created.

This is the script the TL;DR promised. The --quiet flag makes nylas email search print only message IDs, which feeds nylas email reply directly — no jq required. Schedule the second half in cron every 5 minutes and the loop runs unattended.

#!/usr/bin/env bash
# 1. Send the outbound message
nylas email send --to customer@example.com \
  --subject "Order 4812 update" \
  --body "Your order shipped today. Reply with any questions." --yes

# 2. Later (cron): grab the newest unread reply, if any
REPLY_ID=$(nylas email search "Order 4812" \
  --from customer@example.com --unread --limit 1 --quiet)

# 3. Answer it on the same thread
if [ -n "$REPLY_ID" ]; then
  nylas email reply "$REPLY_ID" \
    --body "Thanks! A teammate will follow up within 1 hour." --yes
fi

Tested on Nylas CLI 3.1.17 against Gmail and Outlook grants. The same three commands work unchanged on either provider because the grant abstracts the underlying API — that's the whole argument for one email API doing send and parse instead of two products doing half each.

Next steps