

How to Send Gmail Sales Alerts to Slack with n8n
Polls Gmail every minute for high-priority prospect emails and posts a formatted Slack message with sender, subject, and email preview to a sales channel.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Small-to-mid sales teams who self-host n8n and need instant Slack alerts when prospect emails land in Gmail without paying per-task fees.
Not ideal for
Teams using Outlook or needing sub-30-second latency — Gmail's API polling minimum is 1 minute and webhook push is not natively supported in n8n's Gmail node.
Sync type
real-timeUse case type
notificationReal-World Example
A 12-person SaaS sales team uses this to ping their #inbound-leads Slack channel whenever a prospect from a tracked domain sends an email marked important in Gmail. Before this, AEs checked Gmail manually between calls and routinely missed responses for 2-3 hours during busy days. Now the whole team sees new prospect emails within 60 seconds and can claim follow-ups directly in Slack.
What Will This Cost?
Drag the slider to your expected monthly volume.
Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.





Prices shown for annual billing. Based on published pricing as of April 2026.
Estimated ROI
1000
min saved/mo
$583
labor value/mo
Free
no platform cost
Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.
Implementation
Import this workflow directly into n8n
Copy the pre-built n8n blueprint and paste it straight into n8n. All modules, filters, and field mappings are already configured — you just need to connect your accounts.
Before You Start
Make sure you have everything ready.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Sender Email Address | ||
| Sender Display Name | ||
| Email Subject | ||
| Email Body Preview | ||
| Gmail Thread ID | ||
| Gmail Message ID | ||
2 optional fields▸ show
| Email Received Timestamp | |
| Importance Label |
Step-by-Step Setup
n8n Dashboard > Workflows > + New Workflow
Create a new n8n workflow
Log into your n8n instance and click the '+ New Workflow' button in the top-right corner of the Workflows dashboard. Give it a name like 'Gmail → Slack Sales Alerts' so it's easy to find later. You'll land on a blank canvas with a single grey trigger node in the center. All subsequent nodes will chain off this.
- 1Log into your n8n instance at your host URL or localhost:5678
- 2Click '+ New Workflow' in the top-right corner
- 3Click the pencil icon next to 'My Workflow' and rename it to 'Gmail → Slack Sales Alerts'
- 4Click the grey trigger node in the center of the canvas to open the node selector
Canvas > Trigger Node > Search 'Gmail' > Gmail Trigger
Add and configure the Gmail trigger node
Search for 'Gmail' in the node selector and choose the Gmail node. Set the operation to 'Trigger' mode — this polls for new emails on a schedule. Set the poll interval to 1 minute (the minimum Gmail allows via the API). You'll see a 'Filters' section where you can restrict which emails fire the trigger.
- 1Type 'Gmail' in the search box and select 'Gmail Trigger'
- 2Click 'Create new credential' to connect your Google account
- 3Set 'Poll Times' to 'Every Minute'
- 4Under 'Filters', set 'Label' to 'IMPORTANT' to catch high-priority emails
- 5Optionally add a second filter: 'Search' field with value 'is:unread' to avoid reprocessing read emails
Gmail Trigger Node > Credential > + Create New > Google OAuth2
Connect your Google account credentials
Click 'Create new credential' inside the Gmail Trigger node. n8n will open a Google OAuth flow. You need to grant the 'gmail.readonly' scope at minimum. If you plan to mark emails as read after processing (recommended), also grant 'gmail.modify'. Complete the OAuth popup and return to n8n.
- 1Click the 'Credential' dropdown and select '+ Create New Credential'
- 2Choose 'Google OAuth2 API' from the credential type list
- 3Click 'Sign in with Google' and log in with the Gmail account you want to monitor
- 4Accept the permissions request in the Google popup
- 5Click 'Save' on the credential modal in n8n
Canvas > + > Core > IF
Add a filter node to isolate high-priority senders
Click the '+' button to the right of the Gmail Trigger node and add an 'IF' node. This is where you filter by sender domain or specific email addresses — so only emails from real prospects fire the Slack alert. Without this, every important email (including internal ones) will notify the channel.
- 1Click the '+' connector on the right side of the Gmail Trigger node
- 2Search for 'IF' and select the IF node from the Core section
- 3Set Value 1 to the expression: {{ $json.from }}
- 4Set the condition to 'Contains'
- 5Set Value 2 to your prospect domain, e.g. 'acme.com', or use a comma-separated list by chaining multiple OR conditions
Canvas > IF Node (true branch) > + > Core > Code
Add a Code node to extract and format email data
Connect a Code node to the 'true' output of the IF node. This is where you pull the sender name, email address, subject, and a plain-text preview of the email body. The Gmail Trigger returns the body as base64-encoded HTML — you need to decode and truncate it here before sending it to Slack. This step is what makes the Slack message actually readable.
- 1Click the '+' on the 'true' output of the IF node
- 2Search for 'Code' and select the Code node
- 3Set language to 'JavaScript'
- 4Paste the transformation script from the Pro Tip section below into the code editor
- 5Click 'Test step' to verify the output shows decoded subject, sender, and body preview fields
Paste this into the Code node (step 5) between the IF node and the Slack node. It decodes the base64url email body, extracts sender name and address from the raw From header, truncates the body to 300 characters, and builds the Gmail thread URL — all fields the Slack Block Kit message needs.
JavaScript — Code Node// n8n Code Node — Gmail body decoder and field extractor▸ Show code
// n8n Code Node — Gmail body decoder and field extractor // Runs once per email item passed from the IF node const items = $input.all();
... expand to see full code
// n8n Code Node — Gmail body decoder and field extractor
// Runs once per email item passed from the IF node
const items = $input.all();
const results = [];
for (const item of items) {
const raw = item.json;
// Extract sender name and email from 'From' header
// Gmail returns: 'Display Name <[email protected]>' or just '[email protected]'
const fromHeader = raw.from || '';
const nameMatch = fromHeader.match(/^(.+?)\s*</);
const emailMatch = fromHeader.match(/<([^>]+)>/);
const senderName = nameMatch ? nameMatch[1].trim() : fromHeader;
const senderEmail = emailMatch ? emailMatch[1] : fromHeader;
// Decode base64url email body
// Gmail uses base64url: '-' instead of '+', '_' instead of '/'
let bodyPreview = raw.snippet || '(no preview available)';
try {
const parts = raw.payload?.parts || [];
const textPart = parts.find(p => p.mimeType === 'text/plain')
|| parts.flatMap(p => p.parts || []).find(p => p.mimeType === 'text/plain');
if (textPart?.body?.data) {
const base64 = textPart.body.data
.replace(/-/g, '+')
.replace(/_/g, '/');
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
// Trim whitespace and truncate to 300 chars for Slack readability
bodyPreview = decoded.replace(/\s+/g, ' ').trim().substring(0, 300);
if (decoded.length > 300) bodyPreview += '...';
}
} catch (e) {
// Fall back to Gmail's snippet if body decode fails
bodyPreview = raw.snippet || '(decode error — check email format)';
}
// Convert Gmail internalDate (Unix ms) to readable string
const timestamp = raw.internalDate
? new Date(parseInt(raw.internalDate)).toLocaleString('en-US', {
month: 'short', day: 'numeric', year: 'numeric',
hour: 'numeric', minute: '2-digit', hour12: true
})
: 'Unknown time';
// Build Gmail thread URL for one-click access from Slack
const gmailLink = `https://mail.google.com/mail/u/0/#inbox/${raw.threadId}`;
results.push({
json: {
senderName,
senderEmail,
subject: raw.subject || '(no subject)',
bodyPreview,
receivedAt: timestamp,
gmailLink,
messageId: raw.id,
threadId: raw.threadId
}
});
}
return results;Canvas > Code Node > + > Slack > Slack Node > Credential > + Create New
Connect your Slack credentials
Click '+' after the Code node and add a Slack node. In the node settings, click 'Create new credential' and choose 'Slack OAuth2 API'. You'll be redirected to Slack to authorize n8n as an app. Make sure you're authorizing into the correct Slack workspace — the one your sales team uses.
- 1Click '+' on the Code node's output and search for 'Slack'
- 2Select the 'Slack' node and set Resource to 'Message', Operation to 'Post'
- 3Click the Credential dropdown and select '+ Create New Credential'
- 4Choose 'Slack OAuth2 API' and click 'Connect'
- 5In the Slack authorization screen, select your workspace and click 'Allow'
Slack Node > Resource: Message > Operation: Post > Channel + Text
Configure the Slack message with email details
In the Slack node, set the Channel field to your sales channel name (e.g. #inbound-leads). Set the Message Text field using the output fields from the Code node. Use Slack's Block Kit format for a clean layout — include sender name, email address, subject line, and the body preview. The email link lets reps jump straight to Gmail.
- 1Set 'Channel' to your sales Slack channel, e.g. #inbound-leads
- 2Set 'Message Type' to 'Block'
- 3In the 'Blocks' field, paste or build the Block Kit JSON using the field references from the Code node
- 4Map 'senderName' to the header block, 'subject' and 'bodyPreview' to section blocks
- 5Add a button block with the 'emailLink' field pointing to the Gmail thread URL
Canvas > Slack Node > + > Gmail > Resource: Message > Operation: Mark as Read
Add a Gmail node to mark processed emails as read
After the Slack node, add a second Gmail node to mark the email as read. This prevents the trigger from picking up the same email on the next poll cycle. Set the Resource to 'Message', Operation to 'Mark as Read', and pass the email ID from the trigger output. This is the most important deduplication step in the entire workflow.
- 1Click '+' on the Slack node's output and add a Gmail node
- 2Set Resource to 'Message' and Operation to 'Mark as Read'
- 3Set 'Message ID' to the expression: {{ $('Gmail Trigger').item.json.id }}
- 4Use the same Gmail credential you configured in step 3
- 5Click 'Test step' to confirm the email disappears from the unread filter
Workflow Settings > Error Workflow > + Create Error Workflow
Add error handling with a fallback Error Trigger node
Click the three-dot menu on any node and select 'Add node after error'. Add an Error Trigger node at the workflow level by going to Workflow Settings. If Gmail's API returns a 429 rate limit error or Slack's API is temporarily down, n8n will route the execution to the error branch instead of silently failing. Connect this to a second Slack node that posts to an #ops-alerts channel.
- 1Click the three-dot menu (⋯) in the top-right of the canvas and select 'Settings'
- 2Find 'Error Workflow' and click '+ Create Error Workflow'
- 3In the error workflow canvas, add an 'Error Trigger' node — it fires automatically on failure
- 4Connect the Error Trigger to a Slack node posting to #ops-alerts
- 5Include {{ $execution.error.message }} and {{ $execution.error.node }} in the error Slack message
Canvas > Execute Workflow (top toolbar) > Execution Log
Test the full workflow end-to-end
Send a test email from an external email address to your monitored Gmail account. Mark it as Important in Gmail manually. Then return to n8n and click 'Execute Workflow' on the main canvas. Watch the execution flow through each node — the Gmail Trigger should pick it up, the IF filter should pass it through, the Code node should format it, and Slack should receive the message. Check the execution log for any red error indicators.
- 1Send a test email from a non-Google account to your monitored Gmail address
- 2In Gmail, open the email and click the 'Important' flag (yellow bookmark icon)
- 3Return to n8n and click 'Execute Workflow' in the top toolbar
- 4Watch each node turn green as data flows through
- 5Open your Slack sales channel and confirm the formatted message arrived
Canvas > Top-right toggle > Inactive → Active
Activate the workflow and verify polling
Click the 'Inactive' toggle in the top-right of the canvas to activate the workflow. It will switch to 'Active' with a green indicator. n8n will now poll Gmail every minute. Wait 2 minutes, then send another test email to confirm the automated poll catches it without you manually triggering anything. Check the Executions tab to see the polling history.
- 1Click the 'Inactive' toggle in the top-right of the canvas — it should flip to 'Active' (green)
- 2Wait 60-90 seconds for the first automatic poll to fire
- 3Send another test email from your prospect domain
- 4Open the 'Executions' tab from the left sidebar to see the poll execution log
- 5Confirm a new execution ran and the Slack message appeared in your sales channel
Going live
Production Checklist
Before you turn this on for real, confirm each item.
Troubleshooting
Common errors and how to fix them.
Frequently Asked Questions
Common questions about this workflow.
Analysis
Use n8n for this if your team self-hosts or you're already paying for n8n Cloud — the per-execution pricing of Zapier would cost $49-$299/month for a sales team getting 200-2000 important emails monthly. n8n handles the same volume for $20/month on Cloud or effectively free if self-hosted. The second reason: the Code node. Decoding Gmail's base64url bodies and formatting Slack Block Kit messages cleanly requires actual JavaScript, and n8n gives you a full Node.js environment per execution. If your team uses Zapier exclusively and has no one comfortable editing a 30-line script, pick Make instead — its modules handle Gmail body parsing without code.
Real math: this workflow runs 1 execution per matched email. A sales team getting 10 high-priority prospect emails per day generates 300 executions/month. On n8n Cloud's Starter plan ($20/month, 2,500 executions included), that's 300 of your 2,500 — you'll never hit the limit. On Zapier's Professional plan ($49/month), 300 tasks barely registers, but if you add the IF filter as a separate Zap step, you're at 600 tasks/month. At 1,000 emails/month Zapier's Professional plan (2,000 tasks) gets tight and the next tier is $99/month. n8n self-hosted stays at server costs only — roughly $5-10/month on a small VPS.
Honest comparison: Zapier's Gmail trigger is genuinely easier to set up — 4 clicks versus n8n's credential OAuth flow, and the Slack formatter handles basic message layout without any code. If your team is non-technical and just needs sender + subject in a Slack message, Zapier's 8-minute setup wins. Make's Gmail module has better error handling out of the box and its 'Watch Emails' trigger lets you filter by label and sender in the module UI without a separate filter step. Power Automate has a native 'When a new email arrives (V3)' trigger that handles HTML-to-text conversion automatically, which saves you the base64 decode step — worth knowing if your org is already on Microsoft 365. Pipedream's Gmail source fires faster (near-instant via Gmail push notifications) rather than polling, which gives you true sub-10-second delivery versus n8n's 60-second poll. For a sales team where speed of response matters, Pipedream's latency advantage is real. n8n still wins on cost for self-hosters and on flexibility when you need to add CRM lookups, multi-channel routing, or conditional logic in the same workflow without paying per step.
Three things you'll hit after going live. First: Gmail's importance algorithm is inconsistent. Emails from new domains your account has never interacted with often skip the IMPORTANT label even if they match all your filter criteria — create a Gmail filter rule to force-label by domain. Second: the Gmail Trigger node in n8n does not deduplicate across workflow restarts. If your n8n instance crashes and restarts mid-poll, the same email can fire twice. The Mark as Read step reduces this risk significantly but doesn't eliminate it entirely for emails received during the crash window. Third: Slack's Block Kit has a 3,000-character limit per block. Email bodies longer than ~2,500 characters will cause the Slack node to throw a 'invalid_blocks' error silently. The Code node's 300-character truncation in this guide prevents this, but if you increase that limit, stay under 2,800 characters per block to be safe.
Ideas for what to build next
- →Route emails by priority into different Slack channels — Add a second IF node after the Code node that checks for keywords like 'urgent', 'contract', or 'renewal' in the subject line and routes those to a #hot-leads channel while all others go to #inbound-leads. Takes about 10 minutes to add and dramatically improves how the team triages responses.
- →Log every lead email to a Google Sheet for reporting — Add a Google Sheets node after the Slack node to append each lead email as a new row with sender, subject, timestamp, and a link to the thread. After 30 days you'll have a clean dataset showing response time, email volume by domain, and which prospects email most frequently.
- →Add a daily digest summary instead of per-email alerts — Clone this workflow and change the trigger from polling to a schedule (7 AM each morning). Instead of firing per email, accumulate unread important emails from the last 24 hours and post a single summarized list to Slack. Reduces noise for teams that get 20+ prospect emails per day.
Related guides
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup
How to Share Notion Meeting Notes to Slack with n8n
~20 min setup
How to Send Notion Meeting Notes to Slack with Zapier
~8 min setup
How to Share Notion Meeting Notes to Slack with Make
~12 min setup
How to Create Notion Tasks from Slack with Pipedream
~15 min setup