n8n for Email Automation: Parsing and Routing Incoming Mail
Why Your Inbox Needs a Workflow Engine, Not Just Filters
Every growing team eventually hits the same wall: emails come in faster than anyone can triage them. Support requests, invoices, lead inquiries, partnership pitches, and internal notifications all land in the same inbox, and someone has to read each one, figure out what it is, and decide what happens next. Gmail filters and Outlook rules can catch the obvious cases — a subject line containing "invoice," a sender from a known domain — but they fall apart the moment the pattern gets even slightly more complex. They cannot read the body of an email and extract a purchase order number. They cannot check a sender against a CRM to see if they are an existing customer. They cannot forward a message to a different Slack channel depending on which product line it mentions.
This is exactly the gap n8n was built to fill. n8n is an open-source workflow automation tool that treats email as just another trigger — a node that starts a chain of logic, transforms data, calls APIs, and makes decisions along the way. Instead of static rules, you get a real pipeline: fetch the email, parse it into structured fields, classify what it is, and route it to the right destination, whether that's a support ticket, a database row, a Slack message, or a reply drafted for human review.
This article walks through building that pipeline in n8n end to end. We will cover the IMAP and Gmail trigger nodes, extracting structured data out of unstructured email bodies, handling attachments, building routing logic with the Switch node, and avoiding the operational mistakes that turn an email automation into a source of duplicate tickets and silent failures. If you have ever thought "I wish this just filed itself into the right place," this is the blueprint.
Setting Up the Email Trigger: IMAP vs Gmail Node
The first decision in any n8n email workflow is how you are going to receive incoming mail. n8n gives you a few options, and picking the right one affects reliability and how much setup work you're signing up for.
IMAP Email trigger. This node polls a mailbox over the IMAP protocol at an interval you define. It works with almost any mail provider — Gmail, Outlook, a self-hosted mail server, a shared support@ address hosted anywhere. You configure host, port, username, and password (or an app-specific password if two-factor auth is on), and n8n checks for new messages matching your criteria.
IMAP Trigger settings:
Host: imap.gmail.com
Port: 993
SSL/TLS: enabled
Mailbox: INBOX
Post-processing action: Mark as read (or move to a folder)The post-processing action matters a lot. If you leave messages unread and unmoved, the trigger will pick them up again on the next poll and you'll process the same email multiple times. Most production setups either mark messages as read or move them to a "Processed" folder immediately after the trigger fires, before any other logic runs.
Gmail trigger (OAuth-based). If your mailbox is specifically Gmail or Google Workspace, the dedicated Gmail node uses OAuth2 instead of raw credentials, which is both more secure and gives you access to Gmail-specific features like labels and threads. You can filter by label, so a common pattern is to have a Gmail filter automatically apply a label like "n8n-incoming" to relevant mail, then have your n8n Gmail trigger only watch that label. This keeps your automation scoped and avoids accidentally attempting to parse every marketing newsletter that lands in the inbox.
Webhook-based email (via a forwarding service). Some teams skip polling entirely and use a transactional email provider (like Postmark or SendGrid's inbound parse) that converts incoming email into a webhook POST request. n8n's Webhook node receives this instantly rather than waiting for the next poll cycle. This is the lowest-latency option but requires changing your MX records or setting up mail forwarding, which is a bigger infrastructure change than just pointing n8n at an existing mailbox.
For most teams starting out, the IMAP trigger is the pragmatic choice: no DNS changes, works with any provider, and gets you a working automation in the same afternoon.
Reading the Anatomy of an Incoming Email in n8n
Once the trigger fires, n8n hands you a JSON object per email. Understanding this shape is the foundation for everything downstream. A typical IMAP or Gmail trigger output includes:
{
"textHtml": "<p>Hi team, please process invoice #4521...</p>",
"textPlain": "Hi team, please process invoice #4521...",
"subject": "Invoice #4521 - Payment Confirmation",
"from": [{ "address": "billing@vendor.com", "name": "Vendor Billing" }],
"to": [{ "address": "ap@yourcompany.com" }],
"date": "2026-07-01T09:14:00.000Z",
"attachments": [
{ "filename": "invoice-4521.pdf", "content": "<binary>" }
]
}Two fields matter most for parsing: textPlain (clean text, easier to run regex or keyword matching against) and textHtml (the raw HTML, which you may need if the email uses tables or specific formatting that carries meaning). The subject field alone is often enough for basic routing decisions. The attachments array is where invoices, resumes, and signed contracts live, and n8n exposes each as binary data you can pass along to other nodes or save to disk/cloud storage.
A common early mistake is trying to parse textHtml directly with string functions. HTML entities, nested tags, and inconsistent formatting from different email clients make this fragile. Instead, prefer textPlain whenever it is available, and only fall back to stripping HTML tags (n8n's Code node can do this with a simple regex or an HTML-to-text library) when plain text is missing.
Extracting Structured Data from Free-Form Email Bodies
This is the heart of email parsing: turning "Hi team, please process invoice #4521 for $2,340.00, due by July 15th" into { invoiceNumber: "4521", amount: 2340.00, dueDate: "2026-07-15" }.
n8n gives you three tools for this, in increasing order of power.
1. The Set node with expressions. For simple, consistent patterns, you can use n8n expressions directly in a Set (Edit Fields) node. If every invoice email follows the same template, a regex expression can pull out the number:
{{ $json.textPlain.match(/invoice #(\d+)/i)?.[1] }}This works well when the email format is predictable — for example, automated notifications from a SaaS tool that always uses the same template.
2. The Code node with JavaScript. For anything more complex — multiple possible phrasings, optional fields, data scattered across subject and body — drop into a Code node and write real extraction logic:
const text = $input.item.json.textPlain || '';
const subject = $input.item.json.subject || '';
const invoiceMatch = text.match(/invoice\s*#?\s*(\d{3,8})/i);
const amountMatch = text.match(/\$\s?([\d,]+\.\d{2})/);
const dueDateMatch = text.match(/due\s+(?:by\s+)?([A-Za-z]+\s+\d{1,2}(?:st|nd|rd|th)?)/i);
return {
json: {
invoiceNumber: invoiceMatch ? invoiceMatch[1] : null,
amount: amountMatch ? parseFloat(amountMatch[1].replace(/,/g, '')) : null,
dueDateRaw: dueDateMatch ? dueDateMatch[1] : null,
subject,
from: $input.item.json.from[0]?.address,
}
};This is a normal, defensible pattern: use optional chaining and null fallbacks liberally, because email content is never as clean as you expect. Some invoices will use "Invoice No." instead of "invoice #." Some will format currency as "2,340.00 USD" instead of "$2,340.00." Build your regex library incrementally as real emails reveal edge cases, rather than trying to anticipate every format up front.
3. An LLM node for unstructured or highly variable content. When emails come from many different senders with wildly inconsistent formatting — think inbound sales inquiries, support requests, or resumes — regex stops scaling. This is where an AI node (n8n supports OpenAI, Anthropic Claude, and other model providers natively) earns its keep. You send the email body to a model with a structured extraction prompt:
Extract the following fields from this email as JSON:
- intent (one of: support_request, sales_inquiry, invoice, spam, other)
- urgency (low, medium, high)
- summary (one sentence)
- key_entities (any product names, order numbers, or company names mentioned)
Email:
{{ $json.textPlain }}Set the model node to return structured JSON output, and you now have semantic understanding of the email rather than just pattern matches. This is far more robust for classification tasks, and it's the technique we cover in depth in our course, because reliable structured output from an LLM requires careful prompt design and schema validation — it's easy to get inconsistent JSON back if you don't constrain the model properly.
Handling Attachments: Invoices, Resumes, and Documents
Attachments deserve their own section because they trip up a lot of first-time email automations. When n8n's trigger node picks up an email with an attachment, the file arrives as binary data attached to the item, referenced under a binary property name like attachment_0.
A typical attachment-handling chain looks like this:
- Filter by MIME type or extension. Use an IF node to check
$binary.attachment_0.mimeTypeand branch based on whether it's a PDF, image, or spreadsheet. You don't want to run PDF-parsing logic against a.jpgsignature file. - Extract text from PDFs. n8n has a built-in "Extract from File" node that pulls text out of PDF binaries, which you can then feed into the same regex or LLM extraction logic used for email bodies. This is how you get an invoice's line items even when the email itself just says "see attached."
- Save to structured storage. Push the binary to Google Drive, S3, or a database blob column, keyed by a reference you can look up later — usually the invoice number or the sender's email plus timestamp.
- Never trust the filename alone. A file named
invoice.pdfmight be a phishing payload with a mismatched extension. If this workflow touches financial processes, add a MIME-type check server-side rather than relying on what the filename claims.
For high-volume attachment processing (say, hundreds of resumes a week), it is worth adding a size limit check early in the workflow. An oversized attachment slipping through can stall a workflow or blow past memory limits on self-hosted n8n instances, especially if you're running the extraction step through an LLM node with a token limit on input size.
Building the Routing Logic with Switch and IF Nodes
Once you have structured, extracted data, routing is where the workflow actually pays for itself. n8n's Switch node is the natural tool here: it lets you define multiple output branches based on a single field's value, instead of chaining a dozen IF nodes together.
A typical routing setup for a shared support inbox might look like:
Switch node - Route by: {{ $json.intent }}
Output 0: "support_request" -> Create ticket in helpdesk tool
Output 1: "sales_inquiry" -> Notify sales Slack channel + CRM lead creation
Output 2: "invoice" -> Save to accounting folder + notify AP team
Output 3: "spam" -> Archive silently, log for review
Fallback: "other" -> Forward to a human triage inboxEach branch then continues into its own set of nodes — an HTTP Request node calling your helpdesk API, a Slack node posting a formatted message, a database insert via Postgres or Airtable nodes. Because each branch is independent, you can iterate on one routing path (say, tightening the invoice-detection regex) without touching the others.
A pattern worth adopting from day one: always include a fallback branch. Emails that don't match any of your expected categories should not silently vanish. Route unmatched items to a human-reviewed inbox or a dedicated Slack channel with the raw email content attached. This turns "the automation missed something" into a five-second manual triage instead of a lost email nobody notices until a customer complains.
For routing decisions with more nuance than a single field can capture — like "high urgency AND from a known enterprise customer" — combine the Switch node with an upstream IF node or a Merge node that checks the sender against a customer list pulled from your CRM via an API call. This is where email automation starts to feel less like filtering and more like a lightweight support triage system.
Avoiding Duplicate Processing and Handling Errors Gracefully
Two operational issues will surface in almost every real-world email automation, and it's worth designing for them up front rather than discovering them in production.
Duplicate processing. If your trigger polls on an interval and something goes wrong mid-workflow (an API call times out, the workflow execution fails), a naive setup will re-process the same email on the next poll, because it was never marked as read or moved. Guard against this two ways:
- Configure the trigger's post-processing action (mark as read, move to folder) to fire as early as possible in message handling — ideally n8n handles this automatically as part of the trigger's own settings before your workflow logic even runs.
- Maintain an idempotency check downstream, such as storing the email's
Message-IDheader in a database and skipping any email whose ID you've already logged. This protects you even if the mailbox-level deduplication fails for some reason (like a workflow crash between fetch and mark-as-read).
// Idempotency check in a Code node, using a lookup table
const messageId = $json.messageId;
const alreadyProcessed = await checkDatabase(messageId); // your own lookup
if (alreadyProcessed) {
return []; // stop the workflow for this item
}Error handling. Wrap risky steps — API calls to external systems, LLM nodes with potential rate limits, file parsing that might fail on a corrupted PDF — in n8n's error handling via the "Continue on Fail" setting or a dedicated Error Trigger workflow. Route caught errors to a notification (Slack or email to yourself) so a broken workflow doesn't fail silently for days before someone notices tickets have stopped appearing. Nothing erodes trust in an automation faster than a "the ticket never showed up" complaint that turns out to be a workflow that's been quietly erroring out since last Tuesday.
Rate limits. If you're routing to a CRM, helpdesk, or LLM API, add a small delay (n8n's Wait node) or batch processing logic if you expect email bursts — a newsletter blast bouncing replies, for instance, could trigger dozens of workflow executions in a few minutes and hit API rate limits on whatever you're routing to downstream.
Testing Your Workflow Before It Touches Real Mail
Before pointing this at a live support inbox, test it properly. n8n makes this straightforward because every node's output is inspectable after execution.
- Use "Execute Workflow" with pinned test data rather than waiting for real emails to trigger it. Pin a handful of representative sample emails (a clean invoice, a messy support request, a spam email, an email with no matching pattern) as static JSON so you can re-run the whole pipeline instantly while you tune your regex or LLM prompts.
- Check every branch of the Switch node individually. It's easy to test the happy path and never confirm the fallback branch actually fires when it should.
- Verify idempotency by re-running the same test email twice. Confirm it doesn't create a duplicate ticket or double-post to Slack.
- Test with malformed input. An email with no plain-text body (HTML-only), an email with no attachments when your workflow expects one, an email from a sender with no display name — these edge cases are common in real inboxes and will break naive parsing logic if untested.
Once you're confident in the logic, start with the trigger in a "manual" or low-frequency polling mode against a real but low-stakes mailbox (a secondary alias, or a BCC copy of production mail) before cutting over the primary inbox entirely.
Practical Use Cases Worth Building First
If you're deciding where to point your first n8n email workflow, a few use cases consistently deliver disproportionate value relative to build effort:
- Invoice intake for accounts payable. Parse vendor emails, extract invoice number/amount/due date, save the PDF to a shared drive, and post a summary to an AP Slack channel or create a row in a spreadsheet/database for tracking.
- Support ticket triage. Classify incoming support emails by urgency and topic using an LLM node, then create tickets in your helpdesk tool (Zendesk, Freshdesk, or a custom system via HTTP Request) with the classification already attached, saving your support team the first-pass sorting work.
- Lead qualification from a contact form or sales inbox. Extract company name, use case, and budget signals from inbound emails, cross-reference against your CRM to flag existing accounts, and route hot leads directly to a sales rep's Slack DM.
- Document collection workflows. For anything requiring signed contracts, IDs, or compliance paperwork sent as attachments, auto-extract and file them by sender and date, with a notification when a required document is missing from an otherwise-expected email.
- Auto-drafted replies for common questions. Rather than fully automating outbound replies (risky for tone and accuracy), use an LLM node to draft a suggested reply and drop it into a "Needs Review" queue — a human approves or edits before sending. This keeps a person in the loop while eliminating the blank-page problem for repetitive questions.
Each of these follows the same skeleton covered in this article: trigger, parse, classify, route, notify. Once you've built one, adapting the pattern to the next use case is mostly a matter of swapping the extraction logic and the routing destinations.
Where This Fits Into Your Broader Automation Stack
Email parsing and routing is rarely the end goal — it's usually the entry point into a larger system. The invoice you extract from an email might need to flow into an accounting API. The support ticket you create might need a follow-up workflow that checks for a response after 24 hours and escalates if none arrives. The lead you qualify might trigger a multi-step nurture sequence.
This is exactly why treating email as a first-class trigger in a general-purpose workflow tool like n8n, rather than relying on isolated mail-client rules, matters. Every node you build for parsing and routing email becomes reusable infrastructure — the same LLM classification node you built for support triage can be repurposed for classifying support tickets from a different channel entirely, like a chat widget or an API webhook.
As you get comfortable with triggers, expression syntax, the Switch node, and error handling, you'll find that email automation is really just a specific application of a more general skill: connecting an event source to structured decision logic and downstream actions. That skill transfers directly to building AI agents that need to read, understand, and act on real-world data — which is exactly where this pattern is headed next, as more of these routing and classification decisions get handed off to LLM-powered reasoning rather than static regex.
If you want to go deeper into combining n8n with AI models to build agents that don't just parse and route but actually reason about incoming data, make decisions, and take multi-step actions, check out our n8n AI Agent Tutorial course on teachyou.ai. It picks up exactly where this article leaves off — turning the parsing-and-routing patterns here into full autonomous agents that handle email, support tickets, and business processes end to end.
BootcampA 30-day guided bootcamp: build, harden and ship a production autonomous agent from scratch.
AI AgentsUnderstand how AI agents really work: the loop, the tools, the memory, and why most agent projects fail.