This workflow follows the Airtable → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "BookLeaf Cover Validation Pipeline",
"nodes": [
{
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"value": "={{$json.folderId}}",
"mode": "id"
},
"event": "fileCreated",
"options": {}
},
"id": "node-google-drive-trigger",
"name": "\ud83d\udcc1 Google Drive Trigger",
"type": "n8n-nodes-base.googleDriveTrigger",
"typeVersion": 1,
"position": [
240,
300
],
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"notes": "Watches the 'BookLeaf Covers' folder for new uploaded files (PDF or PNG). Set the folder ID in credentials after importing."
},
{
"parameters": {
"operation": "download",
"fileId": {
"__rl": true,
"value": "={{$json.id}}",
"mode": "id"
},
"options": {}
},
"id": "node-download-file",
"name": "\u2b07\ufe0f Download File from Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
460,
300
],
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"notes": "Downloads the file binary from Google Drive so we can send it to FastAPI."
},
{
"parameters": {
"method": "POST",
"url": "http://host.docker.internal:5001/validate",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "file",
"inputDataFieldName": "data"
},
{
"name": "author_name",
"value": "={{$('\ud83d\udcc1 Google Drive Trigger').item.json.name.split('_')[0]}}"
},
{
"name": "author_email",
"value": ""
}
]
},
"options": {
"timeout": 120000,
"response": {
"response": {
"fullResponse": false
}
}
}
},
"id": "node-validate-api",
"name": "\ud83e\udd16 FastAPI Validate Cover",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
680,
300
],
"notes": "Sends the file to our Python backend. Timeout set to 120s to allow for OCR processing time."
},
{
"parameters": {
"jsCode": "// Parse the API response and look up author info from ISBN\nconst result = $input.item.json;\nconst filename = $('\ud83d\udcc1 Google Drive Trigger').item.json.name;\n\n// ISBN-to-author mapping (edit this to match your real author database)\n// In production this would be a Airtable lookup\nconst ISBN_MAP = {\n '9789898652364': { name: 'Benny James SDB', email: 'benny@example.com' },\n '9789373145068': { name: 'Ojal Jain', email: 'ojal@example.com' },\n '9789898652616': { name: 'Parisha Shodhan', email: 'parisha@example.com' },\n '9789373147994': { name: 'Benny James SDB', email: 'benny@example.com' },\n '9789373147765': { name: 'Pratik Kolekar', email: 'pratik@example.com' },\n '9789898652753': { name: 'Pulak Das', email: 'pulak@example.com' },\n};\n\nconst isbn = result.isbn || 'UNKNOWN';\nconst authorInfo = ISBN_MAP[isbn] || { name: 'Author', email: 'noreply@bookleaf.com' };\n\n// Build the full Drive file URL\nconst driveFileId = $('\ud83d\udcc1 Google Drive Trigger').item.json.id;\nconst driveUrl = `https://drive.google.com/file/d/${driveFileId}/view`;\n\nreturn {\n ...result,\n author_name: authorInfo.name,\n author_email: authorInfo.email,\n drive_file_url: driveUrl,\n filename: filename,\n // Format issues for Airtable multi-select\n issue_types_list: [...new Set(result.issues.map(i => i.type))].join(', ') || 'NONE',\n issue_severity: result.issues.some(i => i.severity === 'CRITICAL') ? 'CRITICAL' : \n result.issues.length > 0 ? 'WARNING' : 'NONE',\n // Truncate correction instructions for Airtable (max 100k chars)\n corrections_short: result.correction_instructions.substring(0, 5000),\n};"
},
"id": "node-enrich-data",
"name": "\ud83d\udd27 Enrich & Parse Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
],
"notes": "Parses API response, looks up author email from ISBN, formats data for Airtable."
},
{
"parameters": {
"operation": "create",
"base": {
"__rl": true,
"value": "AIRTABLE_BASE_ID",
"mode": "id"
},
"table": {
"__rl": true,
"value": "Cover Submissions",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"ISBN": "={{$json.isbn}}",
"Author Name": "={{$json.author_name}}",
"Author Email": "={{$json.author_email}}",
"Submission Date": "={{$('\ud83d\udcc1 Google Drive Trigger').item.json.createdTime}}",
"Detection Timestamp": "={{$json.detection_timestamp}}",
"Status": "={{$json.status}}",
"Confidence Score": "={{$json.confidence_score}}",
"Issue Type": "={{$json.issue_types_list}}",
"Issue Severity": "={{$json.issue_severity}}",
"Issues Detail": "={{JSON.stringify($json.issues)}}",
"Correction Instructions": "={{$json.corrections_short}}",
"Annotated Image URL": "={{$json.annotated_image_url}}",
"Original File URL": "={{$json.drive_file_url}}",
"Email Sent": false,
"Revision Count": 0,
"Filename": "={{$json.filename}}"
}
},
"options": {}
},
"id": "node-airtable-create",
"name": "\ud83d\uddc3\ufe0f Airtable: Create Record",
"type": "n8n-nodes-base.airtable",
"typeVersion": 2.1,
"position": [
1120,
300
],
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"notes": "Creates a new record in the 'Cover Submissions' table with all validation results."
},
{
"parameters": {
"sendTo": "={{$('\ud83d\udd27 Enrich & Parse Response').item.json.author_email}}",
"subject": "={{$('\ud83d\udd27 Enrich & Parse Response').item.json.status === 'PASS' ? '\u2705 Book Cover Approved' : '\u26a0\ufe0f Action Required'}} \u2013 ISBN {{ $('\ud83d\udd27 Enrich & Parse Response').item.json.isbn }}",
"emailType": "text",
"message": "={{$('\ud83d\udd27 Enrich & Parse Response').item.json.email_body}}",
"options": {
"ccList": "bookleaf-team@bookleaf.com",
"replyTo": "support@bookleaf.com"
}
},
"id": "node-gmail-send",
"name": "\ud83d\udce7 Gmail: Notify Author",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1340,
300
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"notes": "Sends personalized email to the author with PASS or REVIEW NEEDED notification."
},
{
"parameters": {
"operation": "update",
"base": {
"__rl": true,
"value": "AIRTABLE_BASE_ID",
"mode": "id"
},
"table": {
"__rl": true,
"value": "Cover Submissions",
"mode": "name"
},
"id": "={{$('\ud83d\uddc3\ufe0f Airtable: Create Record').item.json.id}}",
"columns": {
"mappingMode": "defineBelow",
"value": {
"Email Sent": true,
"Email Sent At": "={{new Date().toISOString()}}"
}
},
"options": {}
},
"id": "node-airtable-update",
"name": "\ud83d\uddc3\ufe0f Airtable: Mark Email Sent",
"type": "n8n-nodes-base.airtable",
"typeVersion": 2.1,
"position": [
1560,
300
],
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
},
"notes": "Updates the Airtable record to mark that the email was sent and record the timestamp."
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{$json.status}}",
"rightValue": "REVIEW NEEDED",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
}
},
"id": "node-status-check",
"name": "\ud83d\udd00 PASS or REVIEW NEEDED?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1120,
500
],
"notes": "Routes to different logging paths based on status. Both paths send email; this is for future conditional logic."
},
{
"parameters": {
"method": "POST",
"url": "http://host.docker.internal:5001/health",
"options": {}
},
"id": "node-error-handler",
"name": "\ud83d\udea8 Error: Log Failure",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
900,
500
],
"notes": "Catches errors from any upstream node and logs them. In production, this would send an admin alert email."
}
],
"connections": {
"\ud83d\udcc1 Google Drive Trigger": {
"main": [
[
{
"node": "\u2b07\ufe0f Download File from Drive",
"type": "main",
"index": 0
}
]
]
},
"\u2b07\ufe0f Download File from Drive": {
"main": [
[
{
"node": "\ud83e\udd16 FastAPI Validate Cover",
"type": "main",
"index": 0
}
]
]
},
"\ud83e\udd16 FastAPI Validate Cover": {
"main": [
[
{
"node": "\ud83d\udd27 Enrich & Parse Response",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udd27 Enrich & Parse Response": {
"main": [
[
{
"node": "\ud83d\uddc3\ufe0f Airtable: Create Record",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\uddc3\ufe0f Airtable: Create Record": {
"main": [
[
{
"node": "\ud83d\udce7 Gmail: Notify Author",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udce7 Gmail: Notify Author": {
"main": [
[
{
"node": "\ud83d\uddc3\ufe0f Airtable: Mark Email Sent",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": ""
},
"staticData": null,
"tags": [
"bookleaf",
"automation",
"cover-validation"
],
"triggerCount": 1,
"updatedAt": "2026-06-08T00:00:00.000Z",
"versionId": "1"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
airtableTokenApigmailOAuth2googleDriveOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
BookLeaf Cover Validation Pipeline. Uses googleDriveTrigger, googleDrive, httpRequest, airtable. Event-driven trigger; 9 nodes.
Source: https://github.com/Mani-Tejeswar/Automated-Book-Cover-Validation-System/blob/26ec2035f58ee521c074be3b2ac1842762c83b00/n8n/bookleaf_workflow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Recruiting agency. Uses typeformTrigger, airtable, httpRequest, googleDrive. Event-driven trigger; 36 nodes.
This N8N template demonstrates using Foxit's Extraction API to get information from an incoming document and then using Diffbot's APIs to turn the text into a list of organizations mentioned in the do
This automation template streamlines the process of capturing screenshots for multiple URLs. Instead of manually visiting each URL, taking a screenshot, and organizing the results, this workflow autom
Capture URL Screenshots from Google Sheets with ScreenshotOne & Save to Drive with Gmail Alerts. Uses httpRequest, googleSheets, googleDrive, googleDriveTrigger. Event-driven trigger; 9 nodes.
This workflow ingests proof-of-delivery and completion documents from Gmail or a webhook, extracts key fields with an OpenRouter vision model, reconciles them against Google Sheets dispatch data, arch