Trigger n8n Workflows from Incoming Emails
n8n is brilliant for workflow automation. But when it comes to email triggers, you're stuck with the IMAP node — polling every few minutes, wrestling with OAuth tokens, and parsing raw MIME data.
There's a better way: trigger workflows instantly when emails arrive, with clean JSON payloads ready to use.
The IMAP Problem
n8n's built-in IMAP node works, but it has friction:
- Polling delays — 1-5 minute intervals, not real-time
- OAuth headaches — Gmail tokens expire, connections drop
- MIME parsing — raw email data needs manual extraction
- No retry logic — if n8n is down during a poll, emails are missed
For simple use cases, this is fine. For production workflows, you want something more reliable.
Email to Webhook
The solution: convert incoming emails to webhooks. Emails arrive → instant HTTP POST to n8n → workflow runs.
Here's how to set it up with Mailhooks.
Two Ways to Connect
Option A: Mailhooks Community Node
We've built a community node for n8n that makes setup even easier:
# Install in your n8n instance
npm install n8n-nodes-mailhooksOr install via n8n's Community Nodes settings panel.
The node provides:
- Mailhooks Trigger — fires when emails arrive (real-time, no polling)
- Mailhooks — fetch emails, list inboxes, manage hooks via API
Option B: Generic Webhook
If you prefer not to install community nodes, use n8n's built-in Webhook node:
Setup: 5 Minutes
1. Create a Webhook Trigger in n8n
- Create a new workflow
- Add a Webhook node as the trigger
- Set HTTP Method to POST
- Copy the Production Webhook URL
2. Create a Mailhooks Inbox
- Sign up at mailhooks.dev (free tier available)
- Go to Dashboard → Inboxes → Create Inbox
- Name it (e.g., "n8n Support")
- Add a Webhook hook with your n8n URL
- Save
You'll get an email address like support@yourteam.mailhooks.email
3. Test It
Send an email to your new address. Watch n8n execute instantly.
The Payload
When an email arrives, your webhook receives clean JSON:
{
"id": "msg_abc123",
"from": "customer@example.com",
"fromName": "Jane Customer",
"to": "support@yourteam.mailhooks.email",
"subject": "Help with my order #12345",
"text": "Hi, I haven't received my order yet...",
"html": "<p>Hi, I haven't received my order yet...</p>",
"date": "2025-01-28T10:30:00Z",
"attachments": [
{
"filename": "screenshot.png",
"contentType": "image/png",
"size": 45678,
"url": "https://files.mailhooks.dev/..."
}
]
}No MIME parsing. No base64 decoding. Just use {{ $json.from }} in your next node.
Real-World Workflows
Support Ticket from Email
Automatically create tickets when customers email:
[Webhook] → [Notion] Create Page
→ [Slack] Notify #supportNotion node config:
- Database: Support Tickets
- Title:
{{ $json.subject }} - Customer:
{{ $json.from }} - Description:
{{ $json.text }}
Slack node config:
- Message:
📧 New ticket from {{ $json.fromName }}: {{ $json.subject }}
Lead Capture from Contact Form
When leads email your sales address:
[Webhook] → [HubSpot] Create Contact
→ [Gmail] Send Auto-Reply
→ [Slack] Notify #salesHubSpot node:
- Email:
{{ $json.from }} - First Name:
{{ $json.fromName.split(' ')[0] }} - Lead Source: "Email Inquiry"
- Notes:
{{ $json.text }}
Invoice Processing
Vendors send invoices to a dedicated address:
[Webhook] → [IF] Has PDF Attachment?
Yes → [HTTP Request] Download PDF
→ [Google Drive] Upload to Invoices folder
→ [Airtable] Log invoice record
No → [Slack] "Invoice missing attachment"Attachment download:
// In HTTP Request node
URL: {{ $json.attachments[0].url }}
Response Format: FileAuto-Responder
Acknowledge emails immediately:
[Webhook] → [Gmail] Send ReplyGmail node:
- To:
{{ $json.from }} - Subject:
Re: {{ $json.subject }} - Body: "Thanks for reaching out! We've received your email and will respond within 24 hours."
Order Notifications to Slack
E-commerce order confirmations forwarded to your team:
[Webhook] → [Code] Extract Order Details
→ [Slack] Post to #ordersCode node:
const text = $json.text;
const orderMatch = text.match(/Order #(\d+)/);
const totalMatch = text.match(/Total: \$?([\d.]+)/);
return {
orderId: orderMatch ? orderMatch[1] : 'Unknown',
total: totalMatch ? totalMatch[1] : 'Unknown',
customer: $json.from
};Slack message:
🛒 New Order #{{ $json.orderId }}
Customer: {{ $json.customer }}
Total: ${{ $json.total }}Email to Database
Archive all emails to a database:
[Webhook] → [Postgres] Insert RowPostgres node:
INSERT INTO emails (from_address, subject, body, received_at)
VALUES (
'{{ $json.from }}',
'{{ $json.subject }}',
'{{ $json.text }}',
'{{ $json.date }}'
)Handling Attachments
Mailhooks provides direct URLs for attachments. Download them in n8n:
Save to Google Drive
[Webhook] → [IF] Has Attachments?
→ [HTTP Request] Download File
→ [Google Drive] UploadHTTP Request config:
- URL:
{{ $json.attachments[0].url }} - Response Format: File
Google Drive config:
- File Name:
{{ $json.attachments[0].filename }} - Parent Folder: Your folder ID
Process Multiple Attachments
Use a Loop Over Items node:
[Webhook] → [Split In Batches] attachments array
→ [HTTP Request] Download each
→ [Google Drive] Upload eachFiltering & Routing
By Sender
[Webhook] → [Switch] Check sender domain
@vip-client.com → [Priority handling]
@vendor.com → [Invoice processing]
default → [Standard queue]Switch conditions:
{{ $json.from.endsWith('@vip-client.com') }}
{{ $json.from.endsWith('@vendor.com') }}By Subject
[Webhook] → [Switch] Check subject keywords
contains "urgent" → [High priority]
contains "invoice" → [Accounting]
default → [General inbox]By Recipient (Catch-All)
With Mailhooks, any address at your domain works:
support@team.mailhooks.emailsales@team.mailhooks.emailinvoices@team.mailhooks.email
Route in n8n:
// Switch node
{{ $json.to.includes('support@') }}
{{ $json.to.includes('sales@') }}
{{ $json.to.includes('invoices@') }}Reliability
What if n8n is Down?
Mailhooks queues failed webhooks and retries automatically:
- First retry: 1 minute
- Then: 5 min, 15 min, 1 hour
- Continues for 24 hours
Your emails aren't lost if n8n restarts or has downtime.
Monitoring Deliveries
Check webhook status in Mailhooks dashboard:
- ✅ Delivered — n8n responded 2xx
- 🔄 Pending — queued for retry
- ❌ Failed — all retries exhausted
Compared to IMAP
Feature | Mailhooks Node | n8n IMAP Node |
|---|---|---|
Latency | Instant (< 10s) | 1-5 minutes |
Setup | 2 minutes | 15+ minutes |
OAuth management | None | Token refresh needed |
Email parsing | Pre-parsed JSON | Raw MIME |
Attachments | Direct URLs | Base64 encoded |
Downtime handling | Queued + retries | Emails missed |
Multiple addresses | Unlimited catch-all | One per credential |
Community node | Built-in |
Advanced: Custom Domain
Instead of @yourteam.mailhooks.email, use your own domain:
- Add domain in Mailhooks dashboard
- Set MX records to Mailhooks servers
- Create inboxes with your domain
Now emails to support@yourbusiness.com trigger your n8n workflows.
Getting Started
- Sign up for Mailhooks — free tier includes 100 emails/month
- Create an inbox with your n8n webhook URL
- Send a test email
- Build your workflow
Total setup: 5-10 minutes. No OAuth, no polling, no MIME parsing.
Need help setting up email-triggered workflows? Check our n8n integration docs or reach out.
Ready to receive email in your app?
Create your first mailhook in minutes. No IMAP, no mail servers, no parsing.
Get Started for Free