This workflow corresponds to n8n.io template #17187 — we link there as the canonical source.
This workflow follows the Gmail → 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 →
{
"id": "p8O9fh8dg0LnAyxD",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "INVOICE ORDERS OR ORDERS AUTOMATION",
"tags": [],
"nodes": [
{
"id": "f18dd5c9-5564-441d-87d9-567e6d4d7357",
"name": "Email Invoice via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
2784,
96
],
"parameters": {
"sendTo": "={{ $('Prepare Invoice Number').item.json.client_email }}",
"message": "=Hi {{ $('Prepare Invoice Number').item.json.client_name }}, please find your invoice attached.",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{}
]
}
},
"subject": "=Your Invoice #{{ $('Prepare Invoice Number').item.json.invoice_number }}"
},
"typeVersion": 2.2
},
{
"id": "5aedfead-3547-4db9-bc4e-3828deb6d0ae",
"name": "Download PDF from URL",
"type": "n8n-nodes-base.httpRequest",
"position": [
2544,
96
],
"parameters": {
"url": "={{ $json.pdf_url }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.4
},
{
"id": "b2dc5784-96ea-49f7-a579-5f70cc466695",
"name": "Generate PDF Invoice",
"type": "n8n-nodes-base.httpRequest",
"position": [
2304,
96
],
"parameters": {
"url": "https://pdfmunk.com/api/v1/generatePdf",
"method": "POST",
"options": {},
"jsonBody": "={\n \"html_content\": {{ JSON.stringify($json.invoice_html) }},\n \"output_format\": \"url\",\n \"paper_size\": \"A4\",\n \"printBackground\": true\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"typeVersion": 4.4
},
{
"id": "9a076cab-85d5-4618-88c1-cba0cecc40db",
"name": "Process Invoice Data",
"type": "n8n-nodes-base.code",
"position": [
2064,
96
],
"parameters": {
"jsCode": "const data = {\n invoice_number: $input.item.json[\"Invoice Number\"],\n client_name: $input.item.json[\"Client Name\"],\n client_email: $input.item.json[\"Client Email\"],\n item_description: $input.item.json[\"Item\"],\n quantity: $input.item.json[\"Quantity\"],\n unit_price: $input.item.json[\"Unit Price\"],\n due_date: $input.item.json[\"Due Date\"],\n status: $input.item.json[\"Status\"]\n};\n\nconst html = `\n<!DOCTYPE html>\n<html>\n<head>\n<style>\n body { font-family: Arial, sans-serif; padding: 40px; color: #2c2c2c; }\n .invoice-box { max-width: 700px; margin: auto; border: 1px solid #ddd; padding: 30px; }\n .header { display: flex; justify-content: space-between; border-bottom: 2px solid #333; padding-bottom: 15px; margin-bottom: 20px; }\n .invoice-title { font-size: 26px; font-weight: bold; color: #444; }\n table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }\n th { background: #333; color: #fff; padding: 8px 10px; text-align: left; font-size: 13px; }\n td { padding: 8px 10px; border-bottom: 1px solid #eee; font-size: 13px; }\n .totals { text-align: right; font-size: 16px; font-weight: bold; margin-top: 10px; }\n .footer { margin-top: 30px; font-size: 12px; color: #888; text-align: center; }\n</style>\n</head>\n<body>\n <div class=\"invoice-box\">\n <div class=\"header\">\n <div>\n <h2>Invoice Orders</h2>\n </div>\n <div class=\"invoice-title\">INVOICE</div>\n </div>\n <p><strong>Invoice Number:</strong> ${data.invoice_number}</p>\n <p><strong>Billed to:</strong> ${data.client_name} (${data.client_email})</p>\n <p><strong>Due Date:</strong> ${data.due_date}</p>\n <table>\n <thead>\n <tr><th>Item</th><th>Quantity</th><th>Unit Price</th><th>Total</th></tr>\n </thead>\n <tbody>\n <tr>\n <td>${data.item_description}</td>\n <td>${data.quantity}</td>\n <td>${data.unit_price}</td>\n <td>${Number(data.quantity) * Number(data.unit_price)}</td>\n </tr>\n </tbody>\n </table>\n <div class=\"totals\">Total: ${Number(data.quantity) * Number(data.unit_price)}</div>\n <div class=\"footer\">Status: ${data.status}</div>\n </div>\n</body>\n</html>\n`;\n\nreturn {\n json: {\n ...data,\n invoice_html: html\n }\n};"
},
"typeVersion": 2
},
{
"id": "aec9cca3-011f-48e1-b6f9-70a6b05fbbed",
"name": "Append to Invoice Orders Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1824,
96
],
"parameters": {
"columns": {
"value": {
"Item": "={{ $json.item_description }}",
"Status": "={{ $json.status }}",
"Due Date": "={{ $json.due_date }}",
"Quantity": "={{ $json.quantity }}",
"Unit Price": "={{ $json.unit_price }}",
"Client Name": "={{ $json.client_name }}",
"Client Email": "={{ $json.client_email }}",
"Invoice Number": "={{ $json.invoice_number }}"
},
"schema": [
{
"id": "Invoice Number",
"type": "string",
"display": true,
"required": false,
"displayName": "Invoice Number",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Client Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Client Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Item",
"type": "string",
"display": true,
"required": false,
"displayName": "Item",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Quantity",
"type": "string",
"display": true,
"required": false,
"displayName": "Quantity",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Unit Price",
"type": "string",
"display": true,
"required": false,
"displayName": "Unit Price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Due Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Due Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1895595365,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw/edit#gid=1895595365",
"cachedResultName": "Sheet2"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw/edit?usp=drivesdk",
"cachedResultName": "INVOICE ORDERS"
}
},
"typeVersion": 4.7
},
{
"id": "b5e41da2-6f19-4468-a908-7a6048edfc6c",
"name": "Prepare Invoice Number",
"type": "n8n-nodes-base.set",
"position": [
1584,
96
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c5a9dcf3-dc11-4b55-955c-8aeed479e88d",
"name": "invoice_number",
"type": "string",
"value": "=INV-{{ $now.format(\"yyyyMMddHHmmss\") }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "2dc348c5-fc6d-4ba3-b37b-893256075a22",
"name": "Set Client and Item Details",
"type": "n8n-nodes-base.set",
"position": [
1360,
96
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "52b833d8-eb1a-47ad-b99f-2429da0abeb4",
"name": "client_name",
"type": "string",
"value": "={{ $json[\"Client Name\"] }}"
},
{
"id": "f20eb1e8-14fe-4fc2-aba0-5a4ee4127adb",
"name": "client_email",
"type": "string",
"value": "={{ $json[\"Client Email\"] }}"
},
{
"id": "ca35f1b1-0712-41c0-bdb7-b766709b1b42",
"name": "item_description",
"type": "string",
"value": "={{ $json[\"Item Description\"] }}"
},
{
"id": "2ac25fdc-37a1-45a3-be87-89baae012611",
"name": "quantity",
"type": "string",
"value": "={{ $json[\"Quantity\"] }}"
},
{
"id": "4d2b444a-9173-4ac6-bf57-f6de45e477ec",
"name": "unit_price",
"type": "string",
"value": "={{ $json[\"Unit Price\"] }}"
},
{
"id": "4a136b0b-612c-4c18-8bbf-c5c37ac0cb86",
"name": "due_date",
"type": "string",
"value": "={{ $json[\"Due Date\"] }} \u2705"
},
{
"id": "b84faaf2-f457-41a6-8848-ac031a958d00",
"name": "status",
"type": "string",
"value": "={{ $json[\"Status\"] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b5f12922-9ab8-4dc3-8bf9-edbeea1d296d",
"name": "When Sheet Updated",
"type": "n8n-nodes-base.googleSheetsTrigger",
"position": [
1088,
96
],
"parameters": {
"event": "rowAdded",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qzXnnZnD2-GnywIjDsYcxD6WembJ_pktz-6VfLa5rLw/edit?usp=drivesdk",
"cachedResultName": "INVOICE ORDERS"
}
},
"typeVersion": 1
},
{
"id": "578aaa5b-d501-4afa-8c32-8b5f51921754",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2736,
-160
],
"parameters": {
"color": 7,
"height": 400,
"content": "## Email invoice message\n\nSends the resulting invoice message through Gmail, likely attaching or linking the generated PDF for the client. This final node is the rightmost delivery step."
},
"typeVersion": 1
},
{
"id": "24b25c34-7180-47a6-91a7-531e0962fc1b",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2256,
-96
],
"parameters": {
"color": 7,
"width": 432,
"height": 336,
"content": "## Generate and fetch PDF\n\nCalls the PdfMunk API to generate the invoice PDF, then retrieves the generated PDF from the returned URL. These adjacent HTTP nodes form the PDF creation and download cluster."
},
"typeVersion": 1
},
{
"id": "1d617725-e1ed-4e97-948e-d8ac5a855501",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1776,
-128
],
"parameters": {
"color": 7,
"width": 432,
"height": 368,
"content": "## Record and prepare invoice\n\nAppends the prepared invoice data back into a Google Sheet, then runs custom JavaScript to shape the payload needed for PDF generation. This is the middle processing cluster before external PDF calls."
},
"typeVersion": 1
},
{
"id": "18b296ea-56c9-4e35-a75d-6bbd265f437d",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1040,
-80
],
"parameters": {
"color": 7,
"width": 688,
"height": 320,
"content": "## Capture sheet input\n\nStarts the workflow from a Google Sheets change and normalizes the incoming client and item details, then assigns an invoice number. These nodes form the leftmost input-preparation cluster."
},
"typeVersion": 1
},
{
"id": "64be2e58-0c76-419a-b3aa-9fee87275ade",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
-160
],
"parameters": {
"width": 480,
"height": 848,
"content": "## My workflow\n\n### How it works\n\nThis workflow creates and sends invoices from Google Sheets data. It triggers when a sheet event occurs, extracts client and item fields, generates an invoice number, records the invoice, creates a PDF through PdfMunk, downloads it, and sends it via Gmail.\n\n### Setup steps\n\n- Connect Google Sheets credentials for both the trigger and append-row node.\n- Configure the source Google Sheet and worksheet used by the trigger, and the destination sheet used to record invoice rows.\n- Review the Set nodes to ensure client_name, client_email, item_description, quantity, and invoice_number match the sheet column names and desired invoice format.\n- Add the required PdfMunk API authentication or headers in the HTTP Request node that posts to https://pdfmunk.com/api/v1/generatePdf.\n- Connect Gmail credentials and configure the recipient, subject, body, and PDF attachment or link handling.\n\n### Customization\n\nYou can customize the invoice numbering logic, the JavaScript payload used for PDF generation, the PdfMunk template or request body, and the Gmail message content."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "4f9be997-4e0a-4777-a679-944f1c21889a",
"nodeGroups": [],
"connections": {
"When Sheet Updated": {
"main": [
[
{
"node": "Set Client and Item Details",
"type": "main",
"index": 0
}
]
]
},
"Generate PDF Invoice": {
"main": [
[
{
"node": "Download PDF from URL",
"type": "main",
"index": 0
}
]
]
},
"Process Invoice Data": {
"main": [
[
{
"node": "Generate PDF Invoice",
"type": "main",
"index": 0
}
]
]
},
"Download PDF from URL": {
"main": [
[
{
"node": "Email Invoice via Gmail",
"type": "main",
"index": 0
}
]
]
},
"Prepare Invoice Number": {
"main": [
[
{
"node": "Append to Invoice Orders Sheet",
"type": "main",
"index": 0
}
]
]
},
"Set Client and Item Details": {
"main": [
[
{
"node": "Prepare Invoice Number",
"type": "main",
"index": 0
}
]
]
},
"Append to Invoice Orders Sheet": {
"main": [
[
{
"node": "Process Invoice Data",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow watches a Google Sheets order sheet for new invoice rows, generates a unique invoice number, appends the normalized record to another sheet, converts an HTML invoice into a PDF via PDFMunk, and emails the PDF to the client using Gmail. Triggers when a new row is…
Source: https://n8n.io/workflows/17187/ — 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.
Automatically processes new orders added to Google Sheets. Small orders are approved instantly; large orders trigger an HTML email with one-click Approve / Reject links — each handled by an independen
Fluidflow Licensing Framework. Uses httpRequest, xero, googleSheetsTrigger, slack. Event-driven trigger; 25 nodes.
This workflow monitors a Google Sheets billing queue, creates Mercado Pago payment links for new invoices, emails customers via Gmail, and logs sent links back to Google Sheets, while also handling Me
This workflow watches Google Sheets for new rows, renders a personalized video with iLoveVideoEditor using the row data, uploads the finished MP4 to Google Drive, writes the Drive link back to the sam
Hiring teams often struggle with document follow-ups, offer letter generation, and stakeholder communication. Manual checks, email back-and-forth, and missing files slow down hiring and create chaos d