โ† All Developer Tools Workflows
BillionVerifyOcrspace

Extract text from Google Drive images with OCR.space, OpenRouter AI summary to sheets & Gmail

Pull contacts, verify each address with BillionVerify, and continue to OCR.space โ€” only deliverable addresses get through.

Why verify before the send

Sending to invalid, risky, catch-all, or disposable addresses spikes your bounce rate and erodes sender reputation. A verification gate before the OCR.space step removes that risk automatically โ€” only deliverable addresses continue, the rest are flagged.

The workflow

BillionVerify โ€” verification sits right before the send.

+7
n8n steps
+3
n8n steps

Node by node

  1. 1
    OpenRouter Chat Model1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  2. 2
    Google Drive New File Trigger1Triggerยท n8n

    Starts the workflow โ€” on a schedule, a webhook, or manually while you test.

  3. 3
    Download Image File1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  4. 4
    Extract Text with OCR.space1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  5. 5
    Format OCR Result & Check for Empty1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  6. 6
    Generate Summary with OpenRouter AI1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  7. 7
    Append row in sheet1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

  8. 8
    Verify Email (BillionVerify)Verifyยท billionverify

    The BillionVerify node verifies the address โ€” status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score โ€” before anything is sent.

  9. 9
    IF deliverableLogicยท n8n

    Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.

  10. 10
    Send Completion Notification via Gmail1Sendยท n8n

    Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.

  11. 11
    Process Completed1Sourceยท n8n

    Provides or transforms the contact data flowing through the workflow.

Workflow JSON

Copy or download this workflow, then import it in n8n (Workflows โ†’ Import from File / Paste). Install the BillionVerify community node first, then add your API key credential.

verify-emails-in-ocrspace.json
{
  "name": "Extract text from Google Drive images with OCR.space, OpenRouter AI summary to sheets & Gmail + BillionVerify",
  "nodes": [
    {
      "id": "14484c3d-1f78-45b1-a778-48b9d7ac1eee",
      "name": "OpenRouter Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        880,
        336
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "id": "credential-id",
          "name": "openRouterApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b8538a4f-9319-46b6-be09-5e343850d1dc",
      "name": "Append row in sheet1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1312,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "ๅ‡ฆ็†ๆ—ฅ": "={{ $now.toISO().split('T')[0] }}",
            "่ฆ็ด„็ตๆžœ": "={{ $('Generate Summary with OpenRouter AI1').first().json.output }}",
            "ใƒ•ใ‚กใ‚คใƒซๅ": "={{ $('Format OCR Result & Check for Empty1').first().json.fileName }}"
          },
          "schema": [
            {
              "id": "ใƒ•ใ‚กใ‚คใƒซๅ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "ใƒ•ใ‚กใ‚คใƒซๅ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "่ฆ็ด„็ตๆžœ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "่ฆ็ด„็ตๆžœ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ๅ‡ฆ็†ๆ—ฅ",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "ๅ‡ฆ็†ๆ—ฅ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/11BmQnKfY4MmCD4iwlvOFUZPAM6kGMWdny8MefHzE2_0/edit#gid=0",
          "cachedResultName": "่ฆ็ด„"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "11BmQnKfY4MmCD4iwlvOFUZPAM6kGMWdny8MefHzE2_0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/11BmQnKfY4MmCD4iwlvOFUZPAM6kGMWdny8MefHzE2_0/edit?usp=drivesdk",
          "cachedResultName": "็”ปๅƒ่ฆ็ด„่จ˜้Œฒ"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "11238230-9772-4fce-a3b9-b1c3a3cfffd1",
      "name": "Google Drive New File Trigger1",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        -48,
        160
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "1jTs0NNXMFTcChRq0C1KEoARVdIOOjQ1r",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1jTs0NNXMFTcChRq0C1KEoARVdIOOjQ1r",
          "cachedResultName": "ใ‚คใƒกใƒผใ‚ธใƒ•ใ‚กใ‚คใƒซ"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b31e181b-5ee1-4008-b3c9-541f3b3e65b8",
      "name": "Download Image File1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        224,
        160
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {
          "binaryPropertyName": "data"
        },
        "operation": "download"
      },
      "typeVersion": 3
    },
    {
      "id": "dd60b9e0-1bfc-4ce3-9e2a-86a5582b1dac",
      "name": "Extract Text with OCR.space1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        496,
        160
      ],
      "parameters": {
        "url": "https://api.ocr.space/parse/image",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "name": "apikey",
              "value": "*****APIKEY*****"
            },
            {
              "name": "language",
              "value": "jpn"
            },
            {
              "name": "isOverlayRequired",
              "value": "false"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "74bc17b2-2556-4a8e-b331-fe5fee94a711",
      "name": "Format OCR Result & Check for Empty1",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        160
      ],
      "parameters": {
        "jsCode": "const raw = $input.first()?.json?.ParsedResults?.[0]?.ParsedText || '';\nconst text = String(raw).replace(/\\r/g, ' ').replace(/\\n+/g, ' ').replace(/\\s{2,}/g, ' ').trim();\nconst fileName = $('Download Image File1').first()?.json?.name || 'unknown';\nreturn [{ json: { extractedText: text, fileName: fileName, hasText: text.length > 0 } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "82e9b60c-eaba-434e-ba0d-3f41ed0bbcf8",
      "name": "Generate Summary with OpenRouter AI1",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        960,
        160
      ],
      "parameters": {
        "text": "=ไปฅไธ‹ใฎๆ–‡็ซ ใ‚’็ฐกๆฝ”ใซ่ฆ็ด„ใ—ใฆใใ ใ•ใ„๏ผš\n{{ \n  $if(\n    $('Format OCR Result & Check for Empty1').first()?.json?.extractedText, \n    $('Format OCR Result & Check for Empty1').first().json.extractedText, \n    \"๏ผˆใƒ†ใ‚ญใ‚นใƒˆใŒ่ฆ‹ใคใ‹ใ‚Šใพใ›ใ‚“ใงใ—ใŸ๏ผ‰\"\n  ) \n}}",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "bba8e569-d625-476f-869d-e3c5c39f166b",
      "name": "Send Completion Notification via Gmail1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1584,
        160
      ],
      "webhookId": "66c7ac47-8411-437c-8132-f89b024f7e09",
      "parameters": {
        "sendTo": " user@example.com",
        "message": "=็”ปๅƒใƒ•ใ‚กใ‚คใƒซใ€Œ{{ $('Format OCR Result & Check for Empty1').first().json.fileName }}ใ€ใฎOCRๅ‡ฆ็†ใŒๅฎŒไบ†ใ—ใพใ—ใŸใ€‚\n\nใ€่ฆ็ด„ใ€‘\n{{ $('Generate Summary with OpenRouter AI1').first().json.message.content }}\n\nใ€Google Docsใ€‘\nๆ–ฐ่ฆใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ไฝœๆˆใ—ใพใ—ใŸใ€‚\nใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆID: {{ $('Google Docs ใธ่ฆ็ด„ใ‚’่ฟฝ่จ˜').first().json.documentId }}",
        "options": {},
        "subject": "=OCRๅ‡ฆ็†ๅฎŒไบ†: {{ $('Format OCR Result & Check for Empty1').first().json.fileName }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d0cacb65-5059-4def-bb53-9f0026938075",
      "name": "Process Completed1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1872,
        160
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "7c8f33d6-080b-4a16-b7df-d389c1b65b37",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        -496
      ],
      "parameters": {
        "width": 480,
        "height": 640,
        "content": "## Overview: Auto OCR โ†’ AI Summary โ†’ Google Sheets & Gmail\n\n## How it works\n\nThis workflow automatically processes any new image uploaded to a specific Google Drive folder.\nIt extracts text using OCR.space, summarizes the content with OpenRouter AI, and logs the result to Google Sheets.\nFinally, it sends a completion email via Gmail including the file name, summary, and document link.\nThis automation is ideal for digitizing book pages, lecture notes, or printed reports with minimal manual effort.\n\n## Setup steps\n\nConnect your Google Drive, OpenRouter, Google Sheets, and Gmail credentials.\n\nSet the target folder in Google Drive Trigger (where new images are uploaded).\n\nInsert your OCR.space API key in the HTTP Request node.\n\nUpdate the destination Google Sheets document and sheet name.\n\nAdjust the recipient email address in the Gmail notification node.ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€ใ€€"
      },
      "typeVersion": 1
    },
    {
      "id": "6a7a6bfa-3a55-4348-b87c-303ef20a91ee",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -160
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "### Section 1 ? Detect & Download Image\n\n  Google Drive Trigger โ†’ Download Image File\n\nMonitors a Drive folder and downloads new image files for OCR processing. (?40 words)"
      },
      "typeVersion": 1
    },
    {
      "id": "e8596db6-7332-4257-9863-1d4099879c61",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        -160
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "### Section 2 ? Extract & Clean Text\n\n  OCR.space API โ†’ Format OCR Result\n\nExtracts Japanese text from the image and removes unnecessary line breaks or spaces. (?35 words)"
      },
      "typeVersion": 1
    },
    {
      "id": "58a38290-9e3a-41c2-9a1b-b3c026eb9c00",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        448,
        -160
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "### Section 3 ? Summarize with AI\n\n  Generate Summary (OpenRouter AI)\n\nUses AI to summarize extracted text in concise Japanese for efficient reading. (?30 words)"
      },
      "typeVersion": 1
    },
    {
      "id": "696b9c8a-05e3-44bf-aff0-693d969178de",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        704,
        -160
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "### Section 4 ? Save to Google Sheets\n\n  Append row in sheet\n\nLogs the filename, AI-generated summary, and current date into a Google Sheet. (?25 words)"
      },
      "typeVersion": 1
    },
    {
      "id": "6b0c9994-a22f-41aa-968e-36a9adca53bd",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        -160
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "### Section 5 ? Notify via Gmail\n\n?? Send Completion Notification โ†’ Process Completed\n\nEmails the user with the OCR summary and Google Docs/Sheets information. (?25 words)"
      },
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "verify",
        "email": "={{ $json.email || $json.Email }}",
        "additionalOptions": {}
      },
      "type": "n8n-nodes-billionverify.billionVerify",
      "typeVersion": 1,
      "position": [
        1224,
        160
      ],
      "name": "Verify Email (BillionVerify)",
      "credentials": {
        "billionVerifyApi": {
          "id": "",
          "name": "BillionVerify account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-deliverable",
              "leftValue": "={{ $json.is_deliverable }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1404,
        160
      ],
      "name": "IF deliverable"
    }
  ],
  "connections": {
    "Append row in sheet1": {
      "main": [
        [
          {
            "node": "Verify Email (BillionVerify)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Image File1": {
      "main": [
        [
          {
            "node": "Extract Text with OCR.space1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Summary with OpenRouter AI1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Text with OCR.space1": {
      "main": [
        [
          {
            "node": "Format OCR Result & Check for Empty1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive New File Trigger1": {
      "main": [
        [
          {
            "node": "Download Image File1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format OCR Result & Check for Empty1": {
      "main": [
        [
          {
            "node": "Generate Summary with OpenRouter AI1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Summary with OpenRouter AI1": {
      "main": [
        [
          {
            "node": "Append row in sheet1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Completion Notification via Gmail1": {
      "main": [
        [
          {
            "node": "Process Completed1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Email (BillionVerify)": {
      "main": [
        [
          {
            "node": "IF deliverable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF deliverable": {
      "main": [
        [
          {
            "node": "Send Completion Notification via Gmail1",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

When to use this

  • Cleaning a list before a OCR.space send or sync.
  • Protecting OCR.space deliverability and sender reputation.
  • Keeping bounce rates low so your sending is never throttled.

FAQ

Why verify before sending in OCR.space?

Verifying first keeps your bounce rate low, which protects your sender reputation and your results.

How do I import this workflow?

Download the JSON, then in n8n go to Workflows โ†’ Import from File (or paste it). Install the BillionVerify community node and add your API key credential.

What happens to risky or catch-all addresses?

They are routed to the false branch and excluded from the send. You decide whether to retry, review, or drop them.

Add verification to your workflow

Create a free account, grab your API key, and stop bounces before they happen.

Get started free