Built a scenario that chases clients who go quiet: reads a Google Sheet, checks Gmail for a reply, sends a nudge if there isn’t one, escalates twice more four days apart, then stops.
Sharing it in case it’s useful — but honestly the failures are more valuable than the scenario.
Structure: Sheets Search Rows → filter (due) → Gmail Search emails → filter (0 bundles) → Gmail Send → Sheets Update a Row
Seven things that cost me hours — all ran green, none threw an error
1. Typed mappings resolve to blank. {{2.Email}} and {{2.B}} both silently produce nothing. Only clicking the field from the mapping panel inserts a reference that actually works.
2. Missing spaces in a Gmail query. from:[email protected]:2026/08/20 returns 0 results — indistinguishable from “no reply found”. Read the resolved query in the Input, never trust the bundle count.
3. Gmail’s after: needs slashes. 2026-08-20 is silently ignored rather than rejected.
4. “Use column headers as IDs of the columns” is off by default in Update a Row, so values land in columns A and B instead of the named ones. In my case it overwrote the client’s name and email address.
5. Positional column slots don’t survive an import — they collapse to column A in the recipient’s copy. Header-name mapping is mandatory for anything you share.
6. The spreadsheet ID is baked into a shared scenario, in every module referencing it. Two here. Fixing one doesn’t fix the other — and missing the second means it emails but never writes back, so it re-sends every day.
7. Unsaved changes mean Run once tests the previous version. Cost me an hour debugging a fix I’d already made.
Free, no catch. If you install it I’d like to hear what broke — especially anything on import I haven’t hit yet.
1 Like
Why not have a separate scenario that logs replies?
Setup forwarding in Gmail to a Make mailhook module. When an email is received → check the sheet if its a reply to something → if it is, log it.
Then you can skip the step where you are searching for replies and have a scenario that only chases people that haven’t replied.
3 Likes
Good breakdown. One extra failure mode I’d guard against is treating any Gmail search result as a current reply. An old message in the same thread—or a sent copy—can make the scenario stop or continue incorrectly.
I’d store the Gmail thread/message ID and a last-checked timestamp in the Sheet, then only accept inbound messages newer than the last follow-up. Before sending, use an idempotency key such as client + follow-up stage + due date, and update the row only after the send module succeeds.
If the Gmail match is ambiguous, routing that row to a review status is safer than sending another nudge automatically.
1 Like
That’s cleaner for reliability — the search is the weakest part of this.
Reason I went with search: it’s aimed at non-technical people installing it themselves, and Make’s free tier only allows two active scenarios. A mailhook version means two scenarios plus Gmail forwarding config, which doubles the install and spends their whole free allowance on one automation.
Genuinely torn though. Might build it that way as a version for people already on a paid plan. Thanks — hadn’t considered the forwarding route at all.
This is the one I hadn’t thought about, and you’re right.
after: is date-granular so anything sent earlier the same day counts, and nothing verifies the match is actually a reply to that thread — an unrelated email would stop the chase silently.
Cleanest fix I can see: store the thread ID the Send module returns and search on that instead of from: + date. One extra column, no second scenario. Rebuilding it that way.
Update-after-send I think I’ve got — Sheets Update is downstream of Gmail Send, so a failed send leaves the row untouched. But routing ambiguous matches to a review status rather than sending is a good call, adding that.
Genuinely useful, thanks.
Rebuilt it — you were right.
Query now scopes to the conversation subject, so an unrelated email from the same client no longer stops the chase:
from:{email} subject:"{about}" after:{last sent} -in:sent
Couldn’t do proper thread-ID matching in the end — Gmail search has no threadId: operator, so it’d need a separate thread module or Stoyan’s mailhook approach. Subject-scoping gets most of the way without a second scenario, which matters here because the free tier only allows two active ones.
Still leaves the granularity issue you flagged — after: is date-level not time-level, so a same-day message before the chase still counts. Logging that as a known limitation rather than pretending it’s solved.
Routing ambiguous matches to a review status is next. Thanks, genuinely improved it. New link: Snap-In · Client Chaser - Make.com Automation Scenario
built a second one on the same architecture — an invoice chaser. Reads a sheet of outstanding invoices, checks whether that client has replied about that specific invoice, sends a reminder if they haven’t. Escalates twice more five days apart, firmer each time, and stops the moment they reply. Three emails maximum, then the row retires itself.
Setup guide: Copy of Snap-In · Invoice Chaser — Setup Guide - Google Docs
Three things I’d flag for anyone else publishing scenarios — they only bite once someone else imports your work, and all three fail silently:
- “Use column headers as IDs of the columns” in Update a Row. Left off, values write to columns A and B instead of the named ones — which on most sheets is somebody’s name and email address.
- Positional column slots don’t survive an import, they collapse to column A in the recipient’s copy. Header-name mapping is effectively mandatory for anything shared.
- The spreadsheet ID is baked into every module that references it — two in this scenario. The importer has to re-point both, and fixing one doesn’t fix the other. Miss the second and it sends emails but never writes back, so it re-sends daily.
Worth importing into a clean account before publishing anything. It’s caught things for me that looked completely fine in my own.
Exactly — the thread ID is the cleanest anchor. One last guard I’d add is direction and time: only treat an inbound message newer than the stored last-follow-up timestamp as a reply. The thread ID proves the conversation, but not that the latest message came from the client. That should close the same-day edge case without adding another scenario.
The quote describes what the scenario does, not what breaks. “The failures are more valuable than the scenario” - which failures? The Gmail check missing a reply that is actually there, the Sheet read timing out, an escalation firing twice, or the whole chain silently stopping after one bad run? Each of those is a different failure mode with a different root cause, and the last one is the only one that never tells you it happened.