DEV Community

Dovetail Scripts
Dovetail Scripts

Posted on

One polite follow-up when a lead goes quiet (Apps Script)

A fast first reply wins leads, but plenty of good leads still go quiet. One short follow-up, sent about 48 hours later, recovers a surprising number of them. More than one starts to feel like pestering.

Here is a small Google Apps Script that does exactly that from the same Google Sheet you use to track leads. It pairs with the auto-reply script from my earlier post, but it also works on its own.

The sheet layout

Same columns as before: email, status, sent_at. The first script sets status to sent and stamps sent_at when it replies. This one looks for rows that are still sent (never replied to) with a sent_at older than 48 hours.

How it knows the lead never replied

It asks Gmail. If any message from the lead's address arrived after your first reply went out, the lead is not quiet, so the script skips them:

function sendFollowUps() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const rows = sheet.getDataRange().getValues();
  const head = rows[0];
  const col = n => head.indexOf(n);
  const HOURS = 48;
  const MAX_PER_RUN = 10;
  const now = Date.now();
  let sent = 0;

  for (let i = 1; i < rows.length && sent < MAX_PER_RUN; i++) {
    if (String(rows[i][col('status')]) !== 'sent') continue;
    const sentAt = new Date(rows[i][col('sent_at')]);
    if (isNaN(sentAt) || (now - sentAt) < HOURS * 3600 * 1000) continue;

    const email = String(rows[i][col('email')]).trim();
    const replied = GmailApp.search(`from:${email} after:${Math.floor(sentAt.getTime() / 1000)}`, 0, 1);
    if (replied.length > 0) {
      sheet.getRange(i + 1, col('status') + 1).setValue('replied');
      continue;
    }

    GmailApp.sendEmail(email, 'Still happy to help', 'Hi, just bumping this in case it got buried. Happy to answer any questions - or if now is not the right time, no worries at all.');
    sheet.getRange(i + 1, col('status') + 1).setValue('followed_up');
    sent++;
  }
}
Enter fullscreen mode Exit fullscreen mode

What it does, line by line

  • Only touches rows marked sent with a sent_at at least 48 hours old.
  • Searches Gmail for anything from the lead after your first reply. A reply flips the row to replied so you never follow up with someone who already wrote back.
  • Sends one short follow-up, then marks the row followed_up so it never sends a second one.
  • MAX_PER_RUN caps each run. Schedule it with a time-driven trigger (Triggers > Add trigger > hourly) and it stays far under Gmail's daily sending limits.

Two things that matter more than the code

Keep the follow-up short and human. Two sentences, no pitch, no "just checking in" three times over. And stop after one. A lead who ignores two emails was never going to buy from the third.


I packaged this follow-up, the instant auto-reply, editable email templates, and a 10-minute setup guide into the LeadReply Kit if you would rather skip the wiring. The kit is mock-tested sample code, so read it before pointing it at real leads.

Top comments (0)