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

How to Forward Gmail Meeting Emails to Slack with n8n

Polls Gmail for emails containing meeting notes or action items, classifies them by type, and routes them to the correct Slack channel automatically.

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 teams where external meeting confirmations and follow-ups land in one inbox but need to reach multiple Slack channels by topic or project.

Not ideal for

Teams using a shared inbox tool like Front or Missive — those have native Slack routing built in and n8n adds unnecessary complexity.

Sync type

scheduled

Use case type

notification

Real-World Example

💡

A 20-person consulting firm has one partner who handles all external client meetings — confirmations, recaps, and action items all land in their Gmail. Before this workflow, they forwarded emails manually to #client-updates in Slack, which happened inconsistently and sometimes days late. Now n8n polls Gmail every 5 minutes, detects meeting-related emails using subject-line keywords, and posts a formatted Slack message to the right channel within minutes of arrival.

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 OAuth2 credentials configured in Google Cloud Console (Gmail API enabled, redirect URI set to your n8n instance URL)
Slack workspace with a bot app created at api.slack.com — bot must have 'chat:write' and 'channels:read' OAuth scopes
n8n instance running (cloud at app.n8n.io or self-hosted on v1.0+)
Bot invited to every Slack channel that will receive routed messages (e.g., #external-meetings, #client-updates, #project-alpha)

Optional

At least one meeting-related email already in your Gmail inbox to use as test data during setup

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Email Subject
Sender Name
Sender Email
Email Body (Plain Text)
Received Date
Gmail Message ID
Meeting Type
Target Slack Channel
1 optional field▸ show
Email Thread ID

Step-by-Step Setup

1

n8n Dashboard > Workflows > New Workflow

Create a new workflow in n8n

Log into your n8n instance (cloud at app.n8n.io or self-hosted). Click the orange 'New Workflow' button in the top-right corner of the Workflows dashboard. Give it a clear name like 'Gmail → Slack Meeting Distributor' — this matters when you're debugging later. You'll land on a blank canvas with a single gray 'Start' node.

  1. 1Click 'New Workflow' in the top-right corner
  2. 2Click the workflow name at the top and rename it to 'Gmail → Slack Meeting Distributor'
  3. 3Press Enter to save the name
What you should see: You should see a blank canvas with a single gray Start node in the center and the new workflow name displayed at the top of the page.
2

Canvas > Add Node > Gmail > Trigger

Add and configure the Gmail trigger node

Click the gray Start node and search for 'Gmail'. Select the Gmail node and choose 'Trigger' mode. Set the operation to 'Message Received'. n8n will poll your Gmail inbox on the schedule you define in Step 3. Connect your Google account by clicking 'Create new credential' — you'll need to authorize Gmail access via OAuth2.

  1. 1Click the '+' icon on the canvas or on the Start node
  2. 2Type 'Gmail' in the search bar and select it
  3. 3Set 'Operation' to 'Message Received'
  4. 4Click 'Create new credential' under the Credential dropdown
  5. 5Sign in with your Google account and grant Gmail read access
What you should see: You should see a green checkmark next to the credential name, and the node should show 'Message Received' as the selected operation.
Common mistake — Google OAuth2 in n8n requires an approved OAuth app if you're self-hosting. If you get a 'This app isn't verified' screen, you must add your Google account as a test user inside Google Cloud Console under OAuth consent screen settings.
n8n
+
click +
search apps
Slack
SL
Slack
Add and configure the Gmail …
Slack
SL
module added
3

Gmail Node > Parameters > Poll Times + Filters

Set polling interval and label filter

Inside the Gmail trigger node, set the 'Poll Times' field to every 5 minutes — this gives near-real-time delivery without hammering the Gmail API. Under 'Filters', add a label filter if you use Gmail labels for external meetings (e.g., 'external-meetings'). If you rely on subject keywords instead, leave the label field blank and you'll handle filtering in Step 5.

  1. 1Click the 'Poll Times' field and select 'Every 5 Minutes'
  2. 2Expand the 'Filters' section
  3. 3Set 'Label Names or IDs' to your meeting label, or leave blank to filter by keyword later
  4. 4Check 'Return All' is set to false — you want only new messages per poll
What you should see: The node parameters panel should show the poll interval and any label filter you set. The node preview will display the filter values.
Common mistake — n8n's Gmail trigger tracks processed emails using a deduplification key internally, but if you duplicate the workflow or reset it, it will reprocess old emails. Keep a note of when you first activated the workflow.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Gmail
GM
notified
4

Gmail Node > Test Step button

Test the Gmail trigger with a real email

Click 'Test Step' on the Gmail node. n8n will immediately pull recent emails from your inbox matching your filter. You need at least one real meeting-related email in your inbox for the test data to be useful — send yourself a test email with a subject like 'Re: Project Kickoff Meeting Notes' before running this step. Look at the output panel on the right and expand one email item to see its structure.

  1. 1Send a test email to your Gmail with subject 'Re: Project Kickoff Meeting Notes'
  2. 2Click 'Test Step' on the Gmail node
  3. 3Expand the output item in the right panel
  4. 4Note the field paths for subject, snippet, from, and body fields
What you should see: You should see one or more email objects in the output panel with fields including 'subject', 'snippet', 'from', 'date', and 'id'. Expand any field to see its exact value.
n8n
▶ Run once
executed
Slack
Gmail
Gmail
🔔 notification
received
5

Canvas > Add Node > IF

Add an IF node to filter for meeting-related emails

Not every email in your inbox is a meeting follow-up. Add an IF node after the Gmail trigger to check whether the subject line contains relevant keywords. This prevents noise from being posted to Slack. You'll build a multi-condition check using OR logic across keywords like 'meeting', 'action items', 'follow-up', 'recap', and 'notes'.

  1. 1Click the '+' after the Gmail trigger node and search for 'IF'
  2. 2Set Condition 1: 'String' | '{{ $json.subject }}' | 'Contains' | 'meeting'
  3. 3Click 'Add Condition' and set Condition 2: subject Contains 'action items'
  4. 4Add Condition 3: subject Contains 'follow-up'
  5. 5Add Condition 4: subject Contains 'recap'
  6. 6Set the 'Combine' dropdown to 'OR'
What you should see: The IF node should show multiple conditions listed with 'OR' logic. When you run a test, matching emails route to the 'true' branch and non-matching emails exit the 'false' branch.
Common mistake — The IF node string comparison is case-insensitive in n8n by default, but only when using 'Contains'. If you switch to 'Equals', it becomes case-sensitive. Stick with 'Contains' for subject matching here.
6

Canvas > Add Node > Code

Add a Code node to classify and extract meeting data

After the true branch of the IF node, add a Code node. This is where n8n earns its place — you can write JavaScript to extract the sender name, detect the meeting type from the subject, strip HTML from the email body, and assign a target Slack channel based on keywords. This single node replaces 4-5 manual routing steps you'd need in Zapier.

  1. 1Click '+' after the IF node's true output
  2. 2Search for 'Code' and select it
  3. 3Set 'Language' to 'JavaScript'
  4. 4Paste the classification code from the Pro Tip section below
  5. 5Click 'Test Step' to verify output fields
What you should see: The Code node output should show enriched fields: 'senderName', 'meetingType', 'targetChannel', 'cleanBody', and 'formattedDate' alongside the original email fields.

Paste this into the Code node (Step 6) that sits after your IF filter node. It strips HTML from the email body, detects meeting type from subject keywords, assigns the correct Slack channel, and formats the sender name — all in one pass. The $input.all() call pulls every email that passed the IF filter in the current execution.

JavaScript — Code Node// n8n Code Node — Meeting Classification & Data Prep
▸ Show code
// n8n Code Node — Meeting Classification & Data Prep
// Place after the IF filter node, before the Slack node
const items = $input.all();

... expand to see full code

// n8n Code Node — Meeting Classification & Data Prep
// Place after the IF filter node, before the Slack node

const items = $input.all();
const results = [];

// Map meeting types to Slack channels — update these to match your workspace
const channelMap = {
  'action items': '#action-items',
  'follow-up': '#follow-ups',
  'follow up': '#follow-ups',
  'recap': '#meeting-recaps',
  'notes': '#meeting-recaps',
  'confirmation': '#external-meetings',
  'confirmed': '#external-meetings',
  'meeting request': '#external-meetings',
  'default': '#general-meetings'
};

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

  // --- 1. Strip HTML from body ---
  const rawBody = email.text || email.snippet || '';
  const cleanBody = rawBody
    .replace(/<[^>]*>/g, ' ')
    .replace(/&nbsp;/g, ' ')
    .replace(/&amp;/g, '&')
    .replace(/\s+/g, ' ')
    .trim()
    .substring(0, 500);

  // --- 2. Extract sender name from 'from' field ---
  // Gmail 'from' field is usually: "First Last <[email protected]>"
  const fromRaw = email.from || '';
  const nameMatch = fromRaw.match(/^([^<]+)/);
  const senderName = nameMatch ? nameMatch[1].trim() : fromRaw;
  const emailMatch = fromRaw.match(/<([^>]+)>/);
  const senderEmail = emailMatch ? emailMatch[1] : fromRaw;

  // --- 3. Classify meeting type by subject keyword ---
  const subject = (email.subject || '').toLowerCase();
  let meetingType = 'General Meeting';
  let targetChannel = channelMap['default'];

  for (const [keyword, channel] of Object.entries(channelMap)) {
    if (keyword !== 'default' && subject.includes(keyword)) {
      targetChannel = channel;
      meetingType = keyword
        .split(' ')
        .map(w => w.charAt(0).toUpperCase() + w.slice(1))
        .join(' ');
      break;
    }
  }

  // --- 4. Format received date ---
  const rawDate = email.date || email.internalDate || '';
  let formattedDate = 'Unknown date';
  if (rawDate) {
    const d = new Date(isNaN(rawDate) ? rawDate : parseInt(rawDate));
    formattedDate = d.toLocaleString('en-US', {
      month: 'short',
      day: 'numeric',
      year: 'numeric',
      hour: 'numeric',
      minute: '2-digit',
      hour12: true
    });
  }

  // --- 5. Build Slack message text ---
  const emoji = meetingType.includes('Confirmation') ? '📅' : '📋';
  const slackMessage = [
    `${emoji} *${meetingType}* from ${senderName} (${senderEmail})`,
    `*Subject:* ${email.subject}`,
    `*Received:* ${formattedDate}`,
    '',
    cleanBody
  ].join('\n');

  results.push({
    json: {
      ...email,
      senderName,
      senderEmail,
      cleanBody,
      meetingType,
      targetChannel,
      formattedDate,
      slackMessage,
      messageId: email.id
    }
  });
}

return results;
7

Canvas > Add Node > Slack > Send Message

Add the Slack node and configure message formatting

Add a Slack node after the Code node. Set the operation to 'Send Message'. In the 'Channel' field, use the dynamic value from your Code node output: '{{ $json.targetChannel }}'. This is what routes the message to the right Slack channel per email. Build the message text using Slack's Block Kit or a simple formatted string combining sender, subject, date, and a clipped body preview.

  1. 1Click '+' after the Code node and search for 'Slack'
  2. 2Select 'Send Message' as the operation
  3. 3Connect your Slack workspace by clicking 'Create new credential' and authorizing via OAuth2
  4. 4Set 'Channel' to '{{ $json.targetChannel }}'
  5. 5Set 'Message Text' to the formatted template (see field mapping section)
What you should see: The Slack node parameters panel should show the dynamic channel reference and a message text block with your template. The credential line should show a green checkmark.
Common mistake — Slack's OAuth bot token requires the 'chat:write' scope and the bot must be invited to every channel you intend to post to. If you get a 'not_in_channel' error, open Slack, go to the target channel, type /invite @YourBotName, and try again.
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
8

Canvas > Test Workflow button (top bar)

Test end-to-end with a real meeting email

Click 'Test Workflow' at the top of the canvas. n8n will run all nodes in sequence using real data. Watch each node light up green as it executes. Check the Slack channel you targeted — the message should appear within seconds of the test completing. Click each node's output panel to verify the data transformation happened correctly at each stage.

  1. 1Click 'Test Workflow' in the top toolbar
  2. 2Watch each node turn green as execution proceeds
  3. 3Open your target Slack channel and confirm the message arrived
  4. 4Click the Code node output panel to verify 'targetChannel' mapped correctly
  5. 5Click the Slack node output panel to confirm 'ok: true' in the response
What you should see: Each node should have a green execution badge. The Slack message should appear in the correct channel with sender name, subject, date, and a body snippet formatted cleanly.
9

Canvas > Three-dot menu > Settings > Error Workflow

Add an error handler for failed Slack posts

Real workflows fail. Add an Error Trigger node connected to a second Slack node that posts to a dedicated #automation-errors channel when the main workflow breaks. In n8n, click the three-dot menu on the workflow canvas and toggle 'Error Workflow'. Create a second minimal workflow with an Error Trigger that sends the error message and node name to your monitoring channel.

  1. 1Click the three-dot menu at the top of the canvas
  2. 2Select 'Settings'
  3. 3Under 'Error Workflow', click 'Select Workflow' and create or select an error-handling workflow
  4. 4In that error workflow, add an Error Trigger node and a Slack node posting to #automation-errors
What you should see: The Settings panel should show your error workflow selected by name. When any node in the main workflow fails, a message will appear in #automation-errors with the error details.
Common mistake — n8n's error workflow receives the error object as input, not the original email data. Don't try to re-post the email from the error workflow — just alert the team and let them check the execution log manually.
10

Canvas > Active/Inactive toggle (top right)

Activate the workflow

Click the 'Inactive' toggle in the top-right corner of the canvas to switch it to 'Active'. n8n will immediately begin polling Gmail every 5 minutes according to your schedule. The workflow is now live. Leave the canvas — it runs independently in the background.

  1. 1Click the gray 'Inactive' toggle in the top-right corner
  2. 2Confirm the dialog if prompted
  3. 3Watch the toggle turn green and read 'Active'
  4. 4Navigate to the Executions tab to monitor the first few runs
What you should see: The toggle should be green and read 'Active'. Within 5 minutes, the Executions tab should show a new successful execution entry.

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 your team is already self-hosting or on n8n Cloud and someone on the team can read JavaScript. The keyword classification and HTML stripping you need for this workflow require real code — n8n's Code node handles it in one step. You also get full control over deduplication logic, which matters here because Gmail polling without deduplication will repost the same emails after any workflow reset. If nobody on your team touches code and you just need a basic 'email arrives → Slack message' without smart routing, use Zapier — the Gmail New Email trigger and Slack Send Message action are 10-minute setup with no code required.

Cost

Cost math: n8n Cloud's Starter plan is $20/month and includes 2,500 executions. This workflow uses 1 execution per email processed. A team receiving 20 meeting-related emails per day generates 600 executions/month — well within the Starter tier. At 100 meeting emails/day (3,000/month), you'd need the Pro plan at $50/month. Self-hosted n8n is free indefinitely at any volume, and this workflow's lightweight JS won't stress a basic $6/month VPS. Zapier's equivalent would cost $19.99/month for 750 tasks — cheaper at low volume, but Zapier can't do the routing logic without 3-4 extra Zaps eating into your task count fast.

Tradeoffs

Make handles multi-branch routing with its Router module natively, which is slightly cleaner than n8n's IF node for this use case — you'd build one branch per meeting type with no code required. Zapier's Gmail trigger is faster to configure but the routing requires Paths, which is a paid feature and costs tasks per branch. Power Automate has a solid Gmail connector via third-party but native support is through Outlook — if your team is Microsoft-first, the Outlook + Teams version of this workflow is better than forcing Gmail into Power Automate. Pipedream's Gmail source fires on actual Gmail push notifications via Google Pub/Sub, which means true real-time delivery instead of polling — if sub-minute latency matters, Pipedream is genuinely better here. n8n wins on total control and cost at mid-volume, but acknowledge Pipedream's edge on latency.

Three things you'll hit after go-live. First: Gmail's API returns email bodies in base64-encoded MIME parts for full message fetches — the snippet field is plain text and safe to use, but if you switch to fetching full bodies, you'll need to decode them with Buffer.from(part.body.data, 'base64').toString('utf-8') in your Code node. Second: Google's OAuth refresh tokens silently expire if your consent screen stays in Testing mode — you won't get an error email, the workflow just stops processing and shows credential failures in the Executions log. Third: Slack's rate limit for the chat.postMessage API is 1 request per second per channel. If a batch of meeting emails arrives simultaneously (e.g., after a conference day), the workflow can hit this limit and fail silently. Add a Wait node between Slack posts set to 1.1 seconds if you're processing more than a few emails in a single polling cycle.

Ideas for what to build next

  • Add a Gmail label after routingUse a second Gmail node after the Slack post to automatically apply a label like 'Distributed-to-Slack' to processed emails. This gives you a clear audit trail inside Gmail and prevents confusion about which emails have been routed.
  • Build a daily digest versionCreate a parallel workflow that collects all meeting emails over a 24-hour window using a Schedule trigger, batches them into a single Slack message, and posts a digest each morning at 8am. Useful for lower-urgency project channels that don't need real-time pings.
  • Route to Notion or a task manager for action itemsWhen the detected meeting type is 'Action Items', fork the workflow to also create tasks in Notion, Asana, or Linear — one task per bullet point extracted from the email body using a Code node with a bullet-point regex parser.

Related guides

Was this guide helpful?
Slack + Gmail overviewn8n profile →