

How to Send Gmail Digest Summaries to Slack with n8n
A scheduled n8n workflow that queries Gmail for priority emails — by label, sender domain, or unread status — then formats and posts a digest message to a Slack channel on a daily or weekly cadence.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.
Best for
Teams that want a scheduled Slack summary of important Gmail activity without giving everyone inbox access or checking email manually throughout the day.
Not ideal for
Workflows where you need real-time Slack alerts the moment a specific email arrives — use a Gmail webhook trigger with Zapier or Make for that instead.
Sync type
scheduledUse case type
notificationReal-World Example
A 12-person B2B SaaS company uses this to post a 9am digest to #customer-success summarizing all unread emails from client domains received in the last 24 hours. Before this workflow, CSMs each checked their own inboxes independently and high-priority client emails went unnoticed for 3-6 hours. Now the whole team sees the same digest and can coordinate responses before the daily standup.
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.
Optional
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Email Subject | ||
| Sender (From) | ||
| Email Snippet | ||
| Date Received | ||
| Slack Channel ID | ||
| Digest Text (formatted) | ||
3 optional fields▸ show
| Label IDs | |
| Thread ID | |
| Message ID |
Step-by-Step Setup
n8n Canvas > + Add first step > Schedule Trigger
Create a new n8n workflow with a Schedule trigger
Open your n8n instance and click the '+ New Workflow' button in the top right. On the blank canvas, click the '+ Add first step' placeholder node. In the node picker panel that slides in from the right, type 'Schedule' and select the 'Schedule Trigger' node. This will fire the workflow at whatever cadence you configure — daily at 9am or weekly on Monday morning are the most useful for email digests.
- 1Click '+ New Workflow' in the top right of the n8n dashboard
- 2Click the '+ Add first step' node on the empty canvas
- 3Type 'Schedule' in the search box of the node picker
- 4Select 'Schedule Trigger' from the results
- 5In the node settings panel, set 'Trigger Interval' to 'Days' and 'Days Between Triggers' to 1, with 'Trigger at Hour' set to 9
n8n Canvas > + Node > Gmail > Credential > Create New > OAuth2
Connect your Gmail account to n8n
Click the '+' button after the Schedule Trigger node to add the next step. Search for 'Gmail' in the node picker and select the Gmail node. In the node settings, click the 'Credential for Gmail API' dropdown and select 'Create New Credential'. n8n will ask you to choose between OAuth2 and a Service Account — use OAuth2 for a personal or shared team Gmail account. You'll be redirected to Google's consent screen to authorize access.
- 1Click the '+' connector on the right side of the Schedule Trigger node
- 2Search 'Gmail' in the node picker and click the Gmail node
- 3In the node panel, click the 'Credential for Gmail API' dropdown
- 4Click 'Create New Credential'
- 5Select 'OAuth2' as the credential type and click 'Sign in with Google'
- 6Complete Google's OAuth consent flow and grant the requested Gmail scopes
Gmail Node > Resource: Message > Operation: Get Many > Filters > Query
Configure Gmail to fetch emails from the last 24 hours
With the Gmail node open, set 'Operation' to 'Get Many' and 'Resource' to 'Message'. In the 'Filters' section, you'll use Gmail's search query syntax in the 'Query' field — this is the most important configuration in the entire workflow. The query controls exactly which emails get pulled. Set the 'Limit' field to 50 to avoid pulling hundreds of messages on busy days.
- 1Set 'Resource' to 'Message'
- 2Set 'Operation' to 'Get Many'
- 3In the 'Query' field, enter your filter — see examples below
- 4Set 'Limit' to 50
- 5Toggle 'Return All' to OFF
Gmail Node > Filters > Query field
Build Gmail query filters for your team's use case
The Gmail query field accepts the same search operators as the Gmail web UI. Pick the query pattern that matches your team's need. For emails from a specific client domain, use 'from:(@acmecorp.com) newer_than:1d is:unread'. For labeled messages, use 'label:priority newer_than:1d'. For all unread messages, use 'is:unread newer_than:1d'. You can combine multiple operators with AND — Gmail treats space-separated terms as AND by default.
- 1Decide which filter pattern fits your team: domain, label, or unread
- 2For domain-based: type 'from:(@yourdomain.com) newer_than:1d is:unread'
- 3For label-based: type 'label:your-label-name newer_than:1d'
- 4Click 'Test step' to verify the query returns expected emails
- 5Adjust the query if the result set is too large or too narrow
n8n Canvas > + Node > Code > JavaScript mode
Add a Code node to format the email data into a digest
Click '+' after the Gmail node and add a 'Code' node. This is where you transform the raw email array into a clean, readable Slack message. The Code node runs JavaScript and has access to all Gmail output via the $input.all() method. You'll loop over each email item, extract subject, sender, snippet, and date, then build a single formatted string that Slack can render with its Block Kit or simple mrkdwn syntax.
- 1Click '+' after the Gmail node
- 2Search for 'Code' in the node picker and select the Code node
- 3Make sure 'Language' is set to 'JavaScript'
- 4Set 'Mode' to 'Run Once for All Items'
- 5Paste the digest-formatting code from the Pro Tip section below
This Code node runs once for all Gmail items, builds a formatted Slack mrkdwn digest string with direct Gmail links, handles missing fields safely, and deduplicates by threadId so reply chains only appear once. Paste this into the Code node in Step 5, with 'Mode' set to 'Run Once for All Items'.
JavaScript — Code Node// n8n Code Node — Run Once for All Items▸ Show code
// n8n Code Node — Run Once for All Items // Transforms Gmail message array into a single Slack mrkdwn digest string const items = $input.all();
... expand to see full code
// n8n Code Node — Run Once for All Items
// Transforms Gmail message array into a single Slack mrkdwn digest string
const items = $input.all();
const now = new Date();
const dateLabel = now.toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric', year: 'numeric' });
// Deduplicate by threadId — only show the most recent message per thread
const seenThreads = new Set();
const dedupedItems = [];
for (const item of items) {
const threadId = item.json.threadId ?? item.json.id;
if (!seenThreads.has(threadId)) {
seenThreads.add(threadId);
dedupedItems.push(item);
}
}
// Sort by date descending (newest first)
dedupedItems.sort((a, b) => {
const dateA = new Date(a.json.date ?? 0).getTime();
const dateB = new Date(b.json.date ?? 0).getTime();
return dateB - dateA;
});
if (dedupedItems.length === 0) {
return [{ json: { digestText: ':white_check_mark: No priority emails in the last 24 hours.', emailCount: 0 } }];
}
// Build the header
let digestLines = [];
digestLines.push(`*📧 Email Digest — ${dateLabel}*`);
digestLines.push(`_${dedupedItems.length} email${dedupedItems.length > 1 ? 's' : ''} from the last 24 hours_`);
digestLines.push('');
// Build one block per email
dedupedItems.forEach((item, index) => {
const subject = item.json.subject ?? '(no subject)';
const from = item.json.from ?? '(unknown sender)';
const snippet = (item.json.snippet ?? '').substring(0, 120);
const threadId = item.json.threadId ?? item.json.id ?? '';
const rawDate = item.json.date ? new Date(item.json.date) : null;
const timeLabel = rawDate
? rawDate.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })
: 'unknown time';
const gmailLink = threadId
? `https://mail.google.com/mail/u/0/#inbox/${threadId}`
: 'https://mail.google.com';
digestLines.push(`*${index + 1}. ${subject}*`);
digestLines.push(`👤 ${from} · ${timeLabel}`);
digestLines.push(`> ${snippet}${snippet.length === 120 ? '...' : ''}`);
digestLines.push(`🔗 <${gmailLink}|Open in Gmail>`);
digestLines.push('');
});
const digestText = digestLines.join('\n').trim();
return [{ json: { digestText, emailCount: dedupedItems.length } }];n8n Canvas > + Node > IF > Condition Builder
Handle the empty-inbox case gracefully
If no emails match your Gmail query, the Gmail node returns zero items and the Code node will produce an empty digest. Add an IF node between the Gmail node and the Code node to check the item count. If zero emails came back, route to a separate Slack node that posts 'No priority emails in the last 24 hours — inbox clear.' This prevents the digest from posting a blank or confusing message to Slack.
- 1Click '+' after the Gmail node to insert a node before the Code node
- 2Search for 'IF' and select the IF node
- 3In the condition builder, set 'Value 1' to the expression: {{ $input.all().length }}
- 4Set the operator to 'Greater Than' and 'Value 2' to 0
- 5Connect the TRUE branch to the Code node and the FALSE branch to a new Slack node
n8n Canvas > + Node > Slack > Credential > Create New > Bot Token
Connect your Slack account and configure the Slack node
Click '+' after the Code node and add a Slack node. Click 'Credential for Slack API' and select 'Create New Credential'. You'll need a Slack Bot Token (starts with xoxb-) from a Slack App you create at api.slack.com/apps. The bot needs the chat:write scope to post messages. Set 'Operation' to 'Post Message' and choose the Resource as 'Message'.
- 1Click '+' after the Code node
- 2Search 'Slack' and select the Slack node
- 3Click 'Credential for Slack API' and select 'Create New Credential'
- 4Paste your Slack Bot Token (xoxb-...) into the 'Access Token' field
- 5Click 'Save' and confirm the green checkmark appears
- 6Set 'Operation' to 'Post Message' and 'Resource' to 'Message'
Slack Node > Channel > Text > Appearance
Configure the Slack message with the digest content
In the Slack node, set 'Channel' to your target channel name or ID — using the channel ID (starts with C0...) is more reliable than the name since channel names can change. In the 'Text' field, use the expression editor to reference the Code node output: {{ $node['Code'].json.digestText }}. Enable 'As User' if you want the message to appear from the bot's name. Set 'Username' to something like 'Email Digest' and optionally add a mail emoji as the icon.
- 1In the 'Channel' field, enter your Slack channel ID (e.g. C04ABCDE123)
- 2Click the expression toggle on the 'Text' field (the lightning bolt icon)
- 3Type or paste: {{ $node['Code'].json.digestText }}
- 4Optionally set 'Username' to 'Email Digest' under 'Other Options'
- 5Optionally set 'Icon Emoji' to ':email:'
IF Node > FALSE branch > + Node > Slack
Wire the empty-inbox Slack node for the FALSE branch
Go back to the IF node's FALSE output branch and connect it to a second Slack node. Configure this node with the same channel and credentials. In the 'Text' field, type a static message: ':white_check_mark: No priority emails in the last 24 hours.' This gives the team a positive signal that the digest ran — not just silence — which matters for trust in the automation.
- 1Click the FALSE output circle on the IF node
- 2Select the Slack node from the picker
- 3Use the same Slack credential as step 7
- 4Set the same channel ID
- 5In 'Text', enter ':white_check_mark: No priority emails in the last 24 hours.'
n8n Workflow Editor > Save > Active Toggle > Executions Panel
Activate the workflow and verify the first scheduled run
Click 'Save' in the top right, then toggle the workflow from 'Inactive' to 'Active' using the toggle in the top bar. The workflow will now run at your configured schedule. To verify without waiting, click the three-dot menu next to the workflow name and select 'Execute Workflow' to trigger a manual test run. Check the Slack channel for the digest message and review the execution log in the n8n 'Executions' panel for any errors.
- 1Click the 'Save' button in the top right of the editor
- 2Click the toggle switch in the top bar to set the workflow to 'Active'
- 3Click the three-dot menu next to the workflow name
- 4Select 'Execute Workflow' for an immediate test run
- 5Open the 'Executions' tab in the left sidebar to confirm a green success status
Workflow Editor > Settings (gear icon) > Error Workflow
Set up error notifications so silent failures don't go unnoticed
Scheduled workflows fail silently unless you set up an error handler. In n8n, go to the workflow settings by clicking the gear icon in the top bar. Under 'Error Workflow', select an existing error-handler workflow or create a simple one that posts a Slack message to a #alerts channel when an execution fails. Without this, a Gmail API credential expiry or Slack rate limit can cause days of missed digests before anyone notices.
- 1Click the gear icon in the top right of the workflow editor
- 2Scroll to the 'Error Workflow' section
- 3Click 'Select Workflow' and choose an existing error handler, or click 'Create New'
- 4In the error handler workflow, add a Slack node that posts to #alerts with the message: 'Email Digest workflow failed: {{ $json.error.message }}'
- 5Save both workflows
Scaling Beyond More than 50 emails matching your query per digest run+ Records
If your volume exceeds More than 50 emails matching your query per digest run records, apply these adjustments.
Cap the result set and prioritize by label
Set the Gmail node 'Limit' to 50 and refine your query to include only the highest-signal emails — add 'is:important' or a specific label to reduce noise. Posting 100+ emails to Slack in a single message creates a wall of text that nobody reads, which defeats the purpose of a digest.
Split the digest into sections by category
Instead of one giant digest, run separate Gmail queries in the same workflow for different categories (clients, vendors, internal) and post each as a separate Slack message block. Use Slack's Block Kit with section dividers so the channel message is skimmable rather than a raw list.
Use Gmail's 'newer_than' with a precise epoch cutoff to avoid duplicates
At high volume, Gmail's relative time tokens become imprecise and you'll see emails appear in two consecutive digests. Calculate the exact cutoff timestamp in a Code node using Date.now() minus your interval in milliseconds and build the query with 'after:EPOCH_SECONDS'. Store the last run timestamp in n8n's Static Data to make the window exact.
Watch Gmail API quota at high frequency
If you run hourly digests across multiple workflows, you can exhaust Gmail's 250 quota units per second burst limit. Stagger workflow start times by at least 30 seconds if running multiple Gmail-based workflows and check your usage in Google Cloud Console under APIs > Gmail API > Quotas.
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 you want full control over how the digest is formatted, you're comfortable with a small amount of JavaScript, and you're running self-hosted infrastructure where you don't want to pay per execution. The Code node in n8n is what makes this use case genuinely useful — you can deduplicate by thread, add direct Gmail links, handle missing fields, and format Slack mrkdwn exactly how you want it. If your team needs this set up in 15 minutes with zero code, pick Zapier instead and accept the formatting limitations.
On n8n Cloud, scheduled workflows cost nothing beyond the base plan ($20/month for the Starter tier), and this workflow uses roughly 3-5 node executions per run (Schedule, Gmail, IF, Code, Slack). At a daily cadence that's ~150 executions per month — well inside the 2,500 execution limit on the Starter plan. Self-hosted n8n is free at any volume. Zapier costs $19.99/month for multi-step zaps and charges per task — at one digest per day with 20 emails per run, that's 600 tasks/month, pushing you toward the $49/month plan. n8n is cheaper by $29-49/month at this volume.
Make (formerly Integromat) handles the scheduled digest pattern well and its built-in array aggregator is easier to use than writing a Code node — no JavaScript required to concatenate fields. Zapier's 'Digest by Zapier' native feature is the simplest possible implementation but gives you almost no control over formatting and only supports one digest per trigger type per zap. Power Automate has solid Gmail connector support through the Google Calendar connector workaround, but formatting a Slack message with conditional logic requires multiple Compose actions chained together in a way that is genuinely painful to maintain. Pipedream's Node.js steps give you the same code flexibility as n8n but with a cleaner development experience and built-in version history — it's a real alternative if you prefer a hosted environment with GitHub-style debugging. n8n wins here because the self-hosted option eliminates execution costs entirely and the visual canvas makes the IF/branch logic easy to audit.
Three things you'll hit after setup. First, Gmail's search query 'newer_than:1d' is fuzzy — Google rounds to the nearest day boundary in the account's timezone, not a precise 24-hour window. You will occasionally see the same email in two consecutive daily digests. Fix this with the epoch timestamp approach in the Code node. Second, Slack's mrkdwn formatting is not standard markdown — asterisks bold, underscores italic, backticks code, but nested formatting (bold inside a blockquote) is inconsistently rendered across Slack clients. Test your digest on both desktop and mobile Slack before declaring it done. Third, if the Gmail OAuth token expires and the workflow fails silently, your team will notice the missing digest before n8n sends any alert — which means trust in the automation erodes fast. The error workflow setup in Step 11 is not optional for production use.
Ideas for what to build next
- →Add a weekly rollup in addition to the daily digest — Duplicate the workflow and change the Schedule Trigger to fire every Monday at 8am with 'newer_than:7d'. Adjust the digest header text to say 'Weekly Email Digest' so the team can distinguish it from daily summaries.
- →Route different email categories to different Slack channels — Add a Switch node after the Gmail node to branch emails by label or sender domain — client emails go to #customer-success, vendor emails go to #operations, and everything else goes to #general-inbox. Each branch gets its own Code and Slack node pair.
- →Let teammates reply to the digest to trigger a Gmail draft — Add a Slack Event trigger (message.channels) that watches for replies to the digest message, then uses the Gmail node with 'Create Draft' operation to pre-populate a response. This closes the loop from digest to action without leaving Slack.
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