engribet/automation
← All projects

Gmail Email Tracker

Watches a Gmail inbox and records every incoming message as a structured row in Google Sheets — no manual copying.

Running in production Live demo

The production workflow reads a private Gmail inbox and cannot be exposed. The live demo below runs a separate webhook workflow on the same n8n instance, writing to a throwaway sheet.

Status
Running in production
Trigger
Gmail poll, 1 min
Nodes
2
Auth
OAuth 2.0

The problem

Tracking incoming email by hand means opening each message, copying the sender, subject and date into a spreadsheet, and doing it again tomorrow. It is tedious, easy to forget, and the data drifts out of date the moment you stop.

This workflow removes the manual step entirely. New mail arrives, and within a minute it is a row in a spreadsheet — consistently formatted, every time.

How it works

Gmail Trigger polls inbox every minute OAuth 2.0 Append Row in Sheet maps 6 fields Google Sheets API Google Sheet one row per email
Two nodes. The trigger polls; the Sheets node writes.
The Gmail Email Tracker workflow open in n8n, showing the Gmail Trigger connected to the Google Sheets append node, both with green success indicators.
The running workflow in n8n. Green checks and the 1 item counters are a completed execution — one email in, one row out.

1 · Gmail Trigger

An n8n Gmail Trigger node polls the connected inbox once a minute using OAuth 2.0. When it finds messages it has not seen before, it emits one item per message — each carrying the full Gmail message payload.

2 · Append Row in Sheet

A Google Sheets node receives each item and appends it to the tracking spreadsheet. Field mapping is defined explicitly rather than auto-matched, so the column order stays stable even if the incoming payload changes shape:

ColumnSource expression
DateDateTime.fromMillis(Number($json.internalDate))
Sender$json.From
Subject$json.Subject
Preview$json.snippet
Message ID$json.id
Status"New" (literal)

The date arrives from Gmail as internalDate — epoch milliseconds — and is reformatted to yyyy-MM-dd HH:mm:ss in the container timezone, so the spreadsheet reads naturally rather than as a raw integer.

Result

An email arrives:

From:    "Darla • Funnels Mastery Academy" <hello@digitallydarla.com>
Subject: [3DFC] We are closing at 12 PM!
Preview: Last chance to join! ...

Within a minute the sheet has a new row:

DateSenderSubjectStatus
2026-08-19 09:14:22 Darla • Funnels Mastery Academy [3DFC] We are closing at 12 PM! New

Try it yourself

The workflow above reads a private inbox, so it cannot be opened up. This form calls a separate demo workflow on the same n8n instance — a webhook trigger feeding the identical Google Sheets node, writing to a throwaway spreadsheet. Submit it and a real n8n execution runs.

The demo workflow in n8n: Webhook, Sanitise Input, Append Demo Row and Respond nodes connected in a row.
The demo workflow the form below calls — a webhook trigger, an input sanitiser, the same Sheets append node, and a response back to the page.
Rate limited to 10 runs per minute.
Every submission lands in a public spreadsheet — open the demo sheet to see your row arrive.

Authentication

Both nodes authenticate through OAuth 2.0 against a Google Cloud project with the Gmail API and Google Sheets API enabled. Credentials live inside the n8n instance, encrypted at rest — never in the repository.

Note on token lifetime: while a Google OAuth consent screen sits in Testing, refresh tokens expire after seven days and the workflow stops silently. Publishing the app to In production is what makes an unattended automation actually stay running.

Deployment

The workflow runs on a self-hosted n8n instance rather than a laptop, so the poll continues whether or not any machine is awake.

LayerChoice
HostAWS EC2 (Ubuntu 22.04, ap-southeast-1)
RuntimeDocker Compose, official n8n image
Binding127.0.0.1:5678 — loopback only
Ingressnginx reverse proxy, WebSocket upgrade enabled
TLSLet’s Encrypt via certbot, auto-renewing
PersistenceDocker named volume for the n8n data directory

The container binds to loopback rather than 0.0.0.0, so port 5678 is unreachable from the internet regardless of what the security group permits — nginx is the only path in. The reverse proxy forwards Upgrade and Connection headers, which the n8n editor requires to stream execution results over WebSocket.

What I would add next

Source

Workflow JSON and setup instructions: github.com/heartChip16/n8n-gmail-email-tracker