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

How to Forward Gmail Meeting Notes to Slack with Pipedream

Watches Gmail for emails containing meeting notes or action items and forwards a formatted summary to the appropriate Slack channel in real time.

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

Best for

Teams where external meeting confirmations and action items land in one inbox but need to reach multiple Slack channels fast.

Not ideal for

If you need meeting notes pulled from a calendar tool like Google Calendar or Zoom — start with those triggers instead of Gmail.

Sync type

real-time

Use case type

notification

Real-World Example

💡

A 20-person consulting firm routes all client meeting follow-ups from a shared Gmail inbox to project-specific Slack channels like #client-acme and #client-globex. Before this workflow, the ops lead manually forwarded emails 2-3 times per day and team members frequently missed action items until the next standup. Now the relevant channel gets a formatted Slack message within 30 seconds of the email arriving.

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 Pipedream

Copy the pre-built Pipedream blueprint and paste it straight into Pipedream. 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 messages.readonly and labels.readonly OAuth scopes — Pipedream requests these during account connection
Slack workspace where you have permission to install apps and post to the target channels
Pipedream account (free tier works; paid required if you need more than 10,000 credits/month)
Target Slack channels already created — Pipedream cannot create channels, only post to existing ones
Gmail account must be a Google personal or Workspace account — Gmail Alias addresses cannot be used as the trigger inbox

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Email Subject
Sender Name and Address
Email Body (Plain Text)
Email Received Date
Target Slack Channel
Gmail Message ID
2 optional fields▸ show
Email Thread ID
Recipient List (To / CC)

Step-by-Step Setup

1

pipedream.com > Workflows > New Workflow

Create a new Pipedream workflow

Go to pipedream.com and sign in. Click 'New Workflow' in the top-left of the Workflows dashboard. You'll land on the workflow builder canvas with a single empty trigger block at the top. Give the workflow a name — something like 'Gmail Meeting Notes → Slack' — by clicking the untitled field at the top of the canvas. This name shows up in your workflow list and in Pipedream's error notification emails, so make it descriptive.

  1. 1Sign in at pipedream.com
  2. 2Click 'New Workflow' in the top-left sidebar
  3. 3Click the untitled workflow name field at the top and type 'Gmail Meeting Notes → Slack'
  4. 4Click the trigger block labeled 'Add a trigger'
What you should see: You should see the workflow builder with an empty trigger block and your workflow name saved at the top.
Common mistake — Pipedream auto-saves workflow names after you click away. If the name reverts, refresh the page — this is a known UI flicker on first save.
2

Trigger Block > Search Apps > Gmail > New Email

Add the Gmail trigger

In the trigger block, search for 'Gmail' and select it from the app list. Choose the trigger event 'New Email' — this fires every time a new email lands in the inbox. Pipedream uses Gmail's push notification API here, not polling, so events fire within seconds of email delivery. You'll see a configuration panel on the right side of the screen where you'll connect your account and set filters.

  1. 1Click the trigger block on the canvas
  2. 2Type 'Gmail' in the search field
  3. 3Select 'Gmail' from the app list
  4. 4Choose 'New Email' as the trigger event
What you should see: The trigger block should now show the Gmail logo and the label 'New Email'. A configuration panel appears on the right.
Common mistake — Do not choose 'New Labeled Email' here unless you plan to use Gmail labels as your routing mechanism — it adds an extra dependency that's easy to break when someone renames a label.
Pipedream
+
click +
search apps
Slack
SL
Slack
Add the Gmail trigger
Slack
SL
module added
3

Trigger Config Panel > Connect Account > Google OAuth

Connect your Gmail account

In the trigger configuration panel, click 'Connect Account' under the Gmail section. Pipedream opens a Google OAuth popup. Sign in with the Gmail account that receives meeting follow-ups — this must be the actual inbox where those emails land. Grant the requested scopes, which include reading mail and managing push notifications. After approving, the account appears in the dropdown labeled with your email address.

  1. 1Click 'Connect Account' in the right-side config panel
  2. 2Sign in with the Gmail account that receives meeting emails
  3. 3Click 'Allow' on the Google permissions screen
  4. 4Confirm your email address appears in the account dropdown
What you should see: Your Gmail address should appear in the 'Connected Account' dropdown. The trigger block on the canvas shows a green connected indicator.
Common mistake — If you're connecting a Google Workspace account, your admin may need to approve Pipedream as a third-party app in the Google Admin Console before OAuth succeeds.
Pipedream settings
Connection
Choose a connection…Add
click Add
Slack
Log in to authorize
Authorize Pipedream
popup window
Connected
green checkmark
4

Trigger Config Panel > Label > Search > Test Trigger

Configure the Gmail label or search filter

In the trigger config panel, set the 'Label' field to the Gmail label where meeting follow-ups land — for example, 'meeting-notes' or 'INBOX'. If you don't use labels, leave it as 'INBOX' and you'll filter by subject line content in the next code step. Optionally, set the 'Search' field to a Gmail search string like 'subject:(meeting OR follow-up OR action items)' to pre-filter at the trigger level. Click 'Test Trigger' at the bottom of the panel to pull a real email as sample data.

  1. 1Set the 'Label' dropdown to 'INBOX' or your specific meeting label
  2. 2In the 'Search' field, type: subject:(meeting OR "follow-up" OR "action items")
  3. 3Click 'Test Trigger' at the bottom of the config panel
  4. 4Select a real meeting email from the results to use as sample data
What you should see: Pipedream displays the raw email data — subject, sender, body text, date — from the email you selected. You'll see this data referenced as 'steps.trigger.event' in subsequent steps.
Common mistake — The Gmail search filter at this step runs server-side via the Gmail API. Complex queries with more than 5 OR conditions sometimes silently fail to match — test your query in Gmail's search bar first before pasting it here.
Slack
SL
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Gmail
GM
notified
5

Canvas > + > Run Node.js Code

Add a Node.js code step to parse and classify the email

Click the '+' button below the trigger block to add a new step. Choose 'Run Node.js code' (not an app). This code step reads the raw email data and does two things: checks whether the email body actually contains meeting-related content, and determines which Slack channel to route it to based on keywords or sender domain. Paste the code provided in the pro tip section below into the code editor. The output of this step — channelId and formattedMessage — gets used by the Slack step next.

  1. 1Click the '+' button below the Gmail trigger block
  2. 2Click 'Run Node.js code' in the step type list
  3. 3Clear the default code in the editor
  4. 4Paste the classification and formatting code from the pro tip below
  5. 5Click 'Test' to run the step against your sample email
What you should see: The step output panel shows a JSON object with at least 'channelId', 'formattedMessage', and 'isMeetingEmail' fields. If 'isMeetingEmail' is false, the workflow will stop before posting to Slack.

Paste this into the Node.js code step added in Step 5. It decodes the Gmail base64 body, classifies the email as meeting-related using keyword matching, routes it to the correct Slack channel based on sender domain, and builds a formatted mrkdwn message with extracted action items. The function returns 'isMeetingEmail: false' to halt non-meeting emails at the filter step.

JavaScript — Code Stepimport { Buffer } from 'buffer';
▸ Show code
import { Buffer } from 'buffer';
export default defineComponent({
  async run({ steps, $ }) {

... expand to see full code

import { Buffer } from 'buffer';

export default defineComponent({
  async run({ steps, $ }) {
    const email = steps.trigger.event;

    // Decode base64url email body (handles multipart MIME)
    let bodyText = '';
    try {
      const parts = email.payload?.parts;
      if (parts && parts.length > 0) {
        const textPart = parts.find(p => p.mimeType === 'text/plain');
        bodyText = textPart
          ? Buffer.from(textPart.body.data, 'base64url').toString('utf-8')
          : Buffer.from(email.payload.body.data || '', 'base64url').toString('utf-8');
      } else {
        bodyText = Buffer.from(email.payload?.body?.data || '', 'base64url').toString('utf-8');
      }
    } catch (err) {
      $.flow.exit('Could not decode email body: ' + err.message);
    }

    // Meeting classification keywords
    const subject = email.payload.headers.find(h => h.name === 'Subject')?.value || '';
    const meetingKeywords = ['meeting', 'follow-up', 'followup', 'action items', 'recap',
      'minutes', 'call summary', 'discussion summary', 'confirmed', 'kickoff'];
    const isMeetingEmail = meetingKeywords.some(k =>
      subject.toLowerCase().includes(k) || bodyText.toLowerCase().includes(k)
    );

    if (!isMeetingEmail) {
      return { isMeetingEmail: false };
    }

    // Extract sender details
    const fromHeader = email.payload.headers.find(h => h.name === 'From')?.value || '';
    const dateHeader = email.payload.headers.find(h => h.name === 'Date')?.value || '';
    const receivedDate = new Date(dateHeader).toLocaleString('en-US', {
      month: 'short', day: 'numeric', year: 'numeric',
      hour: 'numeric', minute: '2-digit', timeZoneName: 'short'
    });

    // Extract sender domain for channel routing
    const emailMatch = fromHeader.match(/<([^>]+)>/) || [null, fromHeader];
    const senderEmail = emailMatch[1];
    const senderDomain = senderEmail.split('@')[1]?.replace('.com', '').replace('.', '-') || 'general';

    // Channel routing map — update these to match your real Slack channel IDs
    const channelMap = {
      'acmecorp': 'C0123456789',   // #client-acme
      'globexsolutions': 'C9876543210', // #client-globex
      'default': 'C1111111111'    // #meetings-general
    };
    const channelId = channelMap[senderDomain] || channelMap['default'];

    // Extract action items (lines starting with numbered lists or bullet indicators)
    const actionItemRegex = /(?:\d+[.)\s]|[-•*]\s)(.+)/g;
    const actionItems = [...bodyText.matchAll(actionItemRegex)].map(m => m[1].trim());
    const actionBlock = actionItems.length > 0
      ? '*Action Items:*\n' + actionItems.map(a => `• ${a}`).join('\n')
      : bodyText.slice(0, 300).trim() + (bodyText.length > 300 ? '...' : '');

    // Build Slack mrkdwn message
    const isConfirmation = subject.toLowerCase().includes('confirm');
    const emoji = isConfirmation ? '📅' : '📋';
    const label = isConfirmation ? 'Meeting Confirmed' : 'Meeting Follow-up';

    const formattedMessage =
      `*${emoji} ${label}:* ${subject}\n` +
      `*From:* ${fromHeader}\n` +
      `*Received:* ${receivedDate}\n\n` +
      actionBlock;

    return {
      isMeetingEmail: true,
      channelId,
      formattedMessage,
      subject,
      senderEmail,
      receivedDate
    };
  }
});
6

Canvas > + > Filter

Add a filter step to stop non-meeting emails

Click '+' below the code step and choose 'Filter' from the built-in Pipedream helpers. Set the condition to: steps.classify_email.isMeetingEmail === true. This prevents every email in the inbox from reaching Slack — only emails the code step flagged as meeting-related will continue. Without this filter, your Slack channel fills up with unrelated emails the moment someone's inbox gets a newsletter or receipt.

  1. 1Click '+' below the Node.js code step
  2. 2Select 'Filter' from the helpers section
  3. 3Set the left-hand field to: {{steps.classify_email.$return_value.isMeetingEmail}}
  4. 4Set the operator to 'is true'
  5. 5Click 'Continue' to save the filter condition
What you should see: The filter step shows a green checkmark for your sample meeting email and would show a red 'X' (halting execution) for a non-meeting email.
Common mistake — Pipedream's Filter step still counts as a credit-consuming execution even when it halts the workflow. If your inbox is very high-volume, add the Gmail search filter from Step 4 to reduce events before they reach this point.
7

Canvas > + > Slack > Send a Message

Add the Slack step to post the message

Click '+' below the filter step and search for 'Slack'. Select the 'Send a Message' action. In the config panel, connect your Slack workspace via OAuth — click 'Connect Account' and authorize Pipedream's Slack app in your workspace. For the 'Channel' field, reference the output from the code step: {{steps.classify_email.$return_value.channelId}}. For the 'Message Text' field, reference: {{steps.classify_email.$return_value.formattedMessage}}.

  1. 1Click '+' below the filter step
  2. 2Search for 'Slack' and select it
  3. 3Choose 'Send a Message' as the action
  4. 4Click 'Connect Account' and authorize Pipedream in your Slack workspace
  5. 5Set 'Channel' to {{steps.classify_email.$return_value.channelId}}
  6. 6Set 'Message Text' to {{steps.classify_email.$return_value.formattedMessage}}
What you should see: After clicking 'Test', you should see the formatted meeting summary appear in the target Slack channel within a few seconds.
Common mistake — Pipedream's Slack app posts as 'Pipedream' by default. If your team wants messages to appear from a named bot (e.g. 'MeetingBot'), you need to create a custom Slack app and use its OAuth token instead of Pipedream's built-in connection.
message template
🔔 New Record: {{text}} {{user}}
channel: {{channel}}
ts: {{ts}}
#sales
🔔 New Record: Jane Smith
Company: Acme Corp
8

Slack Step > Advanced Options > Blocks / Username / Unfurl Links

Configure Slack message formatting

In the Slack step config panel, expand 'Advanced Options'. Enable 'Use Blocks' if you want a structured Slack Block Kit message — this looks significantly better than plain text for meeting summaries. Alternatively, the code step can output pre-formatted mrkdwn text with bold sender names and bullet-point action items. Set 'Username' to something like 'Meeting Bot' and upload a bot icon URL if desired. Check 'Unfurl Links' to off — meeting notes often contain calendar links that generate noisy previews.

  1. 1Click 'Advanced Options' inside the Slack step config panel
  2. 2Set 'Username' to 'Meeting Bot'
  3. 3Set 'Unfurl Links' to false
  4. 4Set 'Unfurl Media' to false
  5. 5If using Block Kit, set 'Blocks' to {{steps.classify_email.$return_value.blocks}}
What you should see: The test message in Slack shows a clean formatted summary with the sender, subject, date, and action items — not a wall of raw email text.
Common mistake — Slack's Block Kit JSON must be a valid array, not a stringified array. If your code step returns blocks as a string, Slack silently ignores them and falls back to the text field.
9

Workflow Canvas > ••• Menu > Add Error Handler > Slack > Send a Message

Add error handling with a catch step

Click the three-dot menu on the workflow canvas and select 'Add Error Handler'. This creates a parallel branch that runs if any step throws an error. In the error handler, add a Slack step that posts to a private #alerts or #automation-errors channel with the error message and which workflow failed. This is essential for production — without it, a Gmail API hiccup or malformed email silently drops the message with no notification.

  1. 1Click the three-dot '•••' menu in the top-right of the workflow canvas
  2. 2Select 'Add Error Handler'
  3. 3In the error handler branch, click '+' and add a Slack step
  4. 4Set the channel to your internal #alerts or #automation-errors channel
  5. 5Set the message to: 'Gmail→Slack meeting workflow failed: {{error.message}}'
What you should see: A separate branch appears on the canvas labeled 'Error'. When you intentionally break the workflow to test, a message lands in your alerts channel with the error details.
10

Canvas > Deploy Button > Events Log

Deploy and verify the live workflow

Click 'Deploy' in the top-right corner of the workflow canvas. The workflow status changes from 'Draft' to 'Active'. Send a real test email to the Gmail account with a subject containing 'meeting notes' or 'action items'. Watch the Pipedream event log (left sidebar > Events) — you should see a new event appear within 30 seconds of sending the email. Click the event to inspect each step's input and output in the execution detail view.

  1. 1Click the blue 'Deploy' button in the top-right corner
  2. 2Confirm the workflow status shows 'Active'
  3. 3Send a real test email to the connected Gmail account
  4. 4Click 'Events' in the left sidebar to watch incoming events
  5. 5Click the new event entry to open the execution detail view
What you should see: The execution detail view shows all steps with green checkmarks. The target Slack channel has received the formatted meeting summary message.
Common mistake — Pipedream's Gmail trigger can take up to 2 minutes to register on first deploy while Google sets up the push notification subscription. If no event fires after 3 minutes, click 'Edit' on the trigger and hit 'Test' manually to re-initialize the subscription.

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 Pipedream for this if you need the message in Slack within 30 seconds of email delivery and you're comfortable with a small amount of JavaScript. Pipedream's Gmail trigger uses Google's push notification API, not polling — that's a real technical difference that cuts delivery latency from 1-15 minutes (Zapier's average) down to under a minute. You also get a full Node.js environment to decode base64 email bodies, extract action items with regex, and route to different channels based on sender domain — all in one step. If nobody on your team touches code and routing logic isn't needed, use Zapier instead. Its Gmail → Slack path is 4 clicks and zero code.

Cost

Pipedream's free tier gives you 10,000 credits/month. This workflow consumes roughly 3-4 credits per email (trigger + code step + filter + Slack). At 20 meeting emails per day, that's ~2,400 credits/month — well inside the free tier. At 100 emails/day you'd hit ~9,000 credits/month, still free but close to the ceiling. The next tier is $19/month for 100,000 credits. Zapier's equivalent on a paid plan costs $29.99/month for 2,000 tasks. For the same 100 emails/day (3,000 tasks/month), you're at Zapier's $73.50/month tier. Pipedream is cheaper by roughly $54/month at moderate volume.

Tradeoffs

Zapier's 'Email Parser by Zapier' is genuinely better at extracting structured fields from templated meeting confirmation emails — no code required. Make's scenario builder has better visual conditional branching if your routing logic involves more than 3-4 channel destinations. n8n self-hosted is the right call if your emails contain sensitive client data and you can't send it through a third-party SaaS. Power Automate wins only if your team already lives in Microsoft 365 and the meeting emails are coming from Outlook, not Gmail. Pipedream is still the right pick here because the Gmail push API integration is solid, the Node.js step handles the base64 MIME decoding that trips up no-code tools, and the pricing doesn't punish you for having an active inbox.

Three things you'll hit after setup. First: Gmail's push notification subscription silently lapses after 7 days if Pipedream's renewal attempt fails — the workflow stops processing with zero error notification unless you've set up health alerts. Check the Events log on day 8. Second: some email clients send HTML-only emails with no plain text MIME part. Your keyword matching returns false positives or misses entirely because you're trying to search raw HTML tags for the word 'meeting'. Add html-to-text as a Pipedream npm import on day one, not after users report missing Slack messages. Third: Slack's API rate limit for chat.postMessage is 1 message per second per channel. If a batch of meeting emails arrives simultaneously (common Monday morning scenario), some Slack posts will return a rate_limited error. The Slack step in Pipedream doesn't retry automatically — you need to catch that error and add an exponential backoff loop in code, or space out posts using setTimeout.

Ideas for what to build next

  • Add a Google Calendar event lookupWhen the email contains a meeting confirmation, cross-reference the date and time against Google Calendar to check for conflicts and include that context in the Slack message. Add a Pipedream 'Google Calendar: Get Events' step between the classification code and the Slack step.
  • Log all meeting summaries to a Google SheetAdd a second Slack-parallel step that writes the sender, subject, date, and extracted action items to a Google Sheet tab. This creates a running log of all external commitments without any manual copy-paste.
  • Route to multiple channels simultaneouslyModify the code step to return an array of channel IDs instead of one, then replace the Slack step with a loop using Pipedream's $.send.http or a secondary code step that iterates over the array and posts to each channel — useful when a meeting involves multiple internal teams.

Related guides

Was this guide helpful?
Slack + Gmail overviewPipedream profile →