This workflow corresponds to n8n.io template #8413 — we link there as the canonical source.
This workflow follows the Emailsend → Google Drive 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "3060dd2d-bf5b-404e-8f85-c0bc78a3075e",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
-192
],
"parameters": {
"width": 214,
"height": 272,
"content": "\u2705 **SUCCESS RESPONSE**\n\n- Confirms invoice generated\n- Returns invoice number & total\n- Email delivery confirmation\n- Google Drive storage status\n- Complete operation summary"
},
"typeVersion": 1
},
{
"id": "353da029-1514-40d0-969b-bcd2816bdbcc",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"position": [
-800,
112
],
"parameters": {
"path": "generate-invoice",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "d3c566ba-582b-4e17-b30d-580c5e617630",
"name": "Process Invoice Data",
"type": "n8n-nodes-base.code",
"position": [
-576,
112
],
"parameters": {
"jsCode": "// Process and validate invoice data\nconst data = $input.item.json.body;\n\n// Generate invoice number if not provided\nconst invoiceNumber = data.invoiceNumber || `INV-${new Date().getFullYear()}-${String(Date.now()).slice(-6)}`;\n\n// Process items and calculate totals\nconst items = data.items || [];\nlet subtotal = 0;\n\nconst processedItems = items.map(item => {\n const qty = parseFloat(item.quantity || item.qty || 1);\n const price = parseFloat(item.price || 0);\n const total = qty * price;\n subtotal += total;\n \n return {\n description: item.description || 'Service',\n quantity: qty,\n price: price,\n total: total.toFixed(2)\n };\n});\n\n// Calculate tax and total\nconst taxRate = parseFloat(data.taxRate || 0.1);\nconst taxAmount = subtotal * taxRate;\nconst totalAmount = subtotal + taxAmount;\n\n// Format dates\nconst currentDate = new Date().toISOString().split('T')[0];\nconst dueDate = data.dueDate || new Date(Date.now() + 30*24*60*60*1000).toISOString().split('T')[0];\n\nreturn {\n customerName: data.customerName || 'Customer',\n customerEmail: data.customerEmail,\n customerAddress: data.customerAddress || '',\n invoiceNumber: invoiceNumber,\n invoiceDate: currentDate,\n dueDate: dueDate,\n companyName: data.companyName || $env.COMPANY_NAME || 'Your Company Ltd',\n companyAddress: data.companyAddress || $env.COMPANY_ADDRESS || '123 Business Street',\n companyEmail: data.companyEmail || $env.COMPANY_EMAIL || 'user@example.com',\n companyPhone: data.companyPhone || $env.COMPANY_PHONE || '+1-555-0123',\n items: processedItems,\n subtotal: subtotal.toFixed(2),\n taxRate: (taxRate * 100).toFixed(1),\n taxAmount: taxAmount.toFixed(2),\n totalAmount: totalAmount.toFixed(2),\n notes: data.notes || 'Thank you for your business!',\n paymentTerms: data.paymentTerms || 'Payment due within 30 days',\n timestamp: new Date().toISOString()\n};"
},
"typeVersion": 2
},
{
"id": "659c77de-7c5c-4a49-9525-07b0106460da",
"name": "Generate HTML Template",
"type": "n8n-nodes-base.code",
"position": [
-352,
112
],
"parameters": {
"jsCode": "// Generate HTML for PDF invoice\nconst data = $input.item.json;\n\n// Create items table rows\nconst itemRows = data.items.map(item => `\n <tr>\n <td style=\"padding: 8px; border-bottom: 1px solid #eee;\">${item.description}</td>\n <td style=\"padding: 8px; border-bottom: 1px solid #eee; text-align: center;\">${item.quantity}</td>\n <td style=\"padding: 8px; border-bottom: 1px solid #eee; text-align: right;\">$${item.price.toFixed(2)}</td>\n <td style=\"padding: 8px; border-bottom: 1px solid #eee; text-align: right;\">$${item.total}</td>\n </tr>\n`).join('');\n\nconst htmlContent = `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <style>\n body { font-family: Arial, sans-serif; margin: 0; padding: 20px; color: #333; }\n .header { display: flex; justify-content: space-between; margin-bottom: 30px; border-bottom: 2px solid #007bff; padding-bottom: 20px; }\n .company-info h1 { color: #007bff; margin: 0; font-size: 28px; }\n .company-info p { margin: 5px 0; color: #666; }\n .invoice-info { text-align: right; }\n .invoice-info h2 { color: #333; margin: 0; font-size: 24px; }\n .customer-section { margin: 30px 0; }\n .customer-section h3 { color: #333; margin-bottom: 10px; }\n .items-table { width: 100%; border-collapse: collapse; margin: 30px 0; }\n .items-table th { background: #007bff; color: white; padding: 12px 8px; }\n .totals { margin-top: 20px; }\n .totals table { margin-left: auto; width: 300px; }\n .totals td { padding: 5px 10px; }\n .totals .total-row { font-weight: bold; border-top: 2px solid #333; }\n .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #eee; color: #666; }\n .payment-terms { background: #f8f9fa; padding: 15px; border-radius: 5px; margin-top: 20px; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <div class=\"company-info\">\n <h1>${data.companyName}</h1>\n <p>${data.companyAddress}</p>\n <p>Email: ${data.companyEmail}</p>\n <p>Phone: ${data.companyPhone}</p>\n </div>\n <div class=\"invoice-info\">\n <h2>INVOICE</h2>\n <p><strong>Invoice #:</strong> ${data.invoiceNumber}</p>\n <p><strong>Date:</strong> ${data.invoiceDate}</p>\n <p><strong>Due Date:</strong> ${data.dueDate}</p>\n </div>\n </div>\n \n <div class=\"customer-section\">\n <h3>Bill To:</h3>\n <p><strong>${data.customerName}</strong></p>\n <p>${data.customerEmail}</p>\n </div>\n \n <table class=\"items-table\">\n <thead>\n <tr>\n <th>Description</th>\n <th>Quantity</th>\n <th>Unit Price</th>\n <th>Total</th>\n </tr>\n </thead>\n <tbody>\n ${itemRows}\n </tbody>\n </table>\n \n <div class=\"totals\">\n <table>\n <tr>\n <td>Subtotal:</td>\n <td style=\"text-align: right;\">$${data.subtotal}</td>\n </tr>\n <tr>\n <td>Tax (${data.taxRate}%):</td>\n <td style=\"text-align: right;\">$${data.taxAmount}</td>\n </tr>\n <tr class=\"total-row\">\n <td><strong>Total Amount:</strong></td>\n <td style=\"text-align: right;\"><strong>$${data.totalAmount}</strong></td>\n </tr>\n </table>\n </div>\n \n <div class=\"payment-terms\">\n <h4>Payment Terms:</h4>\n <p>${data.paymentTerms}</p>\n </div>\n \n <div class=\"footer\">\n <p>${data.notes}</p>\n <p><em>Generated automatically on ${new Date().toLocaleDateString()}</em></p>\n </div>\n</body>\n</html>\n`;\n\nreturn {\n ...data,\n htmlContent: htmlContent,\n filename: `invoice-${data.invoiceNumber}.pdf`\n};"
},
"typeVersion": 2
},
{
"id": "7fe430f5-e516-4f3f-9ffd-d82e3a3db05a",
"name": "Generate PDF",
"type": "n8n-nodes-base.httpRequest",
"position": [
-112,
112
],
"parameters": {
"url": "={{ $env.PDF_API_URL || 'https://api.pdfshift.io/v3/convert/pdf' }}",
"method": "POST",
"options": {
"response": {}
},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{}
]
},
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Authorization",
"value": "Basic {{ $env.PDF_API_KEY }}"
}
]
}
},
"typeVersion": 4
},
{
"id": "9b88a23b-b415-4f2c-b818-a12a6e5c2bf6",
"name": "Send Email to Customer",
"type": "n8n-nodes-base.emailSend",
"position": [
128,
48
],
"parameters": {
"html": "=Dear {{ $json.customerName }},<br><br>Thank you for your business! Please find your invoice attached.<br><br><strong>Invoice Details:</strong><br>\u2022 Invoice Number: {{ $json.invoiceNumber }}<br>\u2022 Date: {{ $json.invoiceDate }}<br>\u2022 Due Date: {{ $json.dueDate }}<br>\u2022 Amount Due: ${{ $json.totalAmount }}<br><br><strong>Payment Terms:</strong><br>{{ $json.paymentTerms }}<br><br>If you have questions, contact us at {{ $json.companyEmail }}<br><br>Best regards,<br>{{ $json.companyName }}",
"options": {},
"subject": "Invoice {{ $json.invoiceNumber }} from {{ $json.companyName }}",
"toEmail": "={{ $json.customerEmail }}",
"fromEmail": "={{ $env.COMPANY_EMAIL }}",
"emailFormat": "html"
},
"typeVersion": 2
},
{
"id": "5279d3ca-eff7-45dc-bcc6-41f85bbe2bb6",
"name": "Save to Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
128,
176
],
"parameters": {
"name": "={{ $json.filename }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "root",
"cachedResultName": "/ (Root folder)"
}
},
"typeVersion": 3
},
{
"id": "629c75bd-88a2-4ea7-a3dc-5450387d6378",
"name": "Success Response",
"type": "n8n-nodes-base.code",
"position": [
352,
112
],
"parameters": {
"jsCode": "return {\n success: true,\n message: 'Invoice generated and sent successfully',\n invoiceNumber: $json.invoiceNumber,\n customerEmail: $json.customerEmail,\n totalAmount: $json.totalAmount,\n filename: $json.filename,\n timestamp: new Date().toISOString(),\n emailSent: true,\n savedToDrive: true\n};"
},
"typeVersion": 2
},
{
"id": "921ff838-cd75-4f5b-9b29-9d96fbcac947",
"name": "Respond Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
576,
112
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={{ $json }}"
},
"typeVersion": 1
},
{
"id": "0c4bb277-7fe4-419c-bee0-69dede34a59e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
320
],
"parameters": {
"width": 214,
"height": 224,
"content": "\u2601\ufe0f **SAVE TO DRIVE**\n\n- Uploads PDF to Google Drive\n- Organized folder structure\n- Automated file naming\n- Backup for accounting records\n- Secure cloud storage"
},
"typeVersion": 1
},
{
"id": "be43dfc4-8068-44db-bbcb-f81dc86d2162",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
-208
],
"parameters": {
"width": 214,
"height": 240,
"content": "\ud83d\udce7 **SENDS TO CUSTOMER**\n\n- Emails PDF invoice to customer\n- Professional email template\n- Includes payment instructions\n- Attachment with generated PDF\n- Confirms delivery status"
},
"typeVersion": 1
},
{
"id": "84e365dd-a54a-4ce0-a273-ae8cbfb9bf93",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
-160
],
"parameters": {
"width": 214,
"height": 256,
"content": "\ud83d\udcc4 **INVOICE GENERATION**\n\n- Creates professional HTML template\n- Applies company branding & colors\n- Builds itemized table with pricing\n- Adds payment terms and due dates\n- Includes company contact details"
},
"typeVersion": 1
},
{
"id": "3673840a-5ac8-48ec-af6a-c30db464e73d",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
-144
],
"parameters": {
"width": 214,
"height": 256,
"content": "\u2699\ufe0f **PREPARING INVOICE**\n\n- Extracts customer data from webhook\n- Validates required fields (email, items)\n- Calculates line totals and subtotals\n- Applies tax rates (default 10%)\n- Formats dates and invoice numbers"
},
"typeVersion": 1
}
],
"connections": {
"Generate PDF": {
"main": [
[
{
"node": "Send Email to Customer",
"type": "main",
"index": 0
},
{
"node": "Save to Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Webhook Trigger": {
"main": [
[
{
"node": "Process Invoice Data",
"type": "main",
"index": 0
}
]
]
},
"Success Response": {
"main": [
[
{
"node": "Respond Webhook",
"type": "main",
"index": 0
}
]
]
},
"Process Invoice Data": {
"main": [
[
{
"node": "Generate HTML Template",
"type": "main",
"index": 0
}
]
]
},
"Save to Google Drive": {
"main": [
[
{
"node": "Success Response",
"type": "main",
"index": 0
}
]
]
},
"Generate HTML Template": {
"main": [
[
{
"node": "Generate PDF",
"type": "main",
"index": 0
}
]
]
},
"Send Email to Customer": {
"main": [
[
{
"node": "Success Response",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically generates professional PDF invoices from webhook data and delivers them via email while storing backups in Google Drive. Perfect for freelancers, small businesses, and service providers who need automated billing workflows.
Source: https://n8n.io/workflows/8413/ — 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.
Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 78 nodes.
Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 78 nodes.
Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.
Email AI Auto-responder. Summerize and send email. Uses emailReadImap, emailSend, httpRequest, googleDrive. Event-driven trigger; 26 nodes.
Automate short-term trading research by generating high-quality trade ideas using MCP (Market Context Protocol) signals and AI-powered analysis. 📈🤖 This workflow evaluates market context, catalysts, m