

How to Route Gmail Support Emails to Slack with Pipedream
Watches a Gmail support inbox for new emails, parses sender, subject, and body, then posts a formatted summary to a Slack channel so your team can coordinate a response.
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-size support teams who triage tickets in Slack and want email context without switching to Gmail
Not ideal for
Teams already using a dedicated helpdesk like Zendesk or Intercom — those tools have native Slack integrations with ticket state management built in
Sync type
real-timeUse case type
routingReal-World Example
A 12-person e-commerce company routes all emails sent to [email protected] into their #support-queue Slack channel. Before this workflow, two support reps would open Gmail in separate tabs and sometimes reply to the same email within minutes of each other. Now every incoming email posts a formatted Slack card with sender, subject, and a 300-character body preview, and the team threads discussion before anyone drafts a reply.
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 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.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Sender Name | ||
| Sender Email | ||
| Subject Line | ||
| Body Preview | ||
| Gmail Thread ID | ||
| Gmail Message ID | ||
2 optional fields▸ show
| Received Timestamp | |
| To Address |
Step-by-Step Setup
pipedream.com > Workflows > New Workflow
Create a new Pipedream Workflow
Go to pipedream.com and sign in. From the left sidebar click 'Workflows', then click the blue 'New Workflow' button in the top right. Give the workflow a name like 'Gmail Support → Slack' so it's easy to find later. You'll land on the workflow canvas with a prompt to choose a trigger.
- 1Click 'Workflows' in the left sidebar
- 2Click the blue 'New Workflow' button
- 3Type a name: 'Gmail Support → Slack'
- 4Click 'Save' or press Enter to confirm the name
Workflow Canvas > Add Trigger > Gmail > New Email
Add the Gmail New Email trigger
Click the 'Add Trigger' block. In the search bar type 'Gmail' and select the Gmail app. Choose the trigger called 'New Email'. This trigger uses Pipedream's Gmail push integration, which creates a Gmail watch via Google's API — it fires within seconds of a message arriving, not on a polling interval.
- 1Click the 'Add Trigger' block
- 2Type 'Gmail' in the search bar
- 3Click the Gmail app icon
- 4Select 'New Email' from the trigger list
Trigger Panel > Gmail > Connect Account > Google OAuth
Connect your Gmail support account
In the trigger panel, click 'Connect Account' under the Gmail section. A Google OAuth popup appears — sign in with the Google account that owns your support inbox (e.g. [email protected]), not your personal account. After signing in, grant Pipedream the requested Gmail scopes. Back in the trigger panel, set the 'Label' field to 'INBOX' or a specific Gmail label you've created for support emails.
- 1Click 'Connect Account' in the Gmail trigger panel
- 2Select or add the support Google account in the OAuth popup
- 3Grant all requested permissions and click 'Continue'
- 4Set the Label dropdown to 'INBOX' or your support-specific label
Trigger Panel > Generate Test Event > Select Event
Test the trigger with a real email
Click 'Generate Test Event' at the bottom of the trigger panel. Pipedream will either fetch the most recent email in the inbox or prompt you to send a test email to the connected address. Send a real test email with a realistic subject line like 'Order #8821 not delivered'. Once Pipedream detects it, click 'Select' next to the event to use it as sample data for the remaining steps.
- 1Click 'Generate Test Event'
- 2Send a test email to the connected support address if prompted
- 3Wait for the event to appear in the list (usually under 30 seconds)
- 4Click 'Select' next to the test event
Workflow Canvas > + > Run Node.js Code
Add a Node.js code step to parse and format the email
Click the '+' button below the trigger to add a new step. Choose 'Run Node.js code'. This step extracts the sender name, email address, subject, and a truncated body preview from the raw Gmail payload. You'll write the parsing logic here so the Slack message is clean and readable rather than dumping raw JSON into the channel.
- 1Click the '+' button below the Gmail trigger
- 2Click 'Run Node.js code' from the step options
- 3Clear the default code in the editor
- 4Paste your formatting code (see Pro Tip section below)
Paste this into the Node.js code step (step 5). It handles both plain-text and multipart HTML emails, decodes the Base64url body, truncates the preview to 300 characters, extracts sender name and email separately, formats the received timestamp, and returns a clean object that the Slack Block Kit step consumes directly. Replace the `export default` function contents with this code.
JavaScript — Code Stepexport default defineComponent({▸ Show code
export default defineComponent({
async run({ steps, $ }) {
const message = steps.trigger.event;... expand to see full code
export default defineComponent({
async run({ steps, $ }) {
const message = steps.trigger.event;
const headers = message.payload.headers;
// Extract headers
const getHeader = (name) =>
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
const fromRaw = getHeader('From');
const subject = getHeader('Subject') || '(no subject)';
const toAddress = getHeader('To');
const dateRaw = getHeader('Date');
// Parse sender name and email from 'From' header
const fromMatch = fromRaw.match(/^(.+?)\s*<(.+?)>$/);
const senderName = fromMatch ? fromMatch[1].trim().replace(/^"|"$/g, '') : fromRaw;
const senderEmail = fromMatch ? fromMatch[2] : fromRaw;
// Recursively find plain text body in potentially nested MIME parts
function findPlainText(part) {
if (part.mimeType === 'text/plain' && part.body?.data) {
return Buffer.from(part.body.data, 'base64url').toString('utf-8');
}
if (part.parts) {
for (const child of part.parts) {
const result = findPlainText(child);
if (result) return result;
}
}
return null;
}
const rawBody = findPlainText(message.payload) || '';
const bodyPreview = rawBody.replace(/\s+/g, ' ').trim().slice(0, 300) +
(rawBody.length > 300 ? '...' : '');
// Format timestamp
const receivedAt = message.internalDate
? new Date(parseInt(message.internalDate)).toLocaleString('en-US', {
month: 'short', day: 'numeric', year: 'numeric',
hour: 'numeric', minute: '2-digit', timeZoneName: 'short'
})
: dateRaw;
// Build Gmail deep link
const threadId = message.threadId;
const gmailLink = `https://mail.google.com/mail/u/0/#all/${threadId}`;
// Deduplication guard using Pipedream data store
const db = $.service.db;
const seen = await db.get('seen_message_ids') || [];
if (seen.includes(message.id)) {
$.flow.exit('Duplicate message — already processed');
}
const updated = [message.id, ...seen].slice(0, 100);
await db.set('seen_message_ids', updated);
return {
senderName,
senderEmail,
subject,
bodyPreview: bodyPreview || '(no body content)',
receivedAt,
gmailLink,
threadId,
toAddress,
messageId: message.id
};
}
});Code Step Panel > Test > Return Value
Test the code step output
Click 'Test' in the code step panel. Pipedream runs the function against the sample email you selected in step 4. Check the 'Return Value' tab on the right side of the editor. You should see clean, decoded values for each field. If `bodyPreview` is empty, the email might use `payload.parts` instead of `payload.body` — multipart emails (HTML + plain text) structure their content differently.
- 1Click the 'Test' button in the code step
- 2Click the 'Return Value' tab in the right panel
- 3Confirm `senderName`, `senderEmail`, `subject`, and `bodyPreview` all have readable values
- 4If any field is empty, check the 'Logs' tab for errors
Paste this into the Node.js code step (step 5). It handles both plain-text and multipart HTML emails, decodes the Base64url body, truncates the preview to 300 characters, extracts sender name and email separately, formats the received timestamp, and returns a clean object that the Slack Block Kit step consumes directly. Replace the `export default` function contents with this code.
JavaScript — Code Stepexport default defineComponent({▸ Show code
export default defineComponent({
async run({ steps, $ }) {
const message = steps.trigger.event;... expand to see full code
export default defineComponent({
async run({ steps, $ }) {
const message = steps.trigger.event;
const headers = message.payload.headers;
// Extract headers
const getHeader = (name) =>
headers.find(h => h.name.toLowerCase() === name.toLowerCase())?.value || '';
const fromRaw = getHeader('From');
const subject = getHeader('Subject') || '(no subject)';
const toAddress = getHeader('To');
const dateRaw = getHeader('Date');
// Parse sender name and email from 'From' header
const fromMatch = fromRaw.match(/^(.+?)\s*<(.+?)>$/);
const senderName = fromMatch ? fromMatch[1].trim().replace(/^"|"$/g, '') : fromRaw;
const senderEmail = fromMatch ? fromMatch[2] : fromRaw;
// Recursively find plain text body in potentially nested MIME parts
function findPlainText(part) {
if (part.mimeType === 'text/plain' && part.body?.data) {
return Buffer.from(part.body.data, 'base64url').toString('utf-8');
}
if (part.parts) {
for (const child of part.parts) {
const result = findPlainText(child);
if (result) return result;
}
}
return null;
}
const rawBody = findPlainText(message.payload) || '';
const bodyPreview = rawBody.replace(/\s+/g, ' ').trim().slice(0, 300) +
(rawBody.length > 300 ? '...' : '');
// Format timestamp
const receivedAt = message.internalDate
? new Date(parseInt(message.internalDate)).toLocaleString('en-US', {
month: 'short', day: 'numeric', year: 'numeric',
hour: 'numeric', minute: '2-digit', timeZoneName: 'short'
})
: dateRaw;
// Build Gmail deep link
const threadId = message.threadId;
const gmailLink = `https://mail.google.com/mail/u/0/#all/${threadId}`;
// Deduplication guard using Pipedream data store
const db = $.service.db;
const seen = await db.get('seen_message_ids') || [];
if (seen.includes(message.id)) {
$.flow.exit('Duplicate message — already processed');
}
const updated = [message.id, ...seen].slice(0, 100);
await db.set('seen_message_ids', updated);
return {
senderName,
senderEmail,
subject,
bodyPreview: bodyPreview || '(no body content)',
receivedAt,
gmailLink,
threadId,
toAddress,
messageId: message.id
};
}
});Workflow Canvas > + > Slack > Send Message to Channel
Add the Slack step to post the message
Click '+' below the code step and search for 'Slack'. Select the Slack app and choose the action 'Send Message to Channel'. Connect your Slack workspace via the Connected Accounts flow. In the 'Channel' field, type or select your support channel name (e.g. #support-queue). Set the 'Message Text' field using the outputs from your code step.
- 1Click '+' below the code step
- 2Search for 'Slack' and select the Slack app
- 3Choose 'Send Message to Channel'
- 4Click 'Connect Account' and authorize Pipedream in your Slack workspace
- 5Select your support channel from the Channel dropdown
channel: {{channel}}
ts: {{ts}}
Slack Step Panel > Blocks field > {} variable picker
Build the Slack message with Block Kit formatting
In the Slack step, use the 'Blocks' field rather than the plain 'Message Text' field. Block Kit lets you format the support ticket summary with bold headers, field rows, and a direct link to Gmail. Reference the outputs from your code step using Pipedream's variable picker — click the `{}` icon next to any field to browse available values from previous steps.
- 1Click inside the 'Blocks' field in the Slack step
- 2Click the '{}' variable picker icon
- 3Select values from your code step: `steps.nodejs.$return_value.senderName`, `subject`, `bodyPreview`
- 4Paste the Block Kit JSON structure from the Pro Tip section
- 5Replace hardcoded strings with the variable references
Workflow Canvas > Test Workflow (top toolbar)
Test the full workflow end-to-end
Click 'Test Workflow' at the top of the canvas. Pipedream runs all steps sequentially using the sample event from step 4. Watch the step indicators — each one turns green when it succeeds. Then open your #support-queue Slack channel and confirm the message appeared with correct sender, subject, and body preview. Check that the Gmail link in the message opens the correct thread.
- 1Click 'Test Workflow' in the top toolbar
- 2Watch each step turn green in sequence
- 3Open your Slack workspace and navigate to #support-queue
- 4Confirm the message shows the correct sender name, email, subject, and preview
Workflow Canvas > Deploy (top right button)
Deploy and enable the workflow
Click the 'Deploy' button in the top right corner of the workflow canvas. Pipedream activates the Gmail push subscription and the workflow goes live. The status indicator next to the workflow name changes from 'Paused' to 'Active'. From this point, every new email arriving in the connected Gmail inbox triggers the workflow in real time — no polling interval, no delay beyond Gmail's own push latency (typically under 10 seconds).
- 1Click the blue 'Deploy' button in the top right
- 2Confirm the deployment in the dialog if prompted
- 3Verify the workflow status shows 'Active' in the left sidebar
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 Pipedream for this if your team has at least one person comfortable reading Node.js. The Gmail push integration means emails land in Slack in under 10 seconds — faster than Zapier's minimum 1-minute polling or Make's 15-minute default on the free plan. The code step also lets you handle messy real-world emails: multipart MIME structures, malformed From headers, Base64url-encoded bodies. If your team is non-technical and wants a click-through setup with zero code, use Zapier — the Gmail + Slack Zap takes 8 minutes to configure and works fine for low volumes.
Pipedream's free tier gives you 10,000 credits per month. This workflow uses 3 steps, so each email costs 3 credits. That covers 3,333 emails per month for free. If your support volume is 500 emails/month, you're well within the free tier with 8,500 credits to spare. Above 3,333 emails/month you'll hit the Basic plan at $19/month, which gives you 100,000 credits — enough for 33,000 emails. Zapier's equivalent (Starter at $19.99/month) caps at 750 tasks, which runs out at 750 emails. For high-volume support teams, Pipedream is significantly cheaper.
Zapier handles the Gmail trigger better for non-technical users — the UI surfaces label filters as a simple dropdown rather than requiring you to understand Gmail's API label structure. Make's scenario builder lets you visually map the From header parsing without writing code, which is faster to set up but harder to extend. n8n has a native Gmail node with built-in MIME parsing that removes the need for a custom code step — if you're self-hosting, n8n handles this workflow with less setup complexity. Power Automate has a solid Gmail connector via the Gmail connector in the M365 ecosystem, but its Slack connector is weaker and often requires a third-party HTTP request step. Pipedream is still the right call here because the combination of instant Gmail push, a real code step, and the built-in data store for deduplication gives you a production-grade workflow you'd otherwise need to build three separate tools to replicate.
Three things you'll hit after going live. First, Gmail's push subscription silently expires every 7 days — Pipedream auto-renews it, but if your workflow was paused or your account hit a credit limit during renewal, the subscription lapses and emails stop triggering the workflow with no error message. Check your workflow's event count every few days for the first two weeks. Second, reply emails and out-of-office auto-responses will hit the trigger too. Add a filter in the code step that checks for `In-Reply-To` or `Auto-Submitted` headers and exits early for those. Third, HTML-only emails (no plain text part) return an empty body preview unless you strip HTML tags — add a basic regex to remove `<[^>]+>` tags from the HTML part as a fallback when no text/plain part exists.
Ideas for what to build next
- →Add Slack Thread Replies Back to Gmail — Use a Slack trigger on new messages in the support thread to auto-draft a reply in Gmail, giving agents a pre-written response to edit and send — cuts reply time without removing human review.
- →Route by Email Content to Different Channels — Add keyword detection in the code step to route billing emails to #support-billing and shipping issues to #support-shipping — one Gmail source, multiple Slack destinations, no manual sorting.
- →Log Every Ticket to a Google Sheet — Add a fourth step that appends a row to a Google Sheet with sender, subject, timestamp, and a Gmail link — gives you a running ticket log you can sort and report on without a dedicated helpdesk tool.
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