89 Resumes to 7 Shortlisted in 14 Min — n8n + Telegram

A client posted one Senior Backend Engineer role last month. Eighty-nine resumes landed in the jobs inbox inside a week. Instead of burning three afternoons on PDF triage or paying $30/seat for someone's AI recruiting add-on, we ran the whole batch through a five-node n8n workflow in 14 minutes and 11 seconds. OpenAI spend: $1.03. Seven candidates surfaced for human review, 82 got personalized rejection emails, and I approved five interviews from my phone while standing in line for coffee.
Here's the exact graph, the scoring prompt, and the Telegram callback handler that makes it work.
The five-node graph, end to end
The whole workflow is one Gmail trigger, one PDF extractor, one OpenAI call, one IF split, and a Telegram approval loop. That's it. No vector DB, no ATS integration, no fine-tuned model. If you can wire up a Zapier zap you can build this — n8n just gives you branching, JSON handling, and callback triggers that Zapier charges extra for.
Here's the topology:
Gmail Trigger (poll 5 min, has attachment, label:Applications)
↓
Extract from File (PDF → text)
↓
OpenAI (gpt-4o-mini, JSON mode, scoring prompt)
↓
IF (stack_match_score >= 7)
├─ true → Telegram sendMessage (candidate card + inline keyboard)
└─ false → Gmail (auto-reject with model's reason)
[separate branch]
Telegram Trigger (callback_query)
↓
Switch (Approve / Reject / Ask Follow-up)
├─ Approve → Cal.com booking link email
├─ Reject → Warm rejection email
└─ Ask Follow-up → Templated clarifying-questions email
Node one is the Gmail trigger, pointed at jobs@yourdomain, filtered for messages with PDF attachments, polling every 5 minutes. Add a Gmail filter that auto-applies an Applications label based on the subject line of your job post, then trigger only on that label. This keeps invoices, spam, and vendor pitches out of the pipeline without any logic in n8n.
Why gpt-4o-mini is the right model here
Resume screening does not need a frontier model. It needs a model that can read 2-4 pages of text, extract structured fields, and produce a warm one-sentence rejection. gpt-4o-mini does all of that reliably in JSON mode, and the cost math only works at mini prices.
Real numbers from the 89-resume run:
| Metric | Value |
|---|---|
| Resumes processed | 89 |
| Total runtime | 14 min 11 sec |
| OpenAI spend | $1.03 |
| Cost per resume | ~$0.0116 |
| Shortlisted (score ≥ 7) | 7 |
| Auto-rejected | 82 |
| Manual triage time | 0 |
For comparison, running the same batch on gpt-4o would have cost roughly $17 — still cheap in absolute terms, but 16× more for zero measurable improvement in shortlist quality on a task this structured. I tested both on a 20-resume sample. Both surfaced the same top candidates. gpt-4o produced slightly more flowery rejection copy. Not worth 16×.
If you're screening for something where nuance genuinely matters — a senior leadership role where a résumé is 60% context — bump to gpt-4o for that one workflow. For engineering, sales, ops, marketing? Mini is fine.
The scoring prompt that does 90% of the work
The prompt is the whole product. Everything else is plumbing. Here's what I ship to clients, with the job description injected as a variable:
You are a technical recruiter screening candidates for the role below.
Be strict but fair. Score on stack match, not vibes.
ROLE:
{{ $json.job_description }}
RESUME TEXT:
{{ $json.resume_text }}
Return a single JSON object with exactly these fields:
{
"candidate_name": string,
"candidate_email": string,
"years_relevant_experience": number,
"stack_match_score": integer between 0 and 10,
"top_strengths": array of exactly 3 short strings,
"red_flags": array of exactly 2 short strings,
"rejection_reason": string — one sentence, warm and specific,
written so it can be sent directly to the candidate without editing.
No generic phrases like "not a fit at this time".
}
Scoring guide:
- 9-10: Exact stack match, seniority matches, clear evidence in projects
- 7-8: Strong overlap, minor gaps, worth an interview
- 4-6: Adjacent experience, notable gaps in required stack
- 0-3: Wrong role, wrong seniority, or unreadable resume
Turn on JSON mode in the OpenAI node (response_format: { type: "json_object" }). This is non-negotiable. Without it you will spend two evenings debugging edge cases where the model wraps output in markdown fences or adds a preamble.
Two things that matter in this prompt:
- The rejection reason is written by the same model call that scores. You are not making a second API call for rejection copy. The model already has the resume in context; asking for one sentence adds maybe 40 tokens. It costs nothing and it means candidates get responses that reference their actual background.
- The scoring guide is explicit. Without it, models cluster everything at 6-8 and your threshold becomes meaningless. With it, the distribution spreads out and the ≥7 filter actually filters.
The Telegram approval loop is the whole point
Ninety percent of "AI screening" tools stop at the shortlist. You still have to log into a dashboard, review candidates, click through profiles. That's not automation, that's a slower ATS.
The Telegram loop closes it. Node four sends a compact candidate card to your bot:
🟢 Sarah Chen — 8/10
6 years relevant experience
Strengths:
• Shipped Postgres-backed billing system at 40k MAU
• Deep async Python (FastAPI, asyncio, Celery)
• Wrote the migration playbook her team still uses
Red flags:
• No mention of production on-call rotation
• Last role was 14 months (short tenure)
[✅ Approve] [❌ Reject] [❓ Ask Follow-up]
The inline keyboard is Telegram's built-in feature. Each button carries a callback_data payload with the candidate's email and the action:
{
"text": "✅ Approve",
"callback_data": "approve|sarah.chen@example.com"
}
Node five is a second Telegram trigger listening for callback_query events. A Switch node routes on the action:
- Approve → Cal.com or Calendly node sends the candidate a booking link for a 15-minute intro call
- Reject → Gmail sends the same warm rejection email as the auto-reject branch
- Ask Follow-up → Gmail sends a templated email with your usual gap questions (visa status, notice period, salary expectations)
In all three cases, archive the Gmail thread so your inbox stays clean.
The feel of this changes the workflow completely. Your phone buzzes with a candidate card. You read six lines. You tap. The workflow keeps moving. No laptop, no ATS login, no context switching, no "I'll get to this tonight" that turns into Friday.
On the 89-resume run I approved 5 candidates, sent 2 follow-ups, and rejected 0 of the shortlisted 7 — all in about 90 seconds while making coffee.
The failure modes nobody shows you
Demo videos skip this part. Here's what actually breaks in production and how to handle it.
- Scanned PDF resumes with no OCR layer. The Extract from File node returns empty text. Add an IF node after extraction: if text length < 200 characters, route to a Telegram message that says "manual review needed" with the original PDF attached. About 3 of the 89 hit this path — usually candidates who exported a design-heavy Figma resume as an image PDF.
- Model returns valid JSON but with a hallucinated email. Add a regex validator on
candidate_email. If it doesn't match a basic email pattern, fall back to the Gmail sender address from the trigger node. - Duplicate applications. Same candidate applies twice to different job posts. Add a Postgres or Airtable node between the IF and Telegram that checks if
candidate_email + job_idhas been processed in the last 30 days. Skip if yes. - Rate limits during a hiring spike. If 200 resumes land in one hour, gpt-4o-mini's rate limit on a Tier 1 account (500 RPM) is fine, but Gmail's send limit isn't. Add a Wait node (2-3 seconds) before each Gmail send in the reject branch, or batch rejections through a queue.
- The bias question. This workflow scores stack match, not people. Do not add prompt fields for "cultural fit" or anything demographic-adjacent. Keep the scoring criteria to concrete, job-relevant, verifiable claims. If you're US-based, review EEOC guidance on automated employment decision tools before deploying to a real hiring pipeline. This is not legal advice — talk to an employment attorney if you're screening at scale.
Cost vs the alternatives, honestly
Let's compare against what a founder would actually consider:
| Option | Monthly cost | Setup time | Fits in phone workflow |
|---|---|---|---|
| Manual triage (3 hrs/wk @ $75/hr) | ~$900 | 0 | No |
| ATS AI add-on ($30/seat × 3 seats) | $90 | Half a day | No — dashboard |
| Recruiter agency (10% first-year salary) | $10k+ per hire | 0 | No |
| This n8n workflow | ~$5 OpenAI + n8n cloud ($24) | 40 min | Yes |
The n8n workflow wins on cost and on the thing that actually matters: it removes the human bottleneck between "resume arrives" and "decision made." Even if you love your ATS, wiring the Telegram approval layer on top of it is worth the 40 minutes.
Where the paid tools genuinely beat this: compliance logging, EEOC audit trails, candidate portals, structured interview scheduling for teams of 5+. If you're a 50-person company hiring 30 people a year, buy the ATS. If you're a 3-person team hiring 2 people this quarter, build this.
Why bizflowai.io helps with this
This exact workflow — Gmail trigger, structured extraction, LLM scoring with JSON mode, Telegram approval loop with inline keyboards — is one of the standard patterns we deploy for clients running lean hiring, inbound lead qualification, and support ticket triage. Same graph shape, different prompt and different downstream actions. If you want the n8n JSON export for this recruiting workflow, or you want it adapted to your ATS and job description, that's the kind of thing bizflowai.io builds and hands over as a working system, not a course.
Want more like this?
I publish practical AI automation, GenAI engineering, and faceless content workflows on YouTube every week.
Subscribe to bizflowai.io on YouTube — never miss a new tutorial.
Planning an AI automation project or need a second opinion on your architecture?
Connect with me on LinkedIn — Lazar Milicevic, GenAI Engineer & bizflowai.io Founder.
Visit bizflowai.io for our services, case studies, and AI consulting.
Frequently asked questions
How do I automate resume screening with n8n and Gmail?
Build a five-node n8n workflow: a Gmail trigger polling the jobs inbox every five minutes for PDF attachments, an Extract from File node feeding text to a GPT-4o-mini node that returns structured JSON (name, email, experience, stack match score, strengths, red flags, rejection reason), an IF node splitting on score, a Telegram node for shortlisted candidates, and a callback handler for Approve/Reject/Follow-up actions.
Why use GPT-4o-mini instead of a frontier model for resume screening?
GPT-4o-mini is sufficient for reading resumes and extracting structured data, and the cost math only works at mini prices. In one real deployment, processing 89 resumes from a single job post took 14 minutes and cost $1.03 in OpenAI spend. A frontier model would inflate cost without meaningfully improving screening quality for standard stack-match evaluation.
What should the OpenAI prompt return when screening resumes?
Ask the model to act as a technical recruiter and return JSON with: candidate name, email, years of relevant experience, stack match score from 0 to 10, top three strengths, top two red flags, and a one-sentence rejection reason written in a warm, human tone that could be sent directly to the candidate. Turn on JSON mode so the output is parseable downstream.
How does the Telegram approval step work in the recruiting workflow?
A Telegram sendMessage node posts a compact candidate card (name, experience, score, strengths, red flags) with an inline keyboard containing Approve, Reject, and Ask Follow-up buttons. Each button carries callback data with the candidate's email and action. A second Telegram trigger listens for callback queries and routes to a Cal.com booking link, a rejection email, or a templated follow-up email.
When should I build this n8n workflow instead of buying an AI recruiting tool?
Build it when you already have Gmail and receive high resume volume on occasional job posts, and don't want to pay $30 per seat for an AI recruiting module. The workflow takes about 40 minutes to wire up once using five nodes, then handles triage automatically. It suits small businesses processing dozens to hundreds of applicants per role without a dedicated ATS.