Recruitment operations
IMAP Resume Parsing: How to Pull CVs From a Shared Inbox
By Andre · · 14 min read
IMAP Resume Parsing: How to Pull CVs From a Shared Inbox

IMAP resume parsing means connecting to a mailbox over the IMAP protocol, finding the emails that carry resumes, downloading the attachments, and turning each file into structured candidate data: name, contact details, skills, experience and so on. It has four moving parts: a mailbox connection, a way to spot resume emails, an attachment decoder, and a parser that reads the document. You can build all four yourself or use software that already does it. This guide walks through each part so you can decide which route fits your team.
TL;DR
- IMAP gives you raw messages, not tidy data. You fetch the MIME structure, find attachments, decode them, and only then parse the resume.
- Authentication is the most common failure. Microsoft has disabled Basic authentication in Exchange Online, so a plain username and password no longer works there.
- Good parsing separates text extraction (including OCR for scans) from field extraction, and ends with validation and duplicate checks.
- Building a pipeline is realistic for a developer, but maintaining it costs more than writing it. Small teams often do better with a ready-made tool.
- RecrutFlo connects to shared inboxes, detects CV attachments and builds searchable profiles, with a free plan to test the workflow.
Table of Contents
- What IMAP resume parsing actually means
- The pipeline in five steps
- Troubleshooting common errors
- Security and privacy basics
- Build or buy?
- Our perspective
- Skip the build: RecrutFlo for shared CV inboxes
- FAQ
- Sources
What IMAP resume parsing actually means
Two separate technologies are hiding in the phrase. IMAP is the transport: IMAP4rev2, defined in RFC 9051, lets a client manipulate mailboxes, search them, and selectively fetch message attributes, texts and portions of messages. Resume parsing is the interpretation: reading a PDF or Word file and deciding which string is a phone number and which is a job title.
IMAP only gets you as far as the file. It does not know a resume from an invoice. That is a real difference from push-style inbound email services, which deliver a structured JSON payload to your endpoint. With IMAP you fetch raw, unstructured MIME content and write the decomposition logic yourself, and you accept some polling delay because your code asks the server for new mail instead of being told about it.
For a recruiting team, that trade-off is usually fine. Candidates already email CVs to a shared address, the mailbox already exists, and a delay of a few minutes does not matter. The harder work is everything after the fetch.
The pipeline in five steps
- Connect and authenticate to the mailbox.
- Select the messages worth looking at.
- Fetch and decode the attachments.
- Extract text and turn it into structured fields.
- Store, de-duplicate and index the result.
Each step has its own failure modes, covered below.
Step 1: Connect to the mailbox
In Python, the standard imaplib module handles the connection. A typical script opens a secure session with IMAP4_SSL and then logs in. Always use the encrypted port (993 for IMAP over TLS), never plain text.
The login is where modern mail systems push back. Microsoft states that Basic authentication is now disabled in all Exchange Online tenants, including for IMAP, and that apps must use OAuth 2.0 based Modern authentication. So a script that logs in to a Microsoft 365 mailbox with a stored password will fail, and nobody at Microsoft can switch it back on for your tenant. If you are building this for Microsoft 365, plan for an OAuth app registration from day one. For classic IMAP providers that still accept passwords, use an app-specific password where the provider offers one.
If you keep credentials at all, treat them seriously. One security write-up recommends AES-256 encryption at rest for IMAP credentials and never returning them through API responses. We cover what to check on the permission side in our guide to shared inbox permissions recruiters must check.

Step 2: Find the emails that contain resumes
Do not download everything. IMAP supports server-side search, so you can filter before fetching. Examples in an open-source fetcher show searching for unseen messages and matching on sender or subject. Useful starting filters for a recruiting inbox:
- Unread messages only, or messages newer than the last processed UID.
- Subjects containing words like “application”, “CV”, “resume” or a job reference code.
- Messages with at least one attachment of type PDF, DOC or DOCX.
Subject matching is fragile. Candidates write “Hello”, “Job” or nothing at all. The more reliable signal is the attachment itself: a message with a single PDF named like a person is more likely a CV than one with a logo and a signature image. Track the last UID you processed per folder so a restart never reprocesses old mail or skips new ones.
If you are not ready for any code, a lighter first step is mailbox rules. Our post on Outlook rules that capture resumes explains what rules can do and where parsing needs to take over.
Step 3: Fetch and decode the attachments
Once you have a message, inspect its structure. The usual approach is to look at the body structure for parts marked as attachments, then fetch and decode only those parts, applying the transfer encoding (usually base64) as needed.
In Python, the modern EmailMessage API with policy.default offers get_body and iter_attachments, while the older compat32 policy relies on walk, get_payload and decode_header. The walk-and-check pattern is the same either way: iterate the multipart message, read the filename with part.get_filename(), check the content type, and decode the payload.
Three details trip people up:
- Encoded filenames. Names with accents or non-Latin characters arrive in encoded headers. Decode them before you test the extension.
- Wrong content types. A PDF sometimes arrives as
application/octet-stream. Check the extension and, better, the file’s first bytes. - Nested messages. Forwarded emails hide the resume inside a
message/rfc822part. Recurse into it.
Also decide what counts as noise. Inline images, calendar invites and signature files will show up as attachments. Filter by type and by a minimum size.
Step 4: Turn the file into structured data
This is the part that determines whether your database is useful. A common architecture has two layers. First, text extraction: one system design write-up describes using Apache Tika and PDFBox for digital files, OCR for scanned resumes, and layout analysis to put the text back in reading order. Second, field extraction: the same write-up uses a fine-tuned BERT-based named-entity model to tag names, contact details, skills and work history.
Layout matters more than most people expect. Two-column resumes, sidebars and tables can scramble the reading order, so a skill list ends up in the middle of a job description. Extraction that ignores layout produces confident but wrong fields.
Large language models are now common in this step, with caveats. An academic paper on the topic notes that asking an LLM to extract every resume field in one pass tends to be suboptimal, while splitting the work into parallel sub-tasks improves accuracy and cuts latency. The same framework returns JSON and post-processes results with normalization, de-duplication and verification against the source text. That last idea is worth copying whatever model you use: never keep a field the resume text does not support.
A practical field list for recruiters:
| Field group | Examples | Why it matters |
|---|---|---|
| Contact | Name, email, phone, city | De-duplication, outreach |
| Experience | Employers, titles, dates | Seniority filters |
| Skills | Tools, certifications | Search by skill |
| Languages | Spoken languages and levels | Agency placements |
| Context | Salary expectation, availability | Shortlisting |
Step 5: Store, de-duplicate and index
Store the original file untouched, store the parsed fields separately, and link the two to the source email. One design example keeps parsed resumes in PostgreSQL with the structured data in a JSONB column and a searchable candidate index. That is a reasonable pattern for a custom build, though it is one team’s design rather than a standard.
Duplicates deserve their own logic. The same candidate applies to three roles, or sends an updated CV a month later. Match on normalized email address first, then phone number, then a name plus employer combination, and merge rather than overwrite so the history stays intact. Our guide on turning CVs in your inbox into a candidate database covers the structure side, and the post on searching CVs you already received shows what good retrieval looks like once the data is clean.
Troubleshooting common errors
Most problems fall into a few buckets. The same source that discusses email security points out that most email integration failures come from predictable handling errors, not exotic attacks, and the same is true of parsing.
| Symptom | Likely cause | What to do |
|---|---|---|
| Login fails on Microsoft 365 | Basic authentication is disabled | Move to OAuth 2.0 Modern authentication |
| Login fails on another provider | IMAP disabled, or app password required | Enable IMAP in the mailbox settings, create an app password |
| Same emails processed twice | UID not tracked | Store the last UID per folder, and the folder’s UIDVALIDITY value |
| Attachment saved but will not open | Transfer decoding skipped | Decode base64 or quoted-printable before writing the file |
| Empty text from a PDF | Scanned image | Run OCR before field extraction |
| Skills mixed into job history | Multi-column layout | Apply layout analysis before entity extraction |
| Candidate appears twice | Different email address or spelling | Match on phone and name plus employer, then merge |
| Garbled names | Character encoding | Decode headers and file text as UTF-8 |
The UID point comes straight from the protocol: RFC 9051 defines UIDs and UIDVALIDITY so a client can tell when a mailbox’s numbering has been reset. If UIDVALIDITY changes, your stored UIDs are no longer valid and you need a resync.
A habit that saves hours: log every message you skip and why. When a recruiter says “Maria sent her CV last Tuesday and it is not in the system”, you can answer in a minute instead of a day.
Security and privacy basics
A recruiting inbox holds personal data: addresses, phone numbers, work history and sometimes photos or dates of birth. Keep the blast radius small.
- Give the parser a dedicated mailbox or a read-only role, not a personal login.
- Keep decrypted credentials only as long as a job needs them. One engineering write-up recommends a write-once model where decrypted credentials exist in memory only for the duration of the server-side job.
- Separate clients or teams into isolated workspaces, and keep an audit trail of who opened what.
- Set a retention rule for rejected candidates and apply it to both the parsed record and the original file. Retention duties differ by country and state, so ask your employment counsel or privacy officer which period applies to you.
The broader setup, including which mailbox permissions to grant, is in our walkthrough of an IMAP recruiting setup for a shared CV inbox.
Build or buy?
A developer can get a working prototype in a weekend: connect, search, download, run a parser library. What takes months is the long tail. OAuth token refresh, odd attachments, scanned PDFs, duplicate rules, access control and a search interface recruiters actually enjoy using.
Build it yourself if you have an engineer who will own it, unusual data requirements, or a need to embed parsing inside your own product. Buy if your goal is a searchable candidate list by next week and nobody on the team wants to maintain mail connectors. Our post on resume parsing for small business goes deeper on that decision, and how to parse resumes from email without retyping them shows the day-to-day workflow.
Our perspective
We built RecrutFlo because the people who receive the most CVs are often the least equipped to process them. A five-person agency or a small business owner does not need a pipeline, stages and an implementation project. They need the CVs already sitting in the shared inbox to become searchable, without retyping and without moving everyone to a new platform.

That shapes what we think matters in IMAP parsing. Connect to the inbox the team already uses. Automate the repetitive steps, detecting attachments, reading fields and flagging duplicates, but leave the decisions to the recruiter, who can see the original file next to the extracted data. Keep pricing and limits visible so nobody needs a sales call to learn what a month costs. And treat candidate data with the care it deserves: isolated workspaces, access control and an audit trail, designed around EU data protection principles.
If you do build your own, copy the habits above: verify extracted fields against the source text, log what you skip, and never store a password you could avoid storing.
— Marco
Skip the build: RecrutFlo for shared CV inboxes
RecrutFlo connects to Microsoft 365, Outlook and IMAP mailboxes (Gmail is coming soon), detects CV attachments in incoming mail, parses PDF, DOC and DOCX files, and organizes the results into searchable profiles with duplicate flags and CSV export. You can see the flow on the How it works page.

You can test the workflow on the Free plan first. Paid plans on the pricing page are Starter at 19 € per month, Professional at 49 € per month and Business at 149 € per month. If you run past your plan’s volume, extra processing runs are a one-off purchase: 9 € for 100, 29 € for 500 or 49 € for 1,000. Or start from the RecrutFlo homepage and connect a mailbox.
For more on recruiting inbox workflows, browse the RecrutFlo recruitment operations blog.
FAQ
Can I parse resumes from Gmail or Outlook over IMAP?
Yes in principle, but both providers now expect modern authentication. Microsoft has disabled Basic authentication in Exchange Online, so Outlook and Microsoft 365 mailboxes need OAuth 2.0. A script with a plain stored password will be refused.
Is IMAP better than forwarding emails to a parsing address?
They solve different problems. Forwarding or inbound parsing pushes structured data to you quickly, but someone has to set up forwarding rules. IMAP reads the mailbox that already exists, so past and future CVs are both reachable, at the cost of polling and doing the MIME work yourself.
Why does my parser return empty fields for some resumes?
Usually the file is a scanned image, so there is no text layer and you need OCR first. The other common cause is a multi-column or table-heavy layout that scrambles reading order. Check the raw extracted text before blaming the field extraction.
How do I avoid duplicate candidates?
Normalize the email address and match on it first, then phone number, then name plus latest employer. Merge records instead of replacing them so earlier applications stay visible. RecrutFlo flags likely duplicates automatically.
Do I need to keep the original CV file?
Keeping it is good practice, because a recruiter must be able to check any parsed field against the source. Apply the same retention rule to the file and the parsed record, and confirm the period with your counsel or privacy officer.
Sources
- RFC 9051: Internet Message Access Protocol (IMAP) Version 4rev2
- Inbound Email Parsing: Definition & How It Works
- Building an email automation agent (callsphere)
- Deprecation of Basic authentication in Exchange Online
- Secure email API for developers (Unipile)
- ShaadyEmad/IMAP-Email-Fetcher
- Email Content (plover)
- Python Receive Email: How to Read and Parse Incoming Email
- System Design: Resume Parsing & Matching System
- Layout-Aware Parsing Meets Efficient LLMs
- Storing Credentials Securely: AES-256-GCM and JWT