Source: https://cli.nylas.com/guides/send-and-parse-email-one-api

# 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](https://cli.nylas.com/authors/pouya-sanooei) Software Engineer

Reviewed by [Qasim Muhammad](https://cli.nylas.com/authors/qasim-muhammad)

Updated June 9, 2026

> **TL;DR:** A sending API moves mail out; parsing what comes back usually means a second product, a dedicated MX record, and a webhook that POSTs raw MIME at you. The CLI runs both directions on one grant — `nylas email send` outbound, `nylas email search` inbound. By the end of this page, a 15-line script sends a message, catches the reply, and answers it.

Command references used in this guide: [`nylas email send`](https://cli.nylas.com/docs/commands/email-send), [`nylas email search`](https://cli.nylas.com/docs/commands/email-search), and [`nylas webhook create`](https://cli.nylas.com/docs/commands/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](https://www.twilio.com/docs/sendgrid/for-developers/parsing-email/setting-up-the-inbound-parse-webhook) 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](https://datatracker.ietf.org/doc/html/rfc5321) and its 1982 predecessor. A bidirectional email API reads that real mailbox instead, so there's no parsing subdomain to operate.

| Concern | Sending API + inbound parse | One bidirectional grant |
| --- | --- | --- |
| Products to integrate | 2 (send + parse) | 1 |
| DNS setup | MX record on a dedicated subdomain | None |
| Inbound payload | multipart/form-data POST | Structured JSON fields |
| Reads the real mailbox | No | Yes |
| Auth systems | API key + webhook signing key | One 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](https://cli.nylas.com/guides/getting-started). The OAuth token lands in your system keyring and refreshes automatically, so the connection survives unattended cron runs.

```bash
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.

```bash
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](https://developers.google.com/workspace/gmail/api/guides) for Google accounts, the Microsoft Graph [message resource](https://learn.microsoft.com/en-us/graph/api/resources/message) 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.

```bash
# 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](https://developer.nylas.com/docs/v3/notifications/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.

```bash
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.

```bash
#!/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

- [Receive inbound email from the CLI](https://cli.nylas.com/guides/receive-inbound-email-cli) — the read side in depth: list, search, and read commands
- [Parse inbound email with webhooks](https://cli.nylas.com/guides/parse-inbound-email-webhooks) — build the push-based pipeline end to end
- [Email API vs SMTP](https://cli.nylas.com/guides/email-api-vs-smtp) — why an HTTP API covers more than a send-only protocol
- [Twilio SendGrid vs Nylas](https://cli.nylas.com/guides/twilio-vs-nylas) — the two-product stack compared head to head
- [EmailEngine vs Nylas](https://cli.nylas.com/guides/emailengine-vs-nylas) — self-hosted bidirectional email vs the hosted grant model
- [Full command reference](https://cli.nylas.com/docs/commands) — every flag and subcommand documented
