Gmail、OpenAI、Google Driveを使用した請求書と领収書の抽出と分類

上級

これはFinance, AI, IT Ops分野の自動化ワークフローで、20個のノードを含みます。主にIf, Set, Code, Gmail, Mergeなどのノードを使用、AI技術を活用したスマート自動化を実現。 Gmail、OpenAI、Google Driveを使用して領収書と伝票を抽出して分類

前提条件
  • Googleアカウント + Gmail API認証情報
  • HTTP Webhookエンドポイント(n8nが自動生成)
  • Google Drive API認証情報
  • OpenAI API Key
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "meta": {
    "instanceId": "d1b60f1865ef6504ee3af5be4ef9a7387762b4132615a52de808456d52e8d336",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "c84f3a9a-66b3-4a09-b06a-9b399ea574b8",
      "name": "OpenAI",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        420,
        -240
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=Does this PDF file look like a {{ $(\"Configure\").first().json[\"Match on\"] }}? Return \"true\" if it is a {{ $(\"Configure\").first().json[\"Match on\"] }} and \"false\" if not. Only reply with lowercase letters \"true\" or \"false\".\n\nThis is the PDF filename:\n```\n{{ $binary.data.fileName }}\n```\n\nThis is the PDF text content:\n```\n{{ $json.text }}\n```"
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "prYAbsQvWl1pPbdL",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "ea1fbc5b-1859-4d65-8401-30baa95fcc52",
      "name": "設定",
      "type": "n8n-nodes-base.set",
      "position": [
        -700,
        0
      ],
      "parameters": {
        "values": {
          "number": [
            {
              "name": "maxTokenSize",
              "value": 8000
            },
            {
              "name": "replyTokenSize",
              "value": 50
            }
          ],
          "string": [
            {
              "name": "Match on",
              "value": "receipt or invoice that can be considered a software engineering business cost"
            },
            {
              "name": "Google Drive folder to upload matched PDFs",
              "value": "https://drive.google.com/drive/folders/[put_folder_id_here]"
            },
            {
              "name": "sendInvoicesTo"
            }
          ],
          "boolean": [
            {
              "name": "sendEmail",
              "value": "={{ $('Webhook').item.json.body.sendEmail === \"true\" }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "3ee63612-c1e7-40e6-a38f-f77f5ee3efa4",
      "name": "メール添付ファイルの反復処理",
      "type": "n8n-nodes-base.code",
      "position": [
        -200,
        0
      ],
      "parameters": {
        "jsCode": "// https://community.n8n.io/t/iterating-over-email-attachments/13588/3\nlet results = [];\n\nfor (const item of $input.all()) {\n  console.log(item);\n  for (const key of Object.keys(item.binary)) {\n    results.push({\n        json: {},\n        binary: {\n            data: item.binary[key],\n        }\n    });\n  }\n}\n\nreturn results;"
      },
      "typeVersion": 1
    },
    {
      "id": "3e638471-c1c5-4bab-aa2a-12a1777225ec",
      "name": "PDFではない",
      "type": "n8n-nodes-base.noOp",
      "position": [
        120,
        80
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b5af902b-2d59-49ee-b6d8-e387c59b89fd",
      "name": "テキストはトークン制限内?",
      "type": "n8n-nodes-base.if",
      "position": [
        300,
        -100
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.text.length() / 4 <= $('Configure').first().json.maxTokenSize - $('Configure').first().json.replyTokenSize }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a0a8895c-ef8b-44e7-9294-1bcf629d0973",
      "name": "結合",
      "type": "n8n-nodes-base.merge",
      "position": [
        720,
        -120
      ],
      "parameters": {
        "mode": "combine",
        "options": {
          "clashHandling": {
            "values": {
              "resolveClash": "preferInput1"
            }
          }
        },
        "combinationMode": "mergeByPosition"
      },
      "typeVersion": 2
    },
    {
      "id": "7565118a-6d44-4583-a19f-cb4177378d33",
      "name": "一致済み",
      "type": "n8n-nodes-base.if",
      "position": [
        880,
        -120
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.message.content }}",
              "value2": "true"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "074ffb7a-f83e-44b8-84fe-7b85f7245bb0",
      "name": "フォルダにファイルをアップロード",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1100,
        -140
      ],
      "parameters": {
        "name": "={{ $binary.data.fileName }}",
        "options": {},
        "parents": [
          "={{ $('Create folder').first().json.id }}"
        ],
        "binaryData": true
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "xXHySx4T77sDdTqY",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7681eb62-ba86-4c89-9b88-3ce6fc438bd4",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1080,
        0
      ],
      "webhookId": "cded3af3-31df-47c2-a826-ff84eb4a41df",
      "parameters": {
        "path": "cded3af3-31df-47c2-a826-ff84eb4a41df",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "90SsOYPPIe3Qv5Rq",
          "name": "Header Auth account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "aab3d940-55c2-40d3-917a-83412d4e378d",
      "name": "Webhookへ返信",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -720,
        -240
      ],
      "parameters": {
        "options": {
          "responseCode": 202
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"Accepted\",\n  \"driveFolderUrl\": \"{{ \"https://drive.google.com/drive/folders/\" + $json.id }}\"\n}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "29a4122f-0112-4157-a50d-0a6cf83ab7fd",
      "name": "フォルダを作成",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -920,
        0
      ],
      "parameters": {
        "name": "={{ \"invoices_\" + $json.body.startDate.split('T')[0] }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "xXHySx4T77sDdTqY",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "df86428f-7e63-4fd9-944c-f48af72af495",
      "name": "添付ファイルを集約",
      "type": "n8n-nodes-base.code",
      "position": [
        1200,
        -340
      ],
      "parameters": {
        "jsCode": "// \"items\" is the array coming from the previous node (14 items)\nconst merged = { json: {}, binary: {} };\n\nfor (const item of $input.all()) {\n  const data = {\n    [item.binary.data.fileName]: item.binary.data\n  };\n  Object.assign(merged.binary, data); // copy every file property\n}\n\nreturn [merged];     // one single item goes out"
      },
      "typeVersion": 2
    },
    {
      "id": "72a21bfa-6e3b-421a-a4ca-dea9e09a5b0b",
      "name": "請求書をメールで送信?",
      "type": "n8n-nodes-base.if",
      "position": [
        1000,
        -320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "63caf3d8-39bd-4300-aa7e-8c0ecfc87576",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Configure').first().json.sendEmail }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bb038635-eb69-447b-a85b-e9c3caebfe3a",
      "name": "会計担当者に送信",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1360,
        -280
      ],
      "webhookId": "3ea4dac1-58fe-4d0e-811b-065ecaef77df",
      "parameters": {
        "sendTo": "test@example.com",
        "message": "Hello, here are my invoices and receipts.",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {
                "property": "={{ Object.keys($binary).join(',') }}"
              }
            ]
          }
        },
        "subject": "={{ \n  (() => {\n    const startDate = $node['Webhook'].json.body.startDate.split('T')[0];\n    const endDate = $node['Webhook'].json.body.endDate.split('T')[0];\n    return `Dokumenty kosztowe za okres od ${startDate} do ${endDate}`;\n  })() \n}}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "PPgHF95PrpAMBlbG",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "7b2e5c6c-0a95-4347-97a9-c9ffbc0e3af2",
      "name": "添付ファイル付きメールを取得",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -500,
        0
      ],
      "webhookId": "6e2ca9f7-6d22-4d94-86bc-8a299bc8e752",
      "parameters": {
        "simple": false,
        "filters": {
          "q": "has:attachment",
          "sender": "",
          "receivedAfter": "={{ $('Webhook').item.json.body.startDate }}",
          "receivedBefore": "={{ $('Webhook').item.json.body.endDate }}"
        },
        "options": {
          "downloadAttachments": true,
          "dataPropertyAttachmentsPrefixName": "attachment_"
        },
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "PPgHF95PrpAMBlbG",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "6d5b2c1b-657d-44bf-980d-fd428fd8d832",
      "name": "PDFメール添付ファイルを読み取り",
      "type": "n8n-nodes-base.readPDF",
      "onError": "continueErrorOutput",
      "position": [
        120,
        -80
      ],
      "parameters": {},
      "notesInFlow": false,
      "typeVersion": 1
    },
    {
      "id": "3166f45c-306f-483a-b2c6-6768abc916a0",
      "name": "添付ファイルはPDF?",
      "type": "n8n-nodes-base.if",
      "position": [
        -40,
        0
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $binary.data.fileExtension }}",
              "value2": "pdf"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "866b286a-7b9b-4506-aa6b-d2049b249991",
      "name": "メールのオプションフィルター",
      "type": "n8n-nodes-base.filter",
      "position": [
        -360,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "687c4cd0-ada5-4dc1-8707-1a9c3b551251",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.to.value[0].address }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "56133dba-bc93-4f65-be42-995164a45c03",
      "name": "付箋",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        -340
      ],
      "parameters": {
        "width": 440,
        "height": 880,
        "content": "## Gmail PDF Invoice/Receipt Classifier & Google Drive Uploader (via n8n & OpenAI)\n\n_**DISCLAIMER**: AI classification isn't perfect. Always double-check that the correct documents were identified and uploaded._\n\nThis n8n workflow, triggered via a webhook, scans your Gmail for emails within a specified date range, extracts PDF attachments, and uses OpenAI to determine if each PDF matches a defined category (defaulting to \"receipt or invoice\"). Matched PDFs are then uploaded to a uniquely named Google Drive folder based on the date range. You can customize the classification term (e.g., change \"receipt or invoice\" to \"contract\") and optionally have the workflow email the collected PDFs to a specified address.\n\n### How it works\n1.  Triggers via a `Webhook` receiving a start date, end date, and an optional flag to send an email.\n2.  Creates a dated folder in `Google Drive` (e.g., `invoices_YYYY-MM-DD_YYYY-MM-DD`).\n3.  Fetches emails with attachments from `Gmail` within the specified date range.\n4.  Iterates through each attachment, filtering specifically for `PDF` files.\n5.  Extracts text from each PDF (skipping if the text exceeds token limits set in the `Configure` node).\n6.  Uses the `OpenAI` node to ask if the PDF content and filename look like the item defined in the `Configure` node's \"Match on\" field (e.g., \"receipt or invoice\").\n7.  If OpenAI responds with \"true\", the original `PDF` file is uploaded to the `Google Drive` folder created in step 2.\n8.  If the initial webhook request included the flag to send an email, it aggregates all successfully matched PDFs and sends them via `Gmail` to the address specified in the `Configure` node.\n\nWorkflow written by [Tom](https://browsewiz.com)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "aa5d8126-e2ec-4476-886d-c46379f1c6e2",
      "name": "付箋1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -780,
        -40
      ],
      "parameters": {
        "width": 260,
        "height": 1000,
        "content": "## Parameters\n\n\n\n\n\n\n\n\n\n* **`maxTokenSize`** (Number)\n    *   **Limits PDF text length** (estimated input tokens) sent to OpenAI for classification. Prevents errors/high costs on long documents.\n    *   *Default: 8000*\n\n*   **`replyTokenSize`** (Number)\n    *   **Reserves tokens for OpenAI's reply** ('true'/'false'). Ensures total tokens stay within limits.\n    *   *Default: 50*\n\n*   **`Match on`** (String)\n    *   **The keyword/phrase OpenAI uses** to identify the desired document type (e.g., \"receipt or invoice\", \"contract\"). Defines what you're searching for.\n    *   *Default: \"receipt or invoice\"*\n\n*   **`sendInvoicesTo`** (String)\n    *   **Recipient email address** for the final collection of matched PDFs. Used only if `sendEmail` is true.\n    *   *Example: \"accounting@example.com\"*\n\n*   **`sendEmail`** (Boolean)\n    *   **Turns the final email step on (`true`) or off (`false`)**. Set via the initial webhook trigger. If false, files are only uploaded to Drive.\n    *   *Example: `true` or `false`*"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "a0a8895c-ef8b-44e7-9294-1bcf629d0973": {
      "main": [
        [
          {
            "node": "7565118a-6d44-4583-a19f-cb4177378d33",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c84f3a9a-66b3-4a09-b06a-9b399ea574b8": {
      "main": [
        [
          {
            "node": "a0a8895c-ef8b-44e7-9294-1bcf629d0973",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7681eb62-ba86-4c89-9b88-3ce6fc438bd4": {
      "main": [
        [
          {
            "node": "29a4122f-0112-4157-a50d-0a6cf83ab7fd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ea1fbc5b-1859-4d65-8401-30baa95fcc52": {
      "main": [
        [
          {
            "node": "7b2e5c6c-0a95-4347-97a9-c9ffbc0e3af2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7565118a-6d44-4583-a19f-cb4177378d33": {
      "main": [
        [
          {
            "node": "074ffb7a-f83e-44b8-84fe-7b85f7245bb0",
            "type": "main",
            "index": 0
          },
          {
            "node": "72a21bfa-6e3b-421a-a4ca-dea9e09a5b0b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "29a4122f-0112-4157-a50d-0a6cf83ab7fd": {
      "main": [
        [
          {
            "node": "ea1fbc5b-1859-4d65-8401-30baa95fcc52",
            "type": "main",
            "index": 0
          },
          {
            "node": "aab3d940-55c2-40d3-917a-83412d4e378d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3166f45c-306f-483a-b2c6-6768abc916a0": {
      "main": [
        [
          {
            "node": "6d5b2c1b-657d-44bf-980d-fd428fd8d832",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "3e638471-c1c5-4bab-aa2a-12a1777225ec",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "df86428f-7e63-4fd9-944c-f48af72af495": {
      "main": [
        [
          {
            "node": "bb038635-eb69-447b-a85b-e9c3caebfe3a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "bb038635-eb69-447b-a85b-e9c3caebfe3a": {
      "main": [
        []
      ]
    },
    "074ffb7a-f83e-44b8-84fe-7b85f7245bb0": {
      "main": [
        []
      ]
    },
    "72a21bfa-6e3b-421a-a4ca-dea9e09a5b0b": {
      "main": [
        [
          {
            "node": "df86428f-7e63-4fd9-944c-f48af72af495",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "866b286a-7b9b-4506-aa6b-d2049b249991": {
      "main": [
        [
          {
            "node": "3ee63612-c1e7-40e6-a38f-f77f5ee3efa4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6d5b2c1b-657d-44bf-980d-fd428fd8d832": {
      "main": [
        [
          {
            "node": "b5af902b-2d59-49ee-b6d8-e387c59b89fd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7b2e5c6c-0a95-4347-97a9-c9ffbc0e3af2": {
      "main": [
        [
          {
            "node": "866b286a-7b9b-4506-aa6b-d2049b249991",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b5af902b-2d59-49ee-b6d8-e387c59b89fd": {
      "main": [
        [
          {
            "node": "c84f3a9a-66b3-4a09-b06a-9b399ea574b8",
            "type": "main",
            "index": 0
          },
          {
            "node": "a0a8895c-ef8b-44e7-9294-1bcf629d0973",
            "type": "main",
            "index": 1
          }
        ],
        []
      ]
    },
    "3ee63612-c1e7-40e6-a38f-f77f5ee3efa4": {
      "main": [
        [
          {
            "node": "3166f45c-306f-483a-b2c6-6768abc916a0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

上級 - 財務, 人工知能, IT運用

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
上級
ノード数20
カテゴリー3
ノードタイプ13
難易度説明

上級者向け、16ノード以上の複雑なワークフロー

作成者

Software Engineer and Architect for well over 10 years. Chromium project expert. Full Stack beast. Workflow automation enthusiast. Founder of BrowseWiz: in-browser AI assistant and AI agent platform with human in-the-loop.

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34