This workflow corresponds to n8n.io template #14856 — we link there as the canonical source.
This workflow follows the Agent → 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 →
{
"id": "tNOLOnPY0dAIq3wC",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Resume Screener(HR Automation)",
"tags": [],
"nodes": [
{
"id": "584caae3-044e-493a-ac70-6db4ea431c6b",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
176,
624
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4-turbo",
"cachedResultName": "gpt-4-turbo"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "9a392def-0ab3-4d3b-82dc-1ecd64bce03c",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1904,
-400
],
"parameters": {
"width": 928,
"height": 496,
"content": "## Workflow Overview & Setup Guide\nThis workflow automates the process of screening resumes using AI. It starts by fetching email drafts from Gmail that contain resume attachments. The attachments are formatted and validated to ensure they are usable files, specifically PDFs. Each file is processed individually, and its content is extracted as plain text.\n\nThe extracted resume text is then sent to an AI model, which analyzes candidate details such as skills, experience, and contact information. The AI also calculates a match score based on predefined job requirements. The response is parsed into structured JSON format for consistency.\n\nNext, the workflow evaluates the candidate using the match score. If the score meets or exceeds the defined threshold, the candidate is shortlisted and their details are sent to a Slack channel. If not, the candidate is marked as rejected.\n\nSetup steps:\n1. Connect your Gmail account to fetch drafts with attachments\n2. Configure OpenAI API credentials for AI analysis\n3. Connect Slack account for notifications\n4. Ensure resumes are in PDF format\n5. Adjust job requirements in AI prompt if needed\n\nThis workflow reduces manual screening effort and speeds up the hiring process efficiently.\n"
},
"typeVersion": 1
},
{
"id": "1909bf65-f0be-4679-941c-e6fbc7043d0c",
"name": "Fetch Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
-1648,
384
],
"parameters": {
"filters": {},
"operation": "getAll"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "cbb75e96-60a8-4620-ad83-c44bcad28f78",
"name": "Format Attachments",
"type": "n8n-nodes-base.function",
"position": [
-1424,
384
],
"parameters": {
"functionCode": "const attachments = items[0].binary || {};\n\nconst files = Object.keys(attachments).map(key => {\n return {\n json: {\n fileName: key\n },\n binary: {\n data: attachments[key]\n }\n };\n});\n\nreturn files;"
},
"typeVersion": 1
},
{
"id": "fc0829f2-a829-44c0-8eaf-5cbed9d51ff2",
"name": "Check Attachments Exist",
"type": "n8n-nodes-base.if",
"position": [
-1200,
384
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{Object.keys($binary || {}).length > 0}}",
"value2": "={{ true }}"
}
]
}
},
"typeVersion": 1
},
{
"id": "7bf4f5c6-e1de-44b5-9484-ef09822eac37",
"name": "Process Each Attachment",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-864,
384
],
"parameters": {
"options": {},
"batchSize": 1
},
"typeVersion": 1
},
{
"id": "0bc95d8b-35a5-430f-86db-6e3ae27a4b86",
"name": "Validate PDF File",
"type": "n8n-nodes-base.if",
"position": [
-656,
384
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$binary.data.mimeType}}",
"value2": "application/pdf"
}
]
}
},
"typeVersion": 1
},
{
"id": "75bf5aeb-610e-4b49-bd72-7b42e95cddb9",
"name": "Extract Resume Text",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-272,
384
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "aaf1d2ac-5865-4363-b054-8f9fdf307ea1",
"name": "AI Resume Analyzer",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
176,
384
],
"parameters": {
"text": "=You are an expert HR assistant and resume parser.\n\nYour task is to extract structured information from resume text and evaluate the candidate against job requirements.\n\nYou MUST return ONLY valid JSON. No explanation, no markdown, no extra text.\n\n\n\nJOB REQUIREMENTS:\n- Skills: React Native, JavaScript, REST APIs, Git, Expo\n- Experience: 3+ years\n- Location: India (preferred)\n\nRESUME TEXT:\n{{ $json.text }}\n\n---\n\nINSTRUCTIONS:\n\n1. Extract the following fields:\n- full_name\n- email\n- phone\n- skills (array)\n- total_experience (in years, number)\n- current_company (if available)\n\n2. Match candidate skills with job requirements.\n\n3. Calculate a score out of 100 based on:\n- Skills match (50%)\n- Experience (30%)\n- Location relevance (20%)\n\n4. Decision:\n- If score >= 70 \u2192 \"SHORTLISTED\"\n- Else \u2192 \"REJECTED\"\n\n---\n\nOUTPUT FORMAT (STRICT JSON):\n\n{\n \"full_name\": \"\",\n \"email\": \"\",\n \"phone\": \"\",\n \"skills\": [],\n \"total_experience\": 0,\n \"current_company\": \"\",\n \"match_score\": 0,\n \"decision\": \"SHORTLISTED or REJECTED\",\n \"reason\": \"\"\n}",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "cf8226b3-a0ec-45ea-aa5e-9fa03c9751bb",
"name": "Parse AI Response",
"type": "n8n-nodes-base.code",
"position": [
480,
384
],
"parameters": {
"jsCode": "return items.map(item => {\n let raw = item.json.output;\n\n try {\n // Step 1: Clean string (remove line breaks)\n raw = raw.replace(/\\\\n/g, '');\n\n // Step 2: Parse JSON string\n const parsed = JSON.parse(raw);\n\n return {\n json: parsed\n };\n\n } catch (err) {\n return {\n json: {\n success: false,\n error: \"JSON_PARSE_ERROR\",\n raw_output: item.json.output\n }\n };\n }\n});"
},
"typeVersion": 2
},
{
"id": "53ba0675-ecaa-46a1-8d7e-aceace3c25a2",
"name": "Evaluate Candidate Score",
"type": "n8n-nodes-base.if",
"position": [
928,
384
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.match_score }}",
"value2": 70,
"operation": "largerEqual"
}
]
}
},
"typeVersion": 1
},
{
"id": "dd3d6690-bca9-4c7d-8cfb-fa05b2196a1a",
"name": "Send Shortlisted to Slack",
"type": "n8n-nodes-base.slack",
"position": [
1536,
368
],
"parameters": {
"text": "=Candidate Shortlisted\n\nName: {{ $json.full_name }}\nEmail: {{ $json.email }}\nPhone: {{ $json.phone }}\n\nCurrent Company: {{ $json.current_company }}\nExperience: {{ $json.total_experience }} years\n\nSkills: {{ $json.skills.join(\", \") }}\n\nMatch Score: {{ $json.match_score }}%\n\nReason: {{ $json.reason }}\n\nStatus: SHORTLISTED\nReady for next round of evaluation/interview",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0ALTQD6L0H",
"cachedResultName": "feature-addition"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "72451af3-e284-486f-9d6f-ef2cd2f37073",
"name": "Mark as Rejected",
"type": "n8n-nodes-base.set",
"position": [
1536,
592
],
"parameters": {
"values": {
"string": [
{
"name": "status",
"value": "Rejected candidate"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "715f2534-55f0-4473-b186-c6351fd40469",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1920,
208
],
"parameters": {
"color": 7,
"width": 896,
"height": 432,
"content": "## Fetch and Prepare Resume Files\nThis section retrieves email drafts from Gmail and prepares attachments for processing. It ensures all attached files are structured properly and checks whether attachments exist before moving forward. This helps in filtering only relevant emails that contain resume files for further evaluation."
},
"typeVersion": 1
},
{
"id": "9150f935-748f-4220-9fb7-037570cb8b84",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-928,
192
],
"parameters": {
"color": 7,
"width": 448,
"height": 448,
"content": "## Process and Validate Resume Files\nThis section handles multiple attachments by splitting them into individual items. It validates whether each file is a PDF and ensures only supported resume formats are processed. This step prevents errors and guarantees that only valid resume files proceed to text extraction."
},
"typeVersion": 1
},
{
"id": "8c602ea8-5cde-4822-9eb2-0eb19dfbe31c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-384,
192
],
"parameters": {
"color": 7,
"width": 368,
"height": 448,
"content": "## Extract Resume Content\nThis section extracts readable text from PDF resumes. The extracted content is essential for AI analysis. It converts unstructured resume files into plain text format, enabling further processing like data extraction, skill matching, and candidate evaluation."
},
"typeVersion": 1
},
{
"id": "00373f58-a8e4-4138-afe3-437691f43e4f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
192
],
"parameters": {
"color": 7,
"width": 608,
"height": 592,
"content": "## Analyze Resume with AI\nThis section sends extracted resume text to an AI model for structured analysis. The AI extracts candidate details such as name, skills, and experience, and calculates a match score. The response is then cleaned and converted into proper JSON format for further decision-making."
},
"typeVersion": 1
},
{
"id": "403cc3f4-9e9c-42f3-bf96-6d6159a0eaf0",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
192
],
"parameters": {
"color": 7,
"width": 384,
"height": 448,
"content": "## Evaluate Candidate Eligibility\nThis section evaluates the candidate based on the AI-generated match score. It checks whether the score meets the required threshold. Based on the result, the workflow decides if the candidate should be shortlisted or rejected for further processing."
},
"typeVersion": 1
},
{
"id": "c2dd667a-835f-4da4-95e8-728e7f2abcd3",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1296,
192
],
"parameters": {
"color": 7,
"width": 544,
"height": 608,
"content": "## Send Results and Final Status\nThis section handles the final outcome of the evaluation. Shortlisted candidates are sent to Slack with detailed information, including skills and match score. Rejected candidates are marked accordingly. This ensures clear communication and proper tracking of candidate status."
},
"typeVersion": 1
},
{
"id": "118ad8f9-4af8-43dc-b8b6-d66d2b45d06f",
"name": "Start Workflow Manually",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1872,
384
],
"parameters": {},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "db6caaf6-1fd4-4570-95a5-3922a0888f44",
"connections": {
"Fetch Gmail": {
"main": [
[
{
"node": "Format Attachments",
"type": "main",
"index": 0
}
]
]
},
"Mark as Rejected": {
"main": [
[]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Resume Analyzer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Parse AI Response": {
"main": [
[
{
"node": "Evaluate Candidate Score",
"type": "main",
"index": 0
}
]
]
},
"Validate PDF File": {
"main": [
[
{
"node": "Extract Resume Text",
"type": "main",
"index": 0
}
]
]
},
"AI Resume Analyzer": {
"main": [
[
{
"node": "Parse AI Response",
"type": "main",
"index": 0
}
]
]
},
"Format Attachments": {
"main": [
[
{
"node": "Check Attachments Exist",
"type": "main",
"index": 0
}
]
]
},
"Extract Resume Text": {
"main": [
[
{
"node": "AI Resume Analyzer",
"type": "main",
"index": 0
}
]
]
},
"Check Attachments Exist": {
"main": [
[
{
"node": "Process Each Attachment",
"type": "main",
"index": 0
}
]
]
},
"Process Each Attachment": {
"main": [
[
{
"node": "Validate PDF File",
"type": "main",
"index": 0
}
]
]
},
"Start Workflow Manually": {
"main": [
[
{
"node": "Fetch Gmail",
"type": "main",
"index": 0
}
]
]
},
"Evaluate Candidate Score": {
"main": [
[
{
"node": "Send Shortlisted to Slack",
"type": "main",
"index": 0
}
],
[
{
"node": "Mark as Rejected",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
gmailOAuth2openAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically fetches resumes from Gmail, extracts text from PDF attachments, analyzes candidate profiles using AI, and shortlists qualified candidates by sending their details to Slack. It significantly reduces manual effort in resume screening and speeds up…
Source: https://n8n.io/workflows/14856/ — 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.
My workflow 250630. Uses httpRequest, lmChatOpenAi, outputParserStructured, gmail. Event-driven trigger; 37 nodes.
This workflow automates legal policy governance for legal teams, policy managers, and compliance officers, eliminating manual document review, approval classification, and multi-channel stakeholder di
Streamline customer support with a real-time, AI-powered answer engine that detects incoming support emails, classifies intent, identifies the customer’s GEO region, and generates a tailored reply rea
Send a message or a voice note on Telegram right after the meeting. n8n transcribes (if it's a voice note) and sends the text to GPT. GPT generates a structured and professional meeting minutes report
Monitors your AP inbox for incoming invoices, extracts structured data with AI, runs duplicate and vendor history checks against Supabase, then scores each invoice for fraud risk — routing suspicious