Gmail + Google Sheets: follow ups that stop on reply
You meant to follow up. Then the week got busy, the spreadsheet got messy, and a “quick nudge” turned into a lost deal.
Gmail follow ups hit sales reps first, honestly, but agency owners and marketing teams running outbound feel the same grind. You want consistent touches without sounding robotic, and you definitely don’t want to keep pinging someone who already replied.
This n8n workflow runs reply-aware follow-up sequences from Google Sheets through Gmail, pauses on weekends, and stops the moment a thread gets a real response. You’ll see what it fixes, how it works, and what you need to launch it.
How This Automation Works
See how this solves the problem:
n8n Workflow Template: Gmail + Google Sheets: follow ups that stop on reply
flowchart LR
subgraph sg0["Every hour Flow"]
direction LR
n0@{ icon: "mdi:database", form: "rounded", label: "Update last contacted time", pos: "b", h: 48 }
n2@{ icon: "mdi:swap-vertical", form: "rounded", label: "Email sequence", pos: "b", h: 48 }
n5@{ icon: "mdi:message-outline", form: "rounded", label: "Get previous message threads", pos: "b", h: 48 }
n6@{ icon: "mdi:message-outline", form: "rounded", label: "Get thread details", pos: "b", h: 48 }
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Classify threads"]
n8@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Next message due?", pos: "b", h: 48 }
n12@{ icon: "mdi:cog", form: "rounded", label: "Call message send sub-workflow", pos: "b", h: 48 }
n13@{ icon: "mdi:swap-vertical", form: "rounded", label: "Prepare reply params", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "Prepare first message params", pos: "b", h: 48 }
n15@{ icon: "mdi:cog", form: "rounded", label: "Call message send sub-workfl..", pos: "b", h: 48 }
n16@{ icon: "mdi:swap-horizontal", form: "rounded", label: "To email?", pos: "b", h: 48 }
n17["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Decode messages"]
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Decode placeholder values"]
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Package placeholder values"]
n20@{ icon: "mdi:swap-vertical", form: "rounded", label: "Settings", pos: "b", h: 48 }
n22@{ icon: "mdi:database", form: "rounded", label: "Get emails", pos: "b", h: 48 }
n23@{ icon: "mdi:play-circle", form: "rounded", label: "Every hour", pos: "b", h: 48 }
n24@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Don't email on weekends", pos: "b", h: 48 }
n20 --> n2
n16 --> n14
n23 --> n24
n22 --> n16
n2 --> n5
n2 --> n22
n17 --> n7
n7 --> n8
n8 --> n13
n6 --> n17
n13 --> n18
n24 --> n20
n18 --> n12
n19 --> n15
n5 --> n6
n14 --> n19
n15 --> n0
end
subgraph sg1["Execute Workflow Flow"]
direction LR
n1@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set message template", pos: "b", h: 48 }
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Fill message placeholders"]
n4@{ icon: "mdi:swap-vertical", form: "rounded", label: "Compose message", pos: "b", h: 48 }
n9@{ icon: "mdi:play-circle", form: "rounded", label: "Execute Workflow Trigger", pos: "b", h: 48 }
n10@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Replying?", pos: "b", h: 48 }
n11@{ icon: "mdi:message-outline", form: "rounded", label: "Send new message", pos: "b", h: 48 }
n21@{ icon: "mdi:message-outline", form: "rounded", label: "Reply to message", pos: "b", h: 48 }
n10 --> n21
n10 --> n11
n4 --> n10
n1 --> n3
n9 --> n1
n3 --> n4
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n23,n9 trigger
class n8,n16,n24,n10 decision
class n0,n22 database
class n7,n17,n18,n19,n3 code
class n1 disabled
classDef customIcon fill:none,stroke:none
class n7,n17,n18,n19,n3 customIcon
The Challenge: Follow-ups that either get forgotten or get awkward
Manual follow-up sounds simple until you do it at scale. You send the first email, add a note in a sheet, set a reminder, and then life happens. Some leads reply and you miss it for a day. Others don’t reply and quietly slip off your radar. And the worst version is when someone replies… and your “Just checking in” follow-up still fires anyway because your tracker didn’t know the thread changed.
It adds up fast. Here’s where it breaks down in real teams.
- You spend about 5–10 minutes per lead just updating status fields, dates, and “next follow-up” notes.
- Replies get buried inside Gmail threads, so you keep chasing people who already answered.
- Sequences drift because each rep “does it their own way,” which means your messaging and timing aren’t consistent.
- Weekend sends happen by accident, and Monday starts with apologizing for bad timing.
The Fix: A reply-aware Gmail sequence driven by Google Sheets
This workflow turns a simple Google Sheet into a follow-up engine that behaves like a thoughtful human. You keep a list of recipients (plus optional fields like name and company) in Sheets. n8n reads that list on a schedule, selects the right email template for each lead based on where they are in the sequence, and sends the message through Gmail. After that, it does the part people usually mess up: it checks the Gmail thread that belongs to that campaign and decides if another follow-up is needed. If there’s a reply, it stops. If it’s not time yet, it waits. If it’s due and still quiet, it sends the next step.
The workflow starts on an hourly schedule, but only runs on weekdays. It pulls recipients from Google Sheets, looks up any prior tagged threads in Gmail, then uses that thread status to decide “send now,” “wait,” or “do nothing.”
What Changes: Before vs. After
| What This Eliminates | Impact You’ll See |
|---|---|
|
|
Real-World Impact
Say you’re running a 3-email sequence (day 0, day 3, day 7) to 40 leads per week. Manually, you might spend about 5 minutes per lead across the week checking threads, updating your sheet, and sending the next message, which is roughly 3 hours of pure admin. With this workflow, you spend about 20 minutes setting up the sheet and templates, then maybe 5 minutes a day reviewing replies. The follow-ups keep going in the background, and they stop the moment a lead answers.
Requirements
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store recipients and fields.
- Gmail to send and detect replies in threads.
- Google account access (connect via n8n credentials setup)
Skill level: Intermediate. You’ll connect Google credentials, edit a few template fields, and confirm the sheet columns match what the workflow expects.
Need help implementing this? Talk to an automation expert (free 15-minute consultation).
The Workflow Flow
Hourly weekday trigger. n8n checks every hour, then applies a weekday gate so the automation doesn’t run on weekends.
Recipient + sequence lookup. It loads your recipient list from Google Sheets and reads your “email sequence map” (the timing and templates for day 0, day 3, day 7, and so on).
Thread awareness and due-date logic. For each recipient, the workflow searches Gmail for prior campaign threads, loads thread details, and evaluates whether anyone replied. If no reply exists, it checks if the next follow-up is due yet.
Send, then record. When it’s time, it builds an HTML email with your placeholders (name, company, etc.), sends through Gmail, and records the contact action back into Google Sheets so future runs know what happened.
You can easily modify the email sequence timing to match your sales cycle based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Schedule Trigger
Set the workflow to run on a weekday schedule and allow manual execution via subflow for testing.
- Open Hourly Schedule Trigger and set Interval to
hourswith triggerAtMinute set to12. - In Weekday Gate, confirm the condition uses
{{$now.isWeekend()}}and the operator is set tofalseto block weekends. - Keep Subflow Trigger Start connected to Select Message Template for manual subflow runs.
Step 2: Connect Google Sheets
Configure the spreadsheet source for recipients and the update step for first contact logging.
- Open Fetch Recipient Sheet and set Document ID to
{{$('Configuration Values').item.json.sheet_url}}and Sheet Name to the same value. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Fetch Recipient Sheet.
- Open Record First Contact and confirm Operation is
updatewith Row Number set to{{$('Unemailed Check').item.json.row_number}}and first_emailed set to{{$now.format('yyyy-MM-dd')}}. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Record First Contact.
row_number column and all placeholder columns referenced in templates (e.g., name, company), or Bundle Placeholder Data will throw an error.Step 3: Set Up Campaign Configuration and Templates
Define campaign settings and message sequences that drive all downstream processing.
- In Configuration Values, set sheet_url to your spreadsheet URL, subject to
My amazing campaign(or your subject), sender_name toAutomation Sender, email_column_name toemail, and mail_id to a unique campaign ID like[YOUR_ID]. - In Email Sequence Map, review the JSON and keep the jsonOutput block containing the
emailsarray with eachmessageandsend_on_day. - Note that Email Sequence Map outputs to both Retrieve Prior Threads and Fetch Recipient Sheet in parallel.
- If you want a manual template preview, enable Select Message Template (currently disabled) and confirm message_template uses
{{$('Email Sequence Map').first().json.emails[0].message}}.
Step 4: Configure Thread Retrieval and Follow-up Logic
Set up the Gmail search, thread decoding, and follow-up timing checks for replies and ongoing sequences.
- Open Retrieve Prior Threads and keep the search filter
=subject:{{ $json.subject }} after:{{ $now.minus({'days': $json.emails.last().send_on_day+1}).toSQL().substr(0, 10) }}with Resource set tothread. - Credential Required: Connect your gmailOAuth2 credentials in Retrieve Prior Threads and Load Thread Details.
- Ensure Load Thread Details has Operation set to
getand Thread ID to{{$json.id}}. - Keep Decode Thread Content and Evaluate Thread Status as-is; they parse HTML, compute
next_message_due, and detect previous campaign emails. - In Follow-up Due Check, keep the boolean condition
{{$json.next_message_due}}set to true for follow-up eligibility.
Step 5: Set Up Placeholder Processing and HTML Assembly
Prepare template data, inject placeholders, and build the final HTML message content.
- In Assemble First Email, confirm to_email uses
{{$('Fetch Recipient Sheet').item.json[$('Configuration Values').item.json.email_column_name]}}and message_template uses{{$('Email Sequence Map').first().json.emails[0].message}}. - In Bundle Placeholder Data, keep the code that validates sheet columns and builds
item.json.placeholders. - In Populate Template Fields, keep the JavaScript placeholder replacement logic to generate
item.json.message. - In Build HTML Message, set message to
=<span data-cam='{{ $json.mail_id }}' data-seq='{{ $json.mail_seq }}' data-ph='{{ JSON.stringify($json.placeholders) }}'></span>{{ $json.message }}.
Step 6: Configure Reply Handling, Sub-Workflows, and Email Sending
Route the workflow between reply and fresh email paths, and ensure sub-workflows are linked for data enrichment or logging.
- In Assemble Reply Data, verify reply_message_id uses
{{$json.messages.last().id}}and message_template uses{{$('Email Sequence Map').first().json.emails[$json.next_sequence_number].message}}. - Keep Extract Placeholder Data connected to Run Sub-Workflow (Configure Required) for additional processing of reply placeholders.
- Open Run Sub-Workflow (Configure Required) and set Workflow ID to the child workflow you want to execute.
- Open Run Sub-Workflow (Configure Required) 2, set Mode to
each, and set Workflow ID to the child workflow that prepares logging data. - Reply Required? routes to Send Reply Email if
{{$json.reply_message_id}}exists; otherwise it sends a new email via Send Fresh Email. - Credential Required: Connect your gmailOAuth2 credentials in Send Fresh Email and Send Reply Email.
Step 7: Test and Activate Your Workflow
Verify that emails generate correctly, logging works, and scheduling runs as expected.
- Use Subflow Trigger Start to execute a test run and follow the data into Populate Template Fields and Build HTML Message.
- Confirm Send Fresh Email or Send Reply Email receives a populated
messageand correctsubject. - Verify Record First Contact updates
first_emailedwith today’s date in your Google Sheet. - Once tests succeed, activate the workflow and let Hourly Schedule Trigger run it automatically on weekdays.
Watch Out For
- Google (Gmail/Sheets) credentials can expire or need specific permissions. If things break, check the n8n Credentials screen and re-auth the Google connection first.
- If you’re using Wait logic or relying on scheduled runs, processing times vary. If downstream Gmail nodes fail because a thread wasn’t found yet, increase the delay or tighten the thread search query.
- Default templates are usually too generic. Add your brand voice and your real “why you’re emailing” early, or you will keep rewriting messages every time you review sent emails.
Common Questions
About an hour if your Google accounts are ready.
Yes, but you’ll want one person to own setup. Most of the work is connecting Google credentials and matching your sheet columns to the workflow fields.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Google Workspace costs if you’re using a paid Gmail/Google account.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
You can change the sequence timing and messages in the “Email Sequence Map” and “Select Message Template” parts of the workflow. If you want different personalization fields, update the Google Sheet columns and adjust the placeholder extraction so {name} or {company} matches your data. Many teams also customize the weekday rules (for example, block holidays) and tweak the “Retrieve Prior Threads” logic so tags and searches match their Gmail labels.
Usually it’s an expired Google auth session, so reconnect Gmail in n8n and try again.
On n8n Cloud, capacity depends on your plan’s monthly executions, and this workflow can use several executions per run because it checks threads and recipients on a schedule. If you self-host, there’s no platform execution cap, but Gmail will still enforce API and sending limits on your account. Practically, it’s great for small teams running dozens to a few hundred leads at a time, and you can scale further by segmenting campaigns into separate sheets and workflow copies. If you push huge batches, add pacing and tighter Gmail searches to avoid rate-limit errors.
Often, yes, because reply-aware follow-ups require more logic than a simple trigger-and-send. n8n handles branching, filters, and thread checks without you stitching together a bunch of separate Zaps or scenarios. It also gives you a self-host option, which matters when you run frequent schedule checks. Zapier or Make can still be fine for very small sequences, but they get clunky once you need “stop on reply” behavior and campaign tagging. Talk to an automation expert if you want a quick recommendation for your exact setup.
Once this is running, follow-ups happen the way you always intended: on time, on weekdays, and only until someone replies. Set it up once, then focus on the conversations that actually matter.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.