Intermediate~20 min setupCommunication & EmailVerified April 2026
Slack logo
Gmail logo

How to Forward Gmail Emails to Slack Channels with n8n

Polls Gmail for emails matching specific senders, subjects, or labels, then posts formatted summaries to designated Slack channels automatically.

Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for

Teams that need emails from specific senders or with specific labels routed to the right Slack channel without anyone manually copy-pasting

Not ideal for

Organizations that need true real-time forwarding under 30 seconds — use a Gmail push notification via Google Pub/Sub instead

Sync type

scheduled

Use case type

notification

Real-World Example

💡

A 12-person e-commerce team receives vendor invoices, customer support emails, and shipping alerts all in one Gmail inbox. Before this workflow, the ops manager forwarded emails manually to #vendors, #support, and #logistics in Slack — averaging 25 manual forwards per day. After setting up n8n with label-based routing, every email lands in the right channel within 5 minutes of arrival, and the ops manager stopped touching it entirely.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

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

Skip the setup

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.

Gmail account with Gmail API enabled in Google Cloud Console and an OAuth 2.0 Client ID + Secret created
Slack workspace with a custom app created at api.slack.com/apps, with chat:write and channels:read bot token scopes enabled
n8n instance running — either self-hosted (Docker or npm) or on n8n Cloud
Your Slack bot invited to every channel it needs to post in before the workflow activates

Optional

Gmail labels or filters already set up on your Gmail account if you're routing by label — n8n reads existing labels, it doesn't create them

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Message ID
Sender Address
Subject Line
Plain Text Body
Slack Channel ID
Slack Message Text
3 optional fields▸ show
Sender Name
Date Received
Gmail Labels

Step-by-Step Setup

1

n8n Dashboard > + New Workflow

Create a new n8n workflow

Log into your n8n instance at your self-hosted URL or app.n8n.cloud. Click the orange '+' button in the top-left sidebar to create a blank workflow. Give it a name like 'Gmail → Slack Forwarder' by clicking 'Untitled Workflow' at the top. You'll land on a blank canvas with a 'Click to add first step' prompt in the center.

  1. 1Log into your n8n instance
  2. 2Click the orange '+' button in the left sidebar
  3. 3Click 'Untitled Workflow' at the top center and type 'Gmail → Slack Forwarder'
  4. 4Press Enter to save the name
What you should see: You should see a blank canvas with your workflow name displayed in the top bar and a '+' node in the center waiting for your first step.
Common mistake — If you're on n8n Cloud's free tier, you get 5 active workflows. If you're already at the limit, you'll need to deactivate one before this will run on a schedule.
2

Canvas > + Node > Gmail > Email Received (Trigger)

Add the Gmail trigger node

Click the '+' node on the canvas to open the node picker. Search for 'Gmail' in the search box and select it. Under the Trigger section, choose 'Email Received' — this is the polling trigger that checks for new emails on a schedule. You'll see a configuration panel slide in from the right with fields for credentials, filters, and poll interval.

  1. 1Click the '+' node in the center of the canvas
  2. 2Type 'Gmail' in the search field
  3. 3Click 'Gmail' under the Apps section
  4. 4Select 'Email Received' under Trigger
  5. 5Click 'Create New Credential' if you haven't connected Gmail yet
What you should see: The Gmail node appears on the canvas and the right-side panel shows fields for 'Credential to connect with', 'Poll Times', and 'Filters'.
Common mistake — n8n's Gmail node uses OAuth2 and requires your Google account to have Gmail API enabled in Google Cloud Console. If you see 'Error: access_denied' during OAuth, your Cloud project may be in 'Testing' mode — you'll need to add your email as a test user under OAuth consent screen.
n8n
+
click +
search apps
Slack
SL
Slack
Add the Gmail trigger node
Slack
SL
module added
3

Gmail Node Panel > Credential to connect with > Create New Credential

Connect your Gmail account

In the Gmail node panel, click 'Create New Credential' next to the credentials dropdown. A pop-up will ask for your OAuth Client ID and Client Secret — get these from Google Cloud Console under APIs & Services > Credentials. Paste them in, click 'Sign in with Google', and authorize n8n to read your Gmail. Once connected, the credential name appears in the dropdown with a green checkmark.

  1. 1Click the credentials dropdown and select 'Create New Credential'
  2. 2Open Google Cloud Console at console.cloud.google.com in a new tab
  3. 3Navigate to APIs & Services > Credentials and copy your OAuth 2.0 Client ID and Secret
  4. 4Paste both values into the n8n credential form
  5. 5Click 'Sign in with Google' and complete the OAuth flow
What you should see: The credential dropdown now shows your Gmail address with a green dot. The node panel updates to show filter options.
Common mistake — The Google OAuth app must have the Gmail API scope 'https://www.googleapis.com/auth/gmail.readonly' enabled. If you only see 'gmail.send' scope in your Cloud project, the trigger won't have permission to read incoming emails.
n8n settings
Connection
Choose a connection…Add
click Add
Slack
Log in to authorize
Authorize n8n
popup window
Connected
green checkmark
4

Gmail Node Panel > Poll Times > Filters

Configure Gmail filters and poll interval

Set 'Poll Times' to every 5 minutes using the cron expression '*/5 * * * *' — this is the shortest practical interval for email forwarding without hammering the API. Under 'Filters', choose your filter type: use 'Sender' to match a specific email address, 'Subject' for keyword matching, or 'Label Name' to catch pre-labeled emails. You can also combine filters using the 'Simple' filter syntax or switch to 'Custom' to write a Gmail search query directly like 'from:[email protected] label:urgent'.

  1. 1Click the 'Poll Times' field and select 'Every X Minutes'
  2. 2Set the interval to 5
  3. 3Scroll down to 'Filters' and click 'Add Filter'
  4. 4Select filter type: Sender, Subject, or Label Name
  5. 5Enter your filter value, e.g. '[email protected]' or 'invoices'
What you should see: The node panel shows your poll interval and at least one filter row. Clicking 'Test Step' at the bottom should return sample emails matching your filter from the last 24 hours.
Common mistake — If you leave Filters empty, the trigger fires on every single incoming email. On a busy Gmail account that can mean hundreds of Slack messages per day. Always set at least one filter before activating.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Gmail
GM
notified
5

Gmail Node Panel > Test Step button

Test the Gmail trigger

Click 'Test Step' at the bottom of the Gmail node panel. n8n polls your Gmail inbox right now and returns up to 10 matching emails as JSON objects. You'll see the raw output in the panel on the right — each item contains fields like subject, from, text, html, date, and messageId. Confirm the emails shown match your filter criteria before moving on. If you see zero results, send yourself a test email matching your filter, wait 60 seconds, and try again.

  1. 1Click 'Test Step' at the bottom of the Gmail node panel
  2. 2Wait 5-10 seconds for n8n to poll Gmail
  3. 3Review the output items in the right-side data panel
  4. 4Confirm subject, from, and body fields are populated correctly
What you should see: You should see 1-10 email objects in the output panel, each with fields including subject, from.value[0].address, text, html, and date.
n8n
▶ Run once
executed
Slack
Gmail
Gmail
🔔 notification
received
6

Canvas > + Connector from Gmail Node > Search 'IF' > IF (Core)

Add an IF node to route by channel

Click the '+' connector coming out of the Gmail node to add the next node. Search for 'IF' and add the core IF node. This is where you split emails into different Slack channels based on sender or label. Set Condition 1 to check '{{ $json.from.value[0].address }}' contains 'vendor.com' for the vendor channel route. Add more conditions using the '+Add Condition' button for each channel you want to route to. The IF node has a 'true' and 'false' output branch — true goes to your first Slack channel, false continues to additional IF nodes or a default channel.

  1. 1Click the '+' connector on the right side of the Gmail node
  2. 2Search for 'IF' and select 'IF' under Core nodes
  3. 3Set Value 1 to '{{ $json.from.value[0].address }}'
  4. 4Set Operation to 'Contains'
  5. 5Set Value 2 to your target domain or email, e.g. 'vendor.com'
What you should see: The IF node appears on the canvas with two output connectors labeled 'true' and 'false'. Hovering over each shows which branch will fire for matching vs non-matching emails.
Common mistake — If you need to route to more than 3 channels, chaining multiple IF nodes gets messy fast. At 4+ channels, switch to a Switch node instead — it handles multi-branch routing in a single node with cleaner canvas layout.
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
7

Canvas > IF Node True Branch > + > Slack > Message > Post

Add the Slack node to the true branch

Click the '+' connector on the 'true' output of the IF node. Search for 'Slack' and add it. Set Resource to 'Message' and Operation to 'Post'. Connect your Slack credentials by clicking 'Create New Credential' — you'll need a Slack Bot Token (starts with xoxb-) from your Slack app configuration at api.slack.com/apps. Set Channel to the target channel name like '#vendor-comms'. In the Message Text field, build your formatted message using Gmail fields.

  1. 1Click the '+' connector on the 'true' output of the IF node
  2. 2Search for 'Slack' and select it
  3. 3Set Resource to 'Message' and Operation to 'Post'
  4. 4Click 'Create New Credential', paste your Slack Bot Token (xoxb-...)
  5. 5Set Channel to your target channel, e.g. '#vendor-comms'
What you should see: The Slack node panel shows your bot credential, target channel, and a text field for the message body. No red error indicators should be visible.
Common mistake — Your Slack bot must be invited to the target channel before messages will post. If you see 'channel_not_found' or 'not_in_channel' errors during testing, type '/invite @YourBotName' in the Slack channel first.
8

Slack Node Panel > Text Field

Build the Slack message format

In the Slack node's Text field, write a formatted message that includes the key email fields. Use n8n's expression syntax with double curly braces to pull values from the Gmail node. A clean format includes the sender, subject, snippet of the body, and a note about the original email. Keep the body preview short — 300 characters is enough to give context without flooding the channel. You can also use Slack's Block Kit markup if you toggle 'Send as Blocks' on, but plain text with line breaks works fine for most teams.

  1. 1Click into the 'Text' field in the Slack node panel
  2. 2Click the expression toggle (the '{x}' icon) to enable dynamic values
  3. 3Type your message template using n8n expression syntax
  4. 4Preview the rendered message by clicking 'Test Step'
What you should see: The Text field shows your template with orange expression tokens for dynamic values. After clicking Test Step, the output panel shows the exact message string that will post to Slack.
Common mistake — Map fields using the variable picker — don't type field names manually. Hand-typed variable names often have invisible spacing errors that produce blank output.
9

Canvas > IF Node False Branch > + > No Operation (or additional Slack node)

Handle the default (false) branch

Click the '+' connector on the 'false' output of the IF node. If you have a catch-all channel like '#general-emails', add another Slack node here pointed at that channel. If you only want specific emails forwarded and nothing else, add a 'No-Op' node (search for 'No Operation') to explicitly terminate the false branch — this prevents n8n from throwing an error about an unconnected branch. Label this branch clearly so future you knows it's intentional.

  1. 1Click the '+' connector on the 'false' output of the IF node
  2. 2Search for 'No Operation' and add it if you want to drop non-matching emails
  3. 3Alternatively, add another Slack node for a catch-all channel
  4. 4Double-click the No Operation node and add a note: 'Non-matching emails — intentionally dropped'
What you should see: Both the true and false branches of the IF node are connected to nodes. The canvas shows a complete path with no dangling connectors.
Common mistake — Leaving the false branch unconnected causes n8n to log execution errors even though no data is lost. Always terminate both branches explicitly.
10

Canvas > Test Workflow button (bottom toolbar)

Test the full workflow end-to-end

Click 'Test Workflow' at the bottom of the canvas. n8n runs the entire workflow using the last data fetched from Gmail. Watch each node light up green (success) or red (error) as execution flows through. Click any node to see its input and output data side by side. Verify that the Slack message actually appeared in your target channel — check Slack now. If a node is red, click it to read the error message before proceeding.

  1. 1Click 'Test Workflow' in the bottom toolbar
  2. 2Watch the execution flow across nodes on the canvas
  3. 3Click the Slack node to confirm the output shows a successful message_id
  4. 4Open Slack and verify the message appeared in the correct channel
What you should see: All nodes show green checkmarks. In Slack, you see a new message in your target channel with the sender, subject, and body preview formatted correctly.
11

Canvas > Active/Inactive Toggle (top right) > Executions Tab

Activate the workflow

Click the 'Inactive' toggle in the top-right of the canvas to flip it to 'Active'. n8n will now poll Gmail every 5 minutes automatically. The workflow card in your dashboard shows a green 'Active' badge. Monitor the first few executions by clicking into the workflow and checking the Executions tab — you'll see a log of every poll with input/output data and execution time. Set up an error notification (via the workflow Settings > Error Workflow option) so you're alerted if the workflow fails silently.

  1. 1Click the 'Inactive' toggle in the top-right corner of the canvas
  2. 2Confirm the toggle switches to 'Active' with a green indicator
  3. 3Click the 'Executions' tab to monitor the first few runs
  4. 4Optionally go to Settings > Error Workflow and connect an error notification workflow
What you should see: The workflow card in your n8n dashboard shows a green 'Active' badge. Within 5 minutes, the first scheduled execution appears in the Executions tab with a success or error status.
Common mistake — n8n's polling trigger does not deduplicate across restarts by default. If your server restarts, the next poll may re-process emails it already forwarded. Add a deduplication step using the messageId field to prevent duplicate Slack messages — covered in the Pro Tip below.

This Code node runs between the Gmail trigger and the IF node. It strips HTML from the email body, truncates the plain text to 300 characters, formats the date into a readable string, and checks a static data store of already-processed message IDs to block duplicates. Paste this as a Code node (using JavaScript) immediately after the Gmail trigger on your canvas.

JavaScript — Code Node// n8n Code Node: Email formatter + deduplication
▸ Show code
// n8n Code Node: Email formatter + deduplication
// Place this between Gmail Trigger and IF node
const items = $input.all();

... expand to see full code

// n8n Code Node: Email formatter + deduplication
// Place this between Gmail Trigger and IF node

const items = $input.all();
const processedIds = $getWorkflowStaticData('global').processedMessageIds || [];

const results = [];

for (const item of items) {
  const email = item.json;
  const messageId = email.id;

  // Skip if we've already forwarded this email
  if (processedIds.includes(messageId)) {
    continue;
  }

  // Strip HTML tags from body if plain text is missing
  let bodyText = email.text || '';
  if (!bodyText && email.html) {
    bodyText = email.html
      .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
      .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
      .replace(/<[^>]+>/g, ' ')
      .replace(/\s+/g, ' ')
      .trim();
  }

  // Truncate body to 300 characters
  const bodyPreview = bodyText.length > 300
    ? bodyText.substring(0, 297) + '...'
    : bodyText;

  // Format the received date
  const receivedDate = new Date(email.date);
  const formattedDate = receivedDate.toLocaleString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
    hour12: true
  });

  // Extract sender info safely
  const senderAddress = email.from?.value?.[0]?.address || '[email protected]';
  const senderName = email.from?.value?.[0]?.name || senderAddress;

  // Build the Slack message text
  const slackMessage = [
    `📧 *New email from ${senderName}* (${senderAddress})`,
    `*Subject:* ${email.subject || '(no subject)'}`,
    `*Received:* ${formattedDate}`,
    '',
    bodyPreview
  ].join('\n');

  // Mark this message as processed
  processedIds.push(messageId);

  results.push({
    json: {
      ...email,
      senderAddress,
      senderName,
      bodyPreview,
      formattedDate,
      slackMessage
    }
  });
}

// Persist the updated list of processed IDs (keeps last 500 to prevent unbounded growth)
const staticData = $getWorkflowStaticData('global');
staticData.processedMessageIds = processedIds.slice(-500);

return results;

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

VerdictWhy n8n for this workflow

Use n8n for this if you're self-hosting, need custom routing logic beyond what a simple Zap allows, or want to keep email data off third-party servers. The code node gives you full control over how messages are formatted, deduplicated, and filtered — you're not limited to the field mapping UI that other platforms enforce. A second good reason: if you're already running n8n for other workflows, adding this costs zero extra dollars. The one case where you'd skip n8n: if your team has no one comfortable reading a JSON path like from.value[0].address, go with Zapier instead. The setup is 10 minutes and requires zero code.

Cost

n8n Cloud's Starter plan costs $20/month and includes 2,500 executions. At a 5-minute poll interval, you burn through roughly 8,640 executions per month just from the Gmail trigger firing — even when no emails match. That puts you on the Growth plan at $50/month. Self-hosted n8n costs nothing in licensing. If you run it on a $6/month DigitalOcean droplet, your total cost is $6/month regardless of execution count. Zapier by comparison charges per task: at 50 forwarded emails per day (1,500/month), you're on the $19.99/month Starter plan. Make's free tier handles 1,000 operations/month, which covers about 33 forwarded emails per day before you hit the $9/month Core plan.

Tradeoffs

Zapier handles this use case in fewer clicks — their Gmail 'New Email Matching Search' trigger has a clean UI for building Gmail search queries without touching JSON paths, and setup genuinely takes 8 minutes. Make's Gmail module is similarly straightforward and its scenario debugger is better than n8n's for stepping through failed executions one item at a time. Pipedream's Gmail source supports real push notifications via Google Pub/Sub out of the box, giving you sub-5-second latency vs n8n's 5-minute polling floor — that's a real gap if timing matters. Power Automate's Gmail connector is thin and unreliable; skip it for this workflow. n8n wins on the code node: no other platform gives you a full JavaScript runtime mid-workflow with access to static data for deduplication, and you control the exact Slack message format without fighting a GUI.

Three things you'll hit after setup. First: Gmail's API daily quota is 1 billion units per day for most projects, but the 'list messages' call costs 5 units per request and 'get message' costs 5 more — at a 5-minute poll interval that's around 3,000 units per day, well under the limit, but if you duplicate workflows per account carelessly you can exhaust quota on a shared Cloud project. Second: n8n's static data store (used for deduplication) is stored in the workflow's metadata and has no automatic expiry — after 6 months of high email volume, the processedIds array can grow large enough to slow execution. The code node above caps it at 500 entries, which is the right call. Third: Slack's Block Kit formatting is tempting but the Slack node's 'Blocks' field requires a valid JSON array — a malformed block silently drops the message without an error in n8n's execution log. Stick with plain text formatting until you've verified the workflow is stable.

Ideas for what to build next

  • Add a digest mode for low-priority channelsInstead of posting every email instantly, batch emails into a single daily or hourly digest message in Slack using n8n's Schedule trigger and an Aggregate node. Reduces Slack noise for channels like #newsletters or #vendor-updates.
  • Create a Slack reply that logs back to GmailExtend this workflow to listen for Slack thread replies on forwarded emails and send those replies back to the original Gmail thread using the Gmail 'Reply' operation. Keeps the email thread and Slack conversation in sync.
  • Attach email files to the Slack messagePull email attachments using the Gmail node's 'Download Attachment' operation and upload them to Slack alongside the message using the Slack 'Upload File' operation. Useful for invoices and reports that need to be reviewed in Slack directly.

Related guides

Was this guide helpful?
Slack + Gmail overviewn8n profile →