Source: https://cli.nylas.com/guides/email-to-google-sheets

# Log Email to Google Sheets from the Terminal

A spreadsheet is still the fastest way to track leads, signups, or support requests that arrive by email. Wiring that up usually means a brittle Apps Script or a paid Zapier task per row. The Nylas CLI gives you the email side as clean JSON; jq shapes it into rows; the Google Sheets API appends them. This guide builds an email-to-Sheets pipeline you can run on a schedule, with the row mapping in plain code you control.

Written by [Pouya Sanooei](https://cli.nylas.com/authors/pouya-sanooei) Software Engineer

Updated June 8, 2026

> **TL;DR:** Pull messages with `nylas email search --json`, map each one to a row array with `jq`, and append to a sheet with the Google Sheets API `values.append` endpoint. The CLI handles the inbox across six providers; jq handles the shape; the Sheets API handles the write. Run it on a schedule to keep a sheet current with no add-on and no per-row automation fee.

Command references used in this guide: [`nylas email search`](https://cli.nylas.com/docs/commands/email-search), [`nylas email list`](https://cli.nylas.com/docs/commands/email-list), and [`nylas email read`](https://cli.nylas.com/docs/commands/email-read).

## How do you log email to Google Sheets?

You log email to a sheet in three steps: pull the messages as JSON, shape them into rows, and append the rows with the Sheets API. The CLI owns the first step — `nylas email search --json` returns structured messages from any of six providers — so you never parse a mailbox by hand. The last step is one HTTP call to the Sheets `values.append` endpoint, documented in the [Google Sheets API reference](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append).

The middle step is where your logic lives, and keeping it in jq makes the mapping explicit. Each message becomes a row array — date, sender, subject — that the Sheets API accepts directly. Because every layer speaks JSON, there's no scraping and no fragile cell math; the pipeline is three commands you can read in one screen.

```bash
# Pull recent leads as JSON (provider-agnostic)
nylas email search "subject:demo request newer_than:1d" --json --limit 50 > leads.json
```

## How do you shape email into rows?

Shape the messages with `jq`, mapping each one to an array of cells in the order your sheet expects. A row of date, from-address, and subject is a one-line transform, and you can add or reorder columns by editing the array. Because the Sheets API takes a 2D array of values, jq's output drops straight into the request body with no reshaping.

Keep the mapping defensive: messages can have a missing subject or an empty from, so use jq's `// ""` fallback to avoid null cells. A clean row mapping is the difference between a tidy sheet and one with gaps that break downstream formulas. Validate the output is a JSON array of arrays before sending it.

```bash
# Map each message to [date, from, subject], with null-safe fallbacks
jq '[.[] | [ (.date|tostring), (.from[0].email // ""), (.subject // "") ]]' \
  leads.json > rows.json

cat rows.json   # -> [["1718000000","a@x.com","Demo request"], ...]
```

## How do you append rows to the sheet?

Append by POSTing the rows to the Sheets `values.append` endpoint with an OAuth token for the Sheets scope. The request body wraps your jq output under a `values` key, and `valueInputOption=RAW` writes the cells as-is. One call adds every new row to the bottom of the tab, so the sheet grows without you tracking the last row index.

Run the whole pipeline on a schedule — cron, a CI job, or a Kubernetes CronJob — to keep the sheet current. A daily run that appends the day's demo requests costs nothing per row, unlike a per-task automation tool that bills each append. The Google auth here is for Sheets, separate from the mailbox grant the CLI manages.

```bash
SHEET_ID="your-spreadsheet-id"
curl -s -X POST \
  "https://sheets.googleapis.com/v4/spreadsheets/$SHEET_ID/values/Sheet1!A1:append?valueInputOption=RAW" \
  -H "Authorization: Bearer $SHEETS_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"values\": $(cat rows.json)}"
```

## Next steps

- [Extract email data with jq](https://cli.nylas.com/guides/extract-email-data-jq) — the JSON-shaping toolkit
- [Export email to CSV](https://cli.nylas.com/guides/email-to-csv-export) — a file instead of a live sheet
- [Email to Airtable](https://cli.nylas.com/guides/email-to-airtable) — the same pattern into Airtable
- [Automate email reports](https://cli.nylas.com/guides/automate-email-reports-terminal) — schedule the pipeline
- [Email to Discord](https://cli.nylas.com/guides/email-to-discord-notifications) — post email to a channel via webhook
- [Send email to Notion](https://cli.nylas.com/guides/email-to-notion) — file messages as database pages
- [Full command reference](https://cli.nylas.com/docs/commands) — every flag and subcommand documented
