AutomationFlowsEmail & Gmail › Send Automated Recruitment Rejection Email at End-of-day (google Sheets | Gmail)

Send Automated Recruitment Rejection Email at End-of-day (google Sheets | Gmail)

ByWeblineIndia @weblineindia on n8n.io

Automatically reads a “Candidate Status” tab in Google Sheets every day at 18:00 Asia/Kolkata, filters rows with exact (case-sensitive) rejection statuses and sends one personalized rejection email per candidate via SMTP (Gmail). It rate-limits sends, supports DRY\_RUN previews…

Cron / scheduled trigger★★★★☆ complexity15 nodesGoogle SheetsGmail
Email & Gmail Trigger: Cron / scheduled Nodes: 15 Complexity: ★★★★☆ Added:

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

This workflow follows the Gmail → Google Sheets 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
{
  "id": "3bsNBJ5i1ylNYtKM",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automated Recruitment Rejection Emails with Google Sheets and Gmail at End-of-Day",
  "tags": [],
  "nodes": [
    {
      "id": "afba507f-8023-4c22-af01-d040e266d257",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 18 * * *"
            },
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0f99da8f-7974-4fed-986c-e1985d4ad486",
      "name": "Set: Config",
      "type": "n8n-nodes-base.set",
      "position": [
        220,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1e96273a-d891-44c4-b433-2a11840b8c63",
              "name": "SPREADSHEET_ID",
              "type": "string",
              "value": "1n_AIqOd10Q0ErQZSO4q4LBMekwgsR4cP7EW2q9nEzdk"
            },
            {
              "id": "0aae4a91-f153-4493-a9a8-9a2023e4f158",
              "name": "SOURCE_SHEET",
              "type": "string",
              "value": "Candidate Status"
            },
            {
              "id": "802cb08e-cfec-4a40-9236-afea62476136",
              "name": "TIMEZONE",
              "type": "string",
              "value": "Asia/Kolkata"
            },
            {
              "id": "708470ef-5283-4440-9db7-4bd9336ed468",
              "name": "REJECT_STATUS_CSV",
              "type": "string",
              "value": "Rejected"
            },
            {
              "id": "fbaed34b-a618-45ec-883c-7ee89dc2932f",
              "name": "SMTP_FROM",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "b3f745cb-b5d2-43e9-a7a1-803fc0646274",
              "name": "SUBJECT_TEMPLATE",
              "type": "string",
              "value": "Regarding your application for {{role}} at {{company_name}}"
            },
            {
              "id": "03bb79a9-6115-402d-a88a-de24bdaf6016",
              "name": "HTML_TEMPLATE",
              "type": "string",
              "value": "<p>Dear {{candidate_name}},</p><p>Thank you for your interest in the {{role}} position at {{company_name}} and for taking the time to interview with our team.</p><p>After careful consideration, we have decided to move forward with another candidate for this role. This decision was not easy, as we were impressed by your qualifications and experience.</p>{{feedback_html}}<p>We encourage you to apply for future opportunities that align with your skills and interests. We will keep your resume on file for consideration.</p><p>Thank you again for your time and interest in {{company_name}}.</p><p>Best regards,<br>{{recruiter_name}}<br>{{company_name}} Recruiting Team</p>"
            },
            {
              "id": "7fa7d589-8e71-4de4-80bc-fe8bd2c91f1f",
              "name": "TEXT_TEMPLATE",
              "type": "string",
              "value": "Dear {{candidate_name}},\\n\\nThank you for your interest in the {{role}} position at {{company_name}} and for taking the time to interview with our team.\\n\\nAfter careful consideration, we have decided to move forward with another candidate for this role. This decision was not easy, as we were impressed by your qualifications and experience.\\n\\n{{feedback_text}}\\n\\nWe encourage you to apply for future opportunities that align with your skills and interests. We will keep your resume on file for consideration.\\n\\nThank you again for your time and interest in {{company_name}}.\\n\\nBest regards,\\n{{recruiter_name}}\\n{{company_name}} Recruiting Team"
            },
            {
              "id": "881304fe-b862-4d6d-a4e5-8c774fcbb341",
              "name": "RATE_LIMIT_SECONDS",
              "type": "number",
              "value": 10
            },
            {
              "id": "4355e287-bbe4-4e82-a2bd-1cd086dc79db",
              "name": "INCLUDE_WEEKENDS",
              "type": "boolean",
              "value": true
            },
            {
              "id": "74a3dd62-e07d-4878-8ca6-ea6c5fc603d8",
              "name": "DRY_RUN",
              "type": "boolean",
              "value": false
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "504591fe-f969-41cc-87a2-b472916b0d52",
      "name": "Check Weekend Policy",
      "type": "n8n-nodes-base.if",
      "position": [
        420,
        -20
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "3f4bd624-1242-4949-a6dc-f1916a35998c",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.INCLUDE_WEEKENDS }}",
              "rightValue": true
            },
            {
              "id": "11590e43-b563-4652-ba39-c554bbdde5c8",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ [1, 2, 3, 4, 5].includes(new Date().getDay()) }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "da3d050e-cf10-474b-aced-685cdbff2eb8",
      "name": "Weekend Skip Message",
      "type": "n8n-nodes-base.set",
      "position": [
        640,
        80
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "957a03f9-9552-4023-af3b-a315f437ef92",
              "name": "message",
              "type": "string",
              "value": "Skipping execution - Weekend and INCLUDE_WEEKENDS is false"
            },
            {
              "id": "40645baf-356e-4a1f-964a-87248a29205b",
              "name": "timestamp",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ee2c781f-9147-4361-aef7-ed2206f51274",
      "name": "Filter Candidates for Rejection",
      "type": "n8n-nodes-base.code",
      "position": [
        920,
        -140
      ],
      "parameters": {
        "jsCode": "// Get configuration from the Set node\nconst config = $('Set: Config').item.json;\nconst rejectStatuses = config.REJECT_STATUS_CSV.split(',').map(s => s.trim());\n\n// Filter candidates that need rejection emails\nconst candidatesToEmail = [];\nconst skippedCandidates = [];\n\nfor (const item of $input.all()) {\n  const data = item.json;\n  \n  // Skip if no candidate email\n  if (!data.candidate_email || data.candidate_email.trim() === '') {\n    skippedCandidates.push({ reason: 'No email', data });\n    continue;\n  }\n  \n  // Skip if rejection already sent\n  if (data.rejection_sent_at && data.rejection_sent_at.trim() !== '') {\n    skippedCandidates.push({ reason: 'Already sent', data });\n    continue;\n  }\n  \n  // Check if status matches rejection criteria (case-sensitive)\n  if (!rejectStatuses.includes(data.status)) {\n    skippedCandidates.push({ reason: 'Status not in reject list', data });\n    continue;\n  }\n  \n  // Skip if missing required fields\n  if (!data.candidate_name || !data.role || !data.company_name || !data.recruiter_name) {\n    skippedCandidates.push({ reason: 'Missing required fields', data });\n    continue;\n  }\n  \n  candidatesToEmail.push(data);\n}\n\nconsole.log(`Found ${candidatesToEmail.length} candidates to email`);\nconsole.log(`Skipped ${skippedCandidates.length} candidates`);\n\n// Return the filtered candidates\nreturn candidatesToEmail.map(candidate => ({ json: candidate }));"
      },
      "typeVersion": 2
    },
    {
      "id": "ad8780bc-7ff2-490c-9c28-437d70002d0d",
      "name": "Is Dry Run?",
      "type": "n8n-nodes-base.if",
      "position": [
        1360,
        -227.38767390945867
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d47f5a55-07e4-4e27-96c5-ad18c94aa4f5",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $('Set: Config').item.json.DRY_RUN }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7b40df04-318a-4a0f-884f-071ea173e7e0",
      "name": "Dry Run Preview",
      "type": "n8n-nodes-base.code",
      "position": [
        1580,
        -316.6968033946768
      ],
      "parameters": {
        "jsCode": "// Dry run preview\nconst config = $('Set: Config').item.json;\nconst candidates = $input.all();\n\nconsole.log('DRY RUN MODE - Preview of emails to be sent:');\nconsole.log('='.repeat(50));\n\nfor (let i = 0; i < candidates.length; i++) {\n  const candidate = candidates[i].json;\n  \n  // Process subject template\n  let subject = config.SUBJECT_TEMPLATE\n    .replace(/{{candidate_name}}/g, candidate.candidate_name || '')\n    .replace(/{{role}}/g, candidate.role || '')\n    .replace(/{{company_name}}/g, candidate.company_name || '')\n    .replace(/{{recruiter_name}}/g, candidate.recruiter_name || '');\n  \n  console.log(`${i + 1}. To: ${candidate.candidate_email}`);\n  console.log(`   Subject: ${subject}`);\n  console.log(`   Status: ${candidate.status}`);\n  console.log(`   Role: ${candidate.role}`);\n  console.log('');\n}\n\nconsole.log(`Total emails that would be sent: ${candidates.length}`);\nconsole.log('='.repeat(50));\n\nreturn [{ json: { \n  message: `DRY RUN: Would send ${candidates.length} rejection emails`, \n  candidates_count: candidates.length,\n  dry_run: true\n}}];"
      },
      "typeVersion": 2
    },
    {
      "id": "47770189-90de-4470-af74-a3a0ce25c842",
      "name": "Process Email Template",
      "type": "n8n-nodes-base.code",
      "position": [
        1580,
        -120
      ],
      "parameters": {
        "jsCode": "// Process email template for current candidate\nconst config = $('Set: Config').item.json;\nconst candidate = $json;\n\n// Process feedback if available\nlet feedbackHtml = '';\nlet feedbackText = '';\nif (candidate.interview_feedback && candidate.interview_feedback.trim() !== '') {\n  feedbackHtml = `<p><strong>Feedback:</strong> ${candidate.interview_feedback}</p>`;\n  feedbackText = `\\nFeedback: ${candidate.interview_feedback}\\n`;\n}\n\n// Process HTML template\nlet htmlBody = config.HTML_TEMPLATE\n  .replace(/{{candidate_name}}/g, candidate.candidate_name || '')\n  .replace(/{{role}}/g, candidate.role || '')\n  .replace(/{{company_name}}/g, candidate.company_name || '')\n  .replace(/{{recruiter_name}}/g, candidate.recruiter_name || '')\n  .replace(/{{feedback_html}}/g, feedbackHtml);\n\n// Process text template\nlet textBody = config.TEXT_TEMPLATE\n  .replace(/{{candidate_name}}/g, candidate.candidate_name || '')\n  .replace(/{{role}}/g, candidate.role || '')\n  .replace(/{{company_name}}/g, candidate.company_name || '')\n  .replace(/{{recruiter_name}}/g, candidate.recruiter_name || '')\n  .replace(/{{feedback_text}}/g, feedbackText);\n\n// Process subject template\nlet subject = config.SUBJECT_TEMPLATE\n  .replace(/{{candidate_name}}/g, candidate.candidate_name || '')\n  .replace(/{{role}}/g, candidate.role || '')\n  .replace(/{{company_name}}/g, candidate.company_name || '')\n  .replace(/{{recruiter_name}}/g, candidate.recruiter_name || '');\n\nreturn {\n  json: {\n    ...candidate,\n    email_subject: subject,\n    email_html: htmlBody,\n    email_text: textBody,\n    smtp_from: config.SMTP_FROM\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "03cba26e-e096-4e03-9b51-2337da836e1e",
      "name": "Has Candidates to Email?",
      "type": "n8n-nodes-base.if",
      "position": [
        1140,
        -140
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "30b45fed-d929-4718-ac41-21a96c295295",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "62b25b62-a7fb-4f89-9929-52f0bd95eb82",
      "name": "No Candidates Message",
      "type": "n8n-nodes-base.set",
      "position": [
        1380,
        60
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d879c53b-b757-48a8-bc98-12ab841d83a8",
              "name": "message",
              "type": "string",
              "value": "No candidates found for rejection emails today"
            },
            {
              "id": "ef1e7563-4483-44a8-b8fd-cf2b25f82e8a",
              "name": "timestamp",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "71d973fc-3439-4141-8d15-92a3809ea4ca",
      "name": "Rate Limit Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1800,
        -120
      ],
      "parameters": {
        "amount": "={{ $('Set: Config').first().json.RATE_LIMIT_SECONDS }}\n"
      },
      "typeVersion": 1.1
    },
    {
      "id": "502e0718-c576-4200-9e70-813dc8f00ee1",
      "name": "Log Success",
      "type": "n8n-nodes-base.set",
      "position": [
        2400,
        -120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0b708662-5515-443b-9cdc-42c9552f07ad",
              "name": "message",
              "type": "string",
              "value": "=Rejection email sent successfully to {{ $json.candidate_email }}"
            },
            {
              "id": "47d6070a-3cf4-4693-b807-fadc4203e41b",
              "name": "candidate_name",
              "type": "string",
              "value": "={{ $json.candidate_name }}"
            },
            {
              "id": "d34acf55-9411-4ee0-96c9-f764dbeabcbc",
              "name": "sent_at",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "926bc390-d721-4b13-add3-7bc508a8f0ba",
      "name": "Mark as Sent in Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2220,
        -120
      ],
      "parameters": {
        "columns": {
          "value": {
            "rejection_sent_at": "={{ new Date().toISOString() }}"
          },
          "schema": [
            {
              "id": "candidate_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "candidate_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "candidate_email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "candidate_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "role",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "role",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "recruiter_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "recruiter_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rejection_sent_at",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "rejection_sent_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "candidate_email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Candidate Status"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1n_AIqOd10Q0ErQZSO4q4LBMekwgsR4cP7EW2q9nEzdk"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "52bba329-067e-46a5-aef4-7f28558b16ac",
      "name": "Send Rejection Email1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2020,
        -120
      ],
      "parameters": {
        "sendTo": "={{$json.candidate_email}}",
        "message": "={{$json.email_html}}",
        "options": {},
        "subject": "={{$json.email_subject}}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "958eb49a-a567-4608-be1f-52b5291bdbf6",
      "name": "Fetch Candidate Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        700,
        -140
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Candidate Status"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1n_AIqOd10Q0ErQZSO4q4LBMekwgsR4cP7EW2q9nEzdk"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6,
      "alwaysOutputData": true
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "77ed4c82-e3b6-4b6e-b67f-b6cd686f3fcc",
  "connections": {
    "Is Dry Run?": {
      "main": [
        [
          {
            "node": "Dry Run Preview",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Process Email Template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: Config": {
      "main": [
        [
          {
            "node": "Check Weekend Policy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Wait": {
      "main": [
        [
          {
            "node": "Send Rejection Email1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set: Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Weekend Policy": {
      "main": [
        [
          {
            "node": "Fetch Candidate Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Weekend Skip Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Candidate Data": {
      "main": [
        [
          {
            "node": "Filter Candidates for Rejection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Sent in Sheet": {
      "main": [
        [
          {
            "node": "Log Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Rejection Email1": {
      "main": [
        [
          {
            "node": "Mark as Sent in Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Email Template": {
      "main": [
        [
          {
            "node": "Rate Limit Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Candidates to Email?": {
      "main": [
        [
          {
            "node": "Is Dry Run?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Candidates Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Candidates for Rejection": {
      "main": [
        [
          {
            "node": "Has Candidates to Email?",
            "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.

Pro

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

About this workflow

Automatically reads a “Candidate Status” tab in Google Sheets every day at 18:00 Asia/Kolkata, filters rows with exact (case-sensitive) rejection statuses and sends one personalized rejection email per candidate via SMTP (Gmail). It rate-limits sends, supports DRY\_RUN previews…

Source: https://n8n.io/workflows/7766/ — 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

YOUR_ID 4. Uses gmail, googleDrive, googleSheets, httpRequest. Scheduled trigger; 53 nodes.

Gmail, Google Drive, Google Sheets +1
Email & Gmail

Looking for a way to track GitHub bounty issues automatically and get notified in real time? This GitHub Bounty Tracker workflow monitors repositories for issues labeled 💎 Bounty, logs them in Google

Google Sheets, HTTP Request, WhatsApp +1
Email & Gmail

This workflow automatically sends a beautifully designed HTML newsletter every Sunday at 8 AM, featuring products currently on sale from your Algolia-powered e-commerce store.

Google Sheets, HTTP Request, Gmail
Email & Gmail

This n8n template demonstrates how to build a Auto Lead Gen & Outreach System for Local Businesses specifically designed to help businesses that don’t have a website yet.

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

The workflow is triggered automatically every day at 12:00 PM using a Cron node.

RSS Feed Read, Google Sheets, Gmail +1