8
n8n 中文网amn8n.com

使用Gmail和Google Drive存储自动化PDF发票生成与发送

中级

这是一个Miscellaneous, Multimodal AI领域的自动化工作流,包含 13 个节点。主要使用 Code, Webhook, EmailSend, GoogleDrive, HttpRequest 等节点。 使用Gmail和Google Drive存储自动化PDF发票生成与发送

前置要求
  • HTTP Webhook 端点(n8n 会自动生成)
  • Google Drive API 凭证
  • 可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "6d51f49bab6b0dffc9b87e9dabbeb0e9b71c14bdaab2b96ec32b663d472dacc3",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "3060dd2d-bf5b-404e-8f85-c0bc78a3075e",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -192
      ],
      "parameters": {
        "width": 214,
        "height": 272,
        "content": "✅ **成功响应**"
      },
      "typeVersion": 1
    },
    {
      "id": "353da029-1514-40d0-969b-bcd2816bdbcc",
      "name": "Webhook触发器",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -800,
        112
      ],
      "webhookId": "56df3812-2f30-4148-9223-a6474390fe15",
      "parameters": {
        "path": "generate-invoice",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "d3c566ba-582b-4e17-b30d-580c5e617630",
      "name": "处理发票数据",
      "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 || 'billing@company.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": "生成 HTML 模板",
      "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": "生成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": "发送邮件给客户",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        128,
        48
      ],
      "webhookId": "f33ab465-57d0-48db-ae94-3f6d2b37c930",
      "parameters": {
        "html": "=Dear {{ $json.customerName }},<br><br>Thank you for your business! Please find your invoice attached.<br><br><strong>Invoice Details:</strong><br>• Invoice Number: {{ $json.invoiceNumber }}<br>• Date: {{ $json.invoiceDate }}<br>• Due Date: {{ $json.dueDate }}<br>• 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": "保存到 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": "成功响应",
      "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": "响应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": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        320
      ],
      "parameters": {
        "width": 214,
        "height": 224,
        "content": "☁️ **保存到云端硬盘**"
      },
      "typeVersion": 1
    },
    {
      "id": "be43dfc4-8068-44db-bbcb-f81dc86d2162",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        32,
        -208
      ],
      "parameters": {
        "width": 214,
        "height": 240,
        "content": "📧 **发送给客户**"
      },
      "typeVersion": 1
    },
    {
      "id": "84e365dd-a54a-4ce0-a273-ae8cbfb9bf93",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        -160
      ],
      "parameters": {
        "width": 214,
        "height": 256,
        "content": "📄 **发票生成**"
      },
      "typeVersion": 1
    },
    {
      "id": "3673840a-5ac8-48ec-af6a-c30db464e73d",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -448,
        -144
      ],
      "parameters": {
        "width": 214,
        "height": 256,
        "content": "⚙️ **准备发票**"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "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
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

中级 - 杂项, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量13
分类2
节点类型7
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

作者
Ibrahim Emre POLAT

Ibrahim Emre POLAT

@epolat

Senior Software Developer specializing in automation and integrations with n8n. Experienced in .NET, PostgreSQL, and cloud-native systems. Continuously learning new tools and technologies to deliver efficient, scalable workflows.

外部链接
在 n8n.io 查看

分享此工作流