使用Google Sheets和Gmail在每日结束时自动发送招聘拒绝邮件

中级

这是一个HR、Multimodal AI领域的自动化工作流,包含 15 个节点。主要使用 If、Set、Code、Wait、Gmail 等节点。 在每日结束时自动发送招聘拒绝邮件(Google Sheets | Gmail)

前置要求
  • Google 账号和 Gmail API 凭证
  • Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "3bsNBJ5i1ylNYtKM",
  "meta": {
    "instanceId": "14e4c77104722ab186539dfea5182e419aecc83d85963fe13f6de862c875ebfa",
    "templateCredsSetupCompleted": true
  },
  "name": "使用 Google Sheets 和 Gmail 在每日结束时自动发送招聘拒绝邮件",
  "tags": [],
  "nodes": [
    {
      "id": "afba507f-8023-4c22-af01-d040e266d257",
      "name": "由 Github 模型提供支持",
      "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": "设置:配置",
      "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": "careers@company.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": "检查周末政策",
      "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": "周末跳过消息",
      "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": "筛选待拒绝候选人",
      "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": "是否为试运行?",
      "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": "试运行预览",
      "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": "处理邮件模板",
      "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": "是否有待邮件候选人?",
      "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": "无候选人消息",
      "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": "速率限制等待",
      "type": "n8n-nodes-base.wait",
      "position": [
        1800,
        -120
      ],
      "webhookId": "c8f42998-bd55-4ed5-8ffc-28139dc519f4",
      "parameters": {
        "amount": "={{ $('Set: Config').first().json.RATE_LIMIT_SECONDS }}\n"
      },
      "typeVersion": 1.1
    },
    {
      "id": "502e0718-c576-4200-9e70-813dc8f00ee1",
      "name": "记录成功",
      "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": "在表格中标记为已发送",
      "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": {
          "id": "K51JQLS2WHFWzap5",
          "name": "Google Sheets account 7"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "52bba329-067e-46a5-aef4-7f28558b16ac",
      "name": "发送拒绝邮件1",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2020,
        -120
      ],
      "webhookId": "462efaac-082a-4b99-b9a9-c3e04c06572b",
      "parameters": {
        "sendTo": "={{$json.candidate_email}}",
        "message": "={{$json.email_html}}",
        "options": {},
        "subject": "={{$json.email_subject}}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "GsAjl8kiLaQnkjoK",
          "name": "Gmail account 10"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "958eb49a-a567-4608-be1f-52b5291bdbf6",
      "name": "获取候选人数据",
      "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": {
          "id": "K51JQLS2WHFWzap5",
          "name": "Google Sheets account 7"
        }
      },
      "typeVersion": 4.6,
      "alwaysOutputData": true
    }
  ],
  "active": false,
  "pinData": {},
  "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
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

这是一个中级难度的工作流,适用于HR、Multimodal AI等场景。适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量15
分类2
节点类型7
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

作者
WeblineIndia

WeblineIndia

@weblineindia

A Leading Software Engineering, Consulting & Outsourcing Services Company in USA & India serving Clients Globally since 1999.

外部链接
在 n8n.io 上查看 →

分享此工作流