AutomationFlowsEmail & Gmail › Automate Candidate Evaluation with Gpt-4 Scoring and Gmail Notifications

Automate Candidate Evaluation with Gpt-4 Scoring and Gmail Notifications

ByRodrigue Gbadou @gbadou on n8n.io

This comprehensive recruitment automation workflow transforms your hiring process from manual screening to intelligent candidate management. The system begins by automatically collecting CVs from multiple job boards and career platforms, immediately parsing each submission using…

Webhook trigger★★★★☆ complexity12 nodesHTTP RequestGmail
Email & Gmail Trigger: Webhook Nodes: 12 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #6071 — we link there as the canonical source.

This workflow follows the Gmail → HTTP Request 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 →

Download .json
{
  "nodes": [
    {
      "id": "1",
      "name": "CV Submission Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        240,
        300
      ],
      "parameters": {
        "path": "cv-received",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "2",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        140,
        180
      ],
      "parameters": {
        "width": 240,
        "height": 160,
        "content": "## Recruitment AI Config\n\n\u2699\ufe0f **Customize scoring:**\n- Technical skills weights\n- Experience requirements\n- Education priorities\n- Cultural fit criteria"
      },
      "typeVersion": 1
    },
    {
      "id": "3",
      "name": "Job Requirements",
      "type": "n8n-nodes-base.set",
      "position": [
        440,
        300
      ],
      "parameters": {
        "values": {
          "number": [
            {
              "name": "minExperience",
              "value": 5
            },
            {
              "name": "passingScore",
              "value": 75
            }
          ],
          "string": [
            {
              "name": "requiredSkills",
              "value": "JavaScript,React,Node.js,Python"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4",
      "name": "Parse CV with AI",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        640,
        300
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "body": {
          "model": "gpt-4",
          "messages": [
            {
              "role": "system",
              "content": "You are a CV parsing expert. Extract key information from CVs and return structured JSON data."
            },
            {
              "role": "user",
              "content": "Parse this CV and extract: name, email, phone, skills, experience_years, education, previous_roles. CV content: {{ $json.cv_content }}"
            }
          ],
          "response_format": {
            "type": "json_object"
          }
        },
        "method": "POST",
        "headers": {
          "Content-Type": "application/json",
          "Authorization": "Bearer {{ $credentials.openai.apiKey }}"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5",
      "name": "Score Candidate",
      "type": "n8n-nodes-base.code",
      "position": [
        840,
        300
      ],
      "parameters": {
        "jsCode": "// Intelligent candidate scoring algorithm\nconst candidate = $json.choices[0].message.content;\nconst requirements = $node['Job Requirements'].json;\nconst candidateData = JSON.parse(candidate);\n\nlet totalScore = 0;\n\n// Skills matching (40% weight)\nconst requiredSkills = requirements.requiredSkills.split(',');\nconst candidateSkills = candidateData.skills || [];\nconst skillsMatch = requiredSkills.filter(skill => \n  candidateSkills.some(cSkill => cSkill.toLowerCase().includes(skill.toLowerCase()))\n);\nconst skillsScore = (skillsMatch.length / requiredSkills.length) * 40;\ntotalScore += skillsScore;\n\n// Experience scoring (30% weight)\nconst experienceYears = candidateData.experience_years || 0;\nlet experienceScore = 0;\nif (experienceYears >= requirements.minExperience) {\n  experienceScore = 30;\n} else if (experienceYears >= requirements.minExperience * 0.8) {\n  experienceScore = 25;\n} else if (experienceYears >= requirements.minExperience * 0.6) {\n  experienceScore = 20;\n} else {\n  experienceScore = 10;\n}\ntotalScore += experienceScore;\n\n// Education scoring (20% weight)\nconst education = candidateData.education || '';\nlet educationScore = 0;\nif (education.toLowerCase().includes('master') || education.toLowerCase().includes('phd')) {\n  educationScore = 20;\n} else if (education.toLowerCase().includes('bachelor') || education.toLowerCase().includes('degree')) {\n  educationScore = 15;\n} else {\n  educationScore = 10;\n}\ntotalScore += educationScore;\n\n// Role relevance (10% weight)\nconst previousRoles = candidateData.previous_roles || [];\nconst roleRelevance = previousRoles.some(role => \n  role.toLowerCase().includes('engineer') || role.toLowerCase().includes('developer')\n) ? 10 : 5;\ntotalScore += roleRelevance;\n\n// Determine recommendation\nlet recommendation = 'reject';\nlet priority = 'low';\n\nif (totalScore >= 85) {\n  recommendation = 'hire';\n  priority = 'high';\n} else if (totalScore >= requirements.passingScore) {\n  recommendation = 'interview';\n  priority = 'medium';\n} else if (totalScore >= 60) {\n  recommendation = 'phone_screen';\n  priority = 'low';\n}\n\nreturn {\n  candidateData,\n  scoring: {\n    skillsScore,\n    experienceScore,\n    educationScore,\n    roleRelevance,\n    totalScore: Math.round(totalScore),\n    recommendation,\n    priority\n  },\n  jobTitle: requirements.jobTitle,\n  evaluatedAt: new Date().toISOString()\n};"
      },
      "typeVersion": 1
    },
    {
      "id": "6",
      "name": "Check If Top Candidate",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        200
      ],
      "parameters": {
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.scoring.recommendation }}",
              "rightValue": "hire"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7",
      "name": "Alert HR Team",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1240,
        100
      ],
      "parameters": {
        "sendTo": "={{ $node['Job Requirements'].json.hrEmail }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }\n    .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; }\n    .top-candidate { background: linear-gradient(45deg, #28a745, #20c997); color: white; padding: 20px; text-align: center; margin: 20px 0; border-radius: 10px; }\n    .candidate-info { background: #d4edda; padding: 15px; margin: 15px 0; border-radius: 5px; }\n    .score-breakdown { background: #f8f9fa; padding: 15px; margin: 15px 0; border-radius: 5px; }\n    .cta { background: #007bff; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; display: inline-block; margin: 20px 0; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"top-candidate\">\n      <h2>\ud83c\udf1f EXCEPTIONAL CANDIDATE</h2>\n      <p>High-priority candidate for {{ $json.jobTitle }}</p>\n    </div>\n    \n    <div class=\"candidate-info\">\n      <h3>\ud83d\udc64 Candidate Profile</h3>\n      <p><strong>Name:</strong> {{ $json.candidateData.name }}</p>\n      <p><strong>Email:</strong> {{ $json.candidateData.email }}</p>\n      <p><strong>Phone:</strong> {{ $json.candidateData.phone }}</p>\n      <p><strong>Experience:</strong> {{ $json.candidateData.experience_years }} years</p>\n      <p><strong>Education:</strong> {{ $json.candidateData.education }}</p>\n    </div>\n    \n    <div class=\"score-breakdown\">\n      <h3>\ud83d\udcca Scoring Breakdown</h3>\n      <p><strong>Overall Score:</strong> {{ $json.scoring.totalScore }}/100</p>\n      <p><strong>Skills Match:</strong> {{ $json.scoring.skillsScore }}/40</p>\n      <p><strong>Experience:</strong> {{ $json.scoring.experienceScore }}/30</p>\n      <p><strong>Education:</strong> {{ $json.scoring.educationScore }}/20</p>\n      <p><strong>Role Relevance:</strong> {{ $json.scoring.roleRelevance }}/10</p>\n    </div>\n    \n    <div style=\"text-align: center;\">\n      <a href=\"mailto:{{ $json.candidateData.email }}\" class=\"cta\">\ud83d\udce7 Contact Candidate</a>\n      <a href=\"https://calendly.com/interview-{{ $json.candidateData.name }}\" class=\"cta\">\ud83d\udcc5 Schedule Interview</a>\n    </div>\n    \n    <p style=\"color: #666; font-size: 14px; margin-top: 30px;\">\n      Recommendation: {{ $json.scoring.recommendation }} | Priority: {{ $json.scoring.priority }}\n    </p>\n  </div>\n</body>\n</html>",
        "options": {
          "contentType": "html"
        },
        "subject": "\ud83c\udf1f Top Candidate Alert - {{ $json.jobTitle }}"
      },
      "typeVersion": 1
    },
    {
      "id": "8",
      "name": "Check If Interview Worthy",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.scoring.recommendation }}",
              "rightValue": "interview"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "9",
      "name": "Send Interview Invitation",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1240,
        300
      ],
      "parameters": {
        "sendTo": "={{ $json.candidateData.email }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }\n    .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; }\n    .interview-invite { background: #007bff; color: white; padding: 20px; text-align: center; margin: 20px 0; border-radius: 8px; }\n    .next-steps { background: #e8f4f8; padding: 15px; margin: 15px 0; border-radius: 5px; }\n    .cta { background: #28a745; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; display: inline-block; margin: 20px 0; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"interview-invite\">\n      <h2>\ud83c\udf89 Interview Invitation</h2>\n      <p>Congratulations! We'd like to interview you for the {{ $json.jobTitle }} position.</p>\n    </div>\n    \n    <p>Dear {{ $json.candidateData.name }},</p>\n    \n    <p>We were impressed by your profile and would like to invite you for an interview.</p>\n    \n    <div class=\"next-steps\">\n      <h3>\ud83d\udcc5 Next Steps</h3>\n      <ul>\n        <li>Schedule your interview using the link below</li>\n        <li>Prepare for technical questions about your experience</li>\n        <li>Review our company culture and values</li>\n        <li>Prepare questions about the role and team</li>\n      </ul>\n    </div>\n    \n    <div style=\"text-align: center;\">\n      <a href=\"https://calendly.com/interview-{{ $json.candidateData.name }}\" class=\"cta\">\n        \ud83d\udcc5 Schedule Your Interview\n      </a>\n    </div>\n    \n    <p>Looking forward to meeting you!</p>\n    \n    <p style=\"color: #666; font-size: 14px; margin-top: 30px;\">\n      Best regards,<br>\n      HR Team\n    </p>\n  </div>\n</body>\n</html>",
        "options": {
          "contentType": "html"
        },
        "subject": "Interview Invitation - {{ $json.jobTitle }} Position"
      },
      "typeVersion": 1
    },
    {
      "id": "10",
      "name": "Check If Rejected",
      "type": "n8n-nodes-base.if",
      "position": [
        1040,
        400
      ],
      "parameters": {
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.scoring.recommendation }}",
              "rightValue": "reject"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "11",
      "name": "Send Rejection Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1240,
        400
      ],
      "parameters": {
        "sendTo": "={{ $json.candidateData.email }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n  <style>\n    body { font-family: Arial, sans-serif; margin: 20px; background-color: #f8f9fa; }\n    .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; }\n    .thank-you { background: #6c757d; color: white; padding: 20px; text-align: center; margin: 20px 0; border-radius: 8px; }\n    .feedback { background: #f8f9fa; padding: 15px; margin: 15px 0; border-radius: 5px; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <div class=\"thank-you\">\n      <h2>Thank You for Your Interest</h2>\n      <p>We appreciate you taking the time to apply for the {{ $json.jobTitle }} position.</p>\n    </div>\n    \n    <p>Dear {{ $json.candidateData.name }},</p>\n    \n    <p>Thank you for your application. While your background is impressive, we have decided to move forward with other candidates who more closely match our current requirements.</p>\n    \n    <div class=\"feedback\">\n      <h3>\ud83d\udca1 For Future Opportunities</h3>\n      <p>We encourage you to:</p>\n      <ul>\n        <li>Continue developing your technical skills</li>\n        <li>Gain more relevant experience in your field</li>\n        <li>Apply for future positions that match your expertise</li>\n      </ul>\n    </div>\n    \n    <p>We'll keep your resume on file and will reach out if a suitable position becomes available.</p>\n    \n    <p style=\"color: #666; font-size: 14px; margin-top: 30px;\">\n      Best regards,<br>\n      HR Team\n    </p>\n  </div>\n</body>\n</html>",
        "options": {
          "contentType": "html"
        },
        "subject": "Thank you for your application - {{ $json.jobTitle }}"
      },
      "typeVersion": 1
    },
    {
      "id": "12",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1140,
        60
      ],
      "parameters": {
        "width": 240,
        "height": 160,
        "content": "## AI-Powered Decisions\n\n\ud83e\udd16 **Automated actions:**\n- Top candidates: HR alert\n- Interview worthy: Auto-invite\n- Rejected: Polite decline\n- Phone screen: Initial contact"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Score Candidate": {
      "main": [
        [
          {
            "node": "Check If Top Candidate",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check If Interview Worthy",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check If Rejected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Job Requirements": {
      "main": [
        [
          {
            "node": "Parse CV with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse CV with AI": {
      "main": [
        [
          {
            "node": "Score Candidate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check If Rejected": {
      "main": [
        [
          {
            "node": "Send Rejection Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CV Submission Webhook": {
      "main": [
        [
          {
            "node": "Job Requirements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check If Top Candidate": {
      "main": [
        [
          {
            "node": "Alert HR Team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check If Interview Worthy": {
      "main": [
        [
          {
            "node": "Send Interview Invitation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This comprehensive recruitment automation workflow transforms your hiring process from manual screening to intelligent candidate management. The system begins by automatically collecting CVs from multiple job boards and career platforms, immediately parsing each submission using…

Source: https://n8n.io/workflows/6071/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

Receive booking requests via webhook with automatic validation, duplicate detection, availability checking, confirmation emails, Google Calendar sync, and Slack notifications.

HTTP Request, Gmail, Google Calendar +2
Email & Gmail

Automate short-term trading research by generating high-quality trade ideas using MCP (Market Context Protocol) signals and AI-powered analysis. 📈🤖 This workflow evaluates market context, catalysts, m

Slack, Asana, HTTP Request +4
Email & Gmail

Automate building visitor management with secure verification, digital entry passes, and real-time security notifications.

N8N Nodes Verifiemail, HTTP Request, N8N Nodes Htmlcsstopdf +2
Email & Gmail

Most service businesses and freelancers track their quotes in Airtable (or something similar), but when it comes to actually sending the quote, they're still manually copying data into a document, exp

Airtable, HTTP Request, Google Drive +1
Email & Gmail

This workflow is an automated invoice payment tracking and reminder system for the Polish accounting service iFirma.pl. It monitors unpaid and overdue invoices, then automatically sends escalating rem

HTTP Request, Stop And Error, Slack +1