This workflow corresponds to n8n.io template #17920 — we link there as the canonical source.
This workflow follows the Gmail Trigger → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Extract PDF invoices from Gmail to Google Sheets with OpenAI",
"nodes": [
{
"id": "f54f8f1d-9c6e-4a3f-8458-5fe725c8b625",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
-224
],
"parameters": {
"width": 480,
"height": 768,
"content": "## Extract PDF invoices from Gmail to Google Sheets with OpenAI\n\n### How it works\n\nThis workflow monitors a Gmail inbox for PDF invoices, extracts the text from each attachment, and sends the text to an OpenAI-powered information extractor. The extracted invoice fields are then appended as a new row in a Google Sheets ledger.\n\n### Setup steps\n\n- Connect the Gmail credential and configure the trigger to watch the correct inbox, label, or search query for invoice emails with PDF attachments.\n- Configure the PDF extraction node to read the expected attachment/binary property from Gmail.\n- Connect the OpenAI credential and verify the information extractor schema matches the invoice fields you want to capture.\n- Connect the Google Sheets credential and select the target spreadsheet, sheet, and column mappings for the ledger.\n\n### Customization\n\nAdjust the Gmail search filters, the invoice field schema, and the Google Sheets column mapping to match your invoice format and accounting ledger."
},
"typeVersion": 1
},
{
"id": "e26387cd-5391-4b8b-a20a-31eb21c3da29",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
-176
],
"parameters": {
"color": 7,
"width": 432,
"height": 336,
"content": "## Receive and read invoices\n\nWatches Gmail for incoming invoice emails with PDF attachments and extracts the text content from each PDF for downstream processing. These two nodes form the left-side intake cluster."
},
"typeVersion": 1
},
{
"id": "0c3152da-a37a-470f-bdce-75d51dea6f57",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
592,
-224
],
"parameters": {
"color": 7,
"width": 352,
"height": 592,
"content": "## Extract invoice fields\n\nUses the information extractor with an attached OpenAI chat model to turn the PDF text into structured invoice fields such as vendor, date, total, and invoice number. This is the central AI-processing cluster."
},
"typeVersion": 1
},
{
"id": "db6ce5d4-075a-4192-aed9-85fbf74bc40a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
976,
-208
],
"parameters": {
"color": 7,
"width": 240,
"height": 368,
"content": "## Append ledger row\n\nWrites the structured invoice data into a Google Sheets ledger as the final output step on the right side of the canvas."
},
"typeVersion": 1
},
{
"id": "node-gmail-trigger",
"name": "When PDF Invoice Received",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
160,
0
],
"parameters": {
"filters": {
"q": "has:attachment filename:pdf is:unread"
},
"options": {
"downloadAttachments": true,
"dataPropertyAttachmentsPrefixName": "attachment_"
},
"pollTimes": {
"item": [
{
"mode": "everyX",
"unit": "minutes",
"value": 5
}
]
}
},
"typeVersion": 1.2
},
{
"id": "node-extract-text",
"name": "Extract Text from PDF",
"type": "n8n-nodes-base.extractFromFile",
"position": [
400,
0
],
"parameters": {
"options": {},
"operation": "pdf",
"binaryPropertyName": "attachment_0"
},
"typeVersion": 1
},
{
"id": "node-ai-extract",
"name": "Extract Invoice Data with AI",
"type": "@n8n/n8n-nodes-langchain.informationExtractor",
"position": [
640,
0
],
"parameters": {
"text": "={{ $json.text }}",
"options": {
"systemPromptTemplate": "You are an expert accounts-payable clerk. Extract the requested fields from the invoice text precisely. Never invent values: if a field is genuinely absent, return an empty string (or 0 for numbers). Amounts must be plain numbers without currency symbols or thousands separators."
},
"attributes": {
"attributes": [
{
"name": "vendor",
"type": "string",
"description": "Name of the company that issued the invoice (the seller / supplier), exactly as printed"
},
{
"name": "invoice_number",
"type": "string",
"description": "Invoice number or reference ID exactly as printed"
},
{
"name": "invoice_date",
"type": "string",
"description": "Date the invoice was issued, formatted as YYYY-MM-DD"
},
{
"name": "due_date",
"type": "string",
"description": "Payment due date formatted as YYYY-MM-DD; empty string if not present"
},
{
"name": "net_amount",
"type": "number",
"description": "Net amount before tax; if only a total is printed, leave 0"
},
{
"name": "tax_amount",
"type": "number",
"description": "Total tax / VAT amount; 0 if not present"
},
{
"name": "total_amount",
"type": "number",
"description": "Final total amount payable including tax"
},
{
"name": "currency",
"type": "string",
"description": "ISO 4217 currency code, e.g. USD, EUR, GBP. Infer from the currency symbol if needed"
}
]
}
},
"typeVersion": 1
},
{
"id": "node-llm",
"name": "OpenAI GPT-4 Invoice Processor",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
640,
220
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {
"temperature": 0
}
},
"typeVersion": 1.2
},
{
"id": "node-append",
"name": "Append Invoices to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1024,
0
],
"parameters": {
"columns": {
"value": {
"Net": "={{ $json.output.net_amount }}",
"Tax": "={{ $json.output.tax_amount }}",
"Total": "={{ $json.output.total_amount }}",
"Vendor": "={{ $json.output.vendor }}",
"DueDate": "={{ $json.output.due_date }}",
"Currency": "={{ $json.output.currency }}",
"FileName": "={{ $('When PDF Invoice Received').item.binary?.attachment_0?.fileName || '' }}",
"FromEmail": "={{ $('When PDF Invoice Received').item.json.from?.value?.[0]?.address || $('When PDF Invoice Received').item.json.From || '' }}",
"InvoiceDate": "={{ $json.output.invoice_date }}",
"ReceivedDate": "={{ $('When PDF Invoice Received').item.json.date || new Date().toISOString().slice(0,10) }}",
"InvoiceNumber": "={{ $json.output.invoice_number }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Invoices"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID"
}
},
"typeVersion": 4.5
},
{
"id": "sticky-12",
"name": "Sticky Note \u2014 Required Columns",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
592
],
"parameters": {
"width": 380,
"height": 200,
"content": "### \ud83d\udccb Sheet columns (tab `Invoices`)\n\nReceivedDate | FromEmail | Vendor | InvoiceNumber | InvoiceDate | DueDate | Net | Tax | Total | Currency | FileName\n\nOne row per parsed PDF."
},
"typeVersion": 1
},
{
"id": "sticky-13",
"name": "Sticky Note \u2014 Pro Version",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
840
],
"parameters": {
"color": 4,
"width": 380,
"height": 240,
"content": "### \ud83d\ude80 Need more?\n\nI build extended versions of this pipeline: **scanned-PDF OCR**, pushing rows into **QuickBooks/Xero** instead of Sheets, duplicate detection, multi-currency normalization, approval step in Slack/Telegram before posting.\n\nAsync delivery, no calls \u2014 contact links in my creator profile."
},
"typeVersion": 1
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"Extract Text from PDF": {
"main": [
[
{
"node": "Extract Invoice Data with AI",
"type": "main",
"index": 0
}
]
]
},
"When PDF Invoice Received": {
"main": [
[
{
"node": "Extract Text from PDF",
"type": "main",
"index": 0
}
]
]
},
"Extract Invoice Data with AI": {
"main": [
[
{
"node": "Append Invoices to Sheets",
"type": "main",
"index": 0
}
]
]
},
"OpenAI GPT-4 Invoice Processor": {
"ai_languageModel": [
[
{
"node": "Extract Invoice Data with AI",
"type": "ai_languageModel",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow polls Gmail for unread emails with PDF attachments, extracts invoice text, uses OpenAI to pull key invoice fields, and appends the results as a structured row in a Google Sheets “Invoices” ledger. Polls Gmail every 5 minutes for unread emails that include a PDF…
Source: https://n8n.io/workflows/17920/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Detects new unread Gmail messages Extracts sender name for personalized replies Classifies the email into one of four categories Applies the correct Gmail label and either sends an auto-reply, creates
This workflow monitors a Gmail inbox for new support-style emails, uses OpenAI to extract a reusable FAQ question and safe draft answer, logs results to Google Sheets, and then creates a Google Docs d
This n8n workflow automates the complete processing of PDF invoices with AI-powered data extraction. The workflow monitors a Google Drive folder, extracts important invoice data, and automatically org
Who is this for? Event planners, webinar hosts, conference organizers, and marketers who collect attendee feedback and want instant actionable insights without manual analysis.
This workflow runs on demand to crawl Google SERP pages via Talordata, aggregates organic results and related searches, uses OpenAI to produce a structured AI Search Visibility report with GEO recomme