Extraire et classer les factures et reçus avec Gmail, OpenAI et Google Drive

Avancé

Ceci est unFinance, AI, IT Opsworkflow d'automatisation du domainecontenant 20 nœuds.Utilise principalement des nœuds comme If, Set, Code, Gmail, Merge, combinant la technologie d'intelligence artificielle pour une automatisation intelligente. Extraire et classer les factures et les reçus avec Gmail, OpenAI et Google Drive

Prérequis
  • Compte Google et informations d'identification Gmail API
  • Point de terminaison HTTP Webhook (généré automatiquement par n8n)
  • Informations d'identification Google Drive API
  • Clé API OpenAI
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "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": "Configurer",
      "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": "Itérer sur les pièces jointes d'e-mails",
      "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": "Pas un PDF",
      "type": "n8n-nodes-base.noOp",
      "position": [
        120,
        80
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b5af902b-2d59-49ee-b6d8-e387c59b89fd",
      "name": "Le texte est-il dans la limite de tokens ?",
      "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": "Fusionner",
      "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": "Est correspondant",
      "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": "Téléverser le fichier vers le dossier",
      "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": "Répondre à 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": "Créer un dossier",
      "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": "Agréger les pièces jointes",
      "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": "Envoyer un e-mail avec les factures ?",
      "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": "Envoyer à mon comptable",
      "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": "Obtenir les e-mails avec pièces jointes",
      "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": "Lire les pièces jointes PDF des e-mails",
      "type": "n8n-nodes-base.readPDF",
      "onError": "continueErrorOutput",
      "position": [
        120,
        -80
      ],
      "parameters": {},
      "notesInFlow": false,
      "typeVersion": 1
    },
    {
      "id": "3166f45c-306f-483a-b2c6-6768abc916a0",
      "name": "La pièce jointe est-elle un 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": "Filtre optionnel pour les e-mails",
      "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": "Note adhésive",
      "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": "Note adhésive 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
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Finance, Intelligence Artificielle, Opérations IT

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds20
Catégorie3
Types de nœuds13
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Auteur

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.

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34