Extraer y clasificar facturas y recibos usando Gmail, OpenAI y Google Drive

Avanzado

Este es unFinance, AI, IT Opsflujo de automatización del dominio deautomatización que contiene 20 nodos.Utiliza principalmente nodos como If, Set, Code, Gmail, Merge, combinando tecnología de inteligencia artificial para lograr automatización inteligente. Extraer y clasificar facturas y recibos con Gmail, OpenAI y Google Drive

Requisitos previos
  • Cuenta de Google y credenciales de API de Gmail
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Credenciales de API de Google Drive
  • Clave de API de OpenAI
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "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": "Configurar",
      "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": "Iterar sobre archivos adjuntos de correo",
      "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": "No es PDF",
      "type": "n8n-nodes-base.noOp",
      "position": [
        120,
        80
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b5af902b-2d59-49ee-b6d8-e387c59b89fd",
      "name": "¿El texto está dentro del límite 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": "Combinar",
      "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á coincidido?",
      "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": "Subir archivo a carpeta",
      "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": "Responder a 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": "Crear carpeta",
      "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": "Agregar archivos adjuntos",
      "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": "¿Enviar correo con facturas?",
      "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": "Enviar a mi contador",
      "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": "Obtener correos con archivos adjuntos",
      "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": "Leer archivos adjuntos PDF de correos",
      "type": "n8n-nodes-base.readPDF",
      "onError": "continueErrorOutput",
      "position": [
        120,
        -80
      ],
      "parameters": {},
      "notesInFlow": false,
      "typeVersion": 1
    },
    {
      "id": "3166f45c-306f-483a-b2c6-6768abc916a0",
      "name": "¿El archivo adjunto es 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": "Filtro opcional para correos",
      "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": "Nota adhesiva",
      "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": "Nota adhesiva1",
      "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
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Finanzas, Inteligencia Artificial, Operaciones de TI

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos20
Categoría3
Tipos de nodos13
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor

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.

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34