Reads each job application that lands in Gmail, attached CV included, adds the candidate to your Google Sheet and tells your team in Slack.
Uses
Claude
Gmail
Google Sheets
Slack
Add every emailed job application to your candidate sheet
email.When an email arrives. Save it as email.spreadsheetUrl to blank.Set spreadsheetUrl to blank.sheetName to Candidates.Set sheetName to Candidates.slackChannelId to blank.Set slackChannelId to blank.openRoles to blank.Set openRoles to blank.subjectKeywords to [application, applying, apply, cv, resume, résumé, candidate, vacancy, job, position, role].Set subjectKeywords to [application, applying, apply, cv, resume, résumé, candidate, vacancy, job, position, role].ignoreKeywords to [out of office, automatic reply, auto-reply, autoreply, undeliverable, delivery status notification, mail delivery failed].Set ignoreKeywords to [out of office, automatic reply, auto-reply, autoreply, undeliverable, delivery status notification, mail delivery failed].gmailAccountIndex to 0.Set gmailAccountIndex to 0.message, subject_keywords, ignore_keywords, account_index, and open_roles and save it as intake.Run Python code on message, subject_keywords, ignore_keywords, account_index, and open_roles and save it as intake.intake.proceed is noIf intake.proceed is noYes
intake.reason.Finish the run: intake.reason.No
No steps
cvFiles to an empty list.Set cvFiles to an empty list.cvText to an empty list.Set cvText to an empty list.unreadAttachments to an empty list.Set unreadAttachments to an empty list.intake.message_id isn't blankIf intake.message_id isn't blankYes
downloadErrorIf a step below fails, save the error as downloadErrorTry
intake. Save it as attachments.Download the attachments on email intake. Save it as attachments.attachment in attachments.documents:For each attachment in attachments.documents:attachment.content_type is application/pdf If attachment.content_type is application/pdfYes
attachment.document_ref into cvFiles at position 0 and save it as cvFiles.Insert attachment.document_ref into cvFiles at position 0 and save it as cvFiles.Else if ["image/png", "image/jpeg", "image/webp"] contains…
attachment.document_ref to the end of cvFiles and save it as cvFiles.Add attachment.document_ref to the end of cvFiles and save it as cvFiles.Else if @attachment.content_type is…
readErrorIf a step below fails, save the error as readErrorTry
attachment.document_ref Save it as wordFile.Read attachment.document_ref Save it as wordFile.wordFile.text to the end of cvText and save it as cvText.On error
attachment.filename to the end of unreadAttachments and save it as unreadAttachments.Add attachment.filename to the end of unreadAttachments and save it as unreadAttachments.Otherwise
attachment.filename to the end of unreadAttachments and save it as unreadAttachments.Add attachment.filename to the end of unreadAttachments and save it as unreadAttachments.On error
downloadError.message) to the end of unreadAttachments and save it as unreadAttachments.Add the attachments (they could not be downloaded: downloadError.message) to the end of unreadAttachments and save it as unreadAttachments.No
No steps
cvFiles is greater than 10If the length of cvFiles is greater than 10Yes
cvFiles and save it as cvFiles.Take the first 10 items of cvFiles and save it as cvFiles.No
No steps
cvText with nothing and save it as cvTextJoined.Join cvText with nothing and save it as cvTextJoined.aiAnswer to an empty record.Set aiAnswer to an empty record.aiProblem to blank.Set aiProblem to blank.aiErrorIf a step below fails, save the error as aiErrorTry
screening.Run an AI agent: Read this email and any CV attached to it, and fill in the candidate's details.@intake.ro… and save it as screening.aiAnswer to screening.output.Change aiAnswer to screening.output.On error
aiProblem to aiError.message.Change aiProblem to aiError.message.sheetHeaders to an empty list.Set sheetHeaders to an empty list.sheetProblem to blank.Set sheetProblem to blank.headerErrorIf a step below fails, save the error as headerErrorTry
spreadsheetUrl. Save it as candidatesTab.Read the rows of spreadsheetUrl. Save it as candidatesTab.sheetHeaders to candidatesTab.headers.Change sheetHeaders to candidatesTab.headers.On error
sheetProblem to headerError.message.Change sheetProblem to headerError.message.reply, ai_problem, intake, received_at, sheet_url, sheet_name, sheet_headers, unread_attachments, and files_read and save it as candidate.Run Python code on reply, ai_problem, intake, received_at, sheet_url, sheet_name, sheet_headers, unread_attachments, and files_read and save it as candidate.candidate.is_application is noIf candidate.is_application is noYes
candidate.skip_reason.Finish the run: candidate.skip_reason.No
No steps
sheetProblem is blankIf sheetProblem is blankYes
candidate.missing_headers isn't emptyIf candidate.missing_headers isn't emptyYes
candidate.missing_headers with , and save it as missingHeaderList.Join candidate.missing_headers with , and save it as missingHeaderList.the first row of the '@sheetName' tab is missing these headings: @missingHeaderList. Nothing was written, so no value landed in the wrong column. and save it as sheetProblem.Build the text the first row of the '@sheetName' tab is missing these headings: @missingHeaderList. Nothing was written, so no value landed in the wrong column. and save it as sheetProblem.No
sheetErrorIf a step below fails, save the error as sheetErrorTry
sheetName in spreadsheetUrl.Add a row to sheetName in spreadsheetUrl.On error
sheetProblem to sheetError.message.Change sheetProblem to sheetError.message.No
No steps
slackText to candidate.slack_text.Set slackText to candidate.slack_text.sheetProblem isn't emptyIf sheetProblem isn't emptyYes
slackText to slackTextChange slackText to slackText
:warning: This candidate was NOT added to the sheet, so please add them by hand from the email. Reason: sheetProblem with & replaced by & with < replaced by < with > replaced by >.No
No steps
slackErrorIf a step below fails, save the error as slackErrorTry
slackChannelId.Send a message to slackChannelId.slackTextOn error
sheetProblem isn't emptyIf sheetProblem isn't emptyYes
candidate.name: the row could not be added to '@sheetName' and the Slack message could not be posted, so nobody has been told. Reason: sheetProblem Slack said: slackError.message The application is still in Gmail: intake.link.Stop and report a problem: Nothing was recorded for candidate.name: the row could not be added to '@sheetName' and the Slack message could not be posted, so nobody has been told. Reason: sheetProblem Slack said: slackError.message The application is still in Gmail: intake.link.No
candidate.name to '@sheetName', but the Slack message could not be posted, so nobody has been told about this application yet. Slack said: slackError.message.Stop and report a problem: Added candidate.name to '@sheetName', but the Slack message could not be posted, so nobody has been told about this application yet. Slack said: slackError.message.sheetProblem isn't emptyIf sheetProblem isn't emptyYes
candidate.name was not added to '@sheetName'. Reason: sheetProblem.Stop and report a problem: Your team was told in Slack, but candidate.name was not added to '@sheetName'. Reason: sheetProblem.No
No steps
candidate.problem isn't emptyIf candidate.problem isn't emptyYes
candidate.problem.Show in the output: candidate.problem.No
No steps
candidate.name to '@sheetName' and told the team in Slack.Show in the output: Added candidate.name to '@sheetName' and told the team in Slack.