appscript.dev
Automation Beginner Gmail

Auto-reply to out-of-hours support emails

Detect messages arriving outside Northwind's London business hours and send a holding reply.

Published Jan 6, 2026

[email protected] is staffed Monday to Friday, 9am to 6pm London time. A message that arrives at 11pm or over the weekend sits unanswered until the next working day — and a client who hears nothing back assumes it was missed. Gmail’s built-in vacation responder is all-or-nothing; it cannot reply only outside business hours.

This script fills that gap. It runs on a short timer, checks whether the studio is currently open, and — if it is not — sends one holding reply to each new, unanswered support thread. The client gets an instant acknowledgement, and a label makes sure nobody is replied to twice.

What you’ll need

  • A Gmail account (or a delegated mailbox) that receives support email, with a support label applied to incoming threads — by filter or by hand.
  • Permission for the script to read and reply to that mailbox.
  • Nothing else. The script creates the support/auto-replied label itself on first run.

The script

// Northwind's timezone and opening hours (24-hour clock).
const TZ = 'Europe/London';
const OPEN_HOUR = 9;   // 9am
const CLOSE_HOUR = 18; // 6pm

// The label applied to threads we have already auto-replied to.
const REPLIED_LABEL = 'support/auto-replied';

// The holding message sent to out-of-hours senders.
const HOLDING_REPLY = `Thanks for emailing Northwind. Our team is offline ` +
  `right now and will reply on the next working day. For urgent issues, ` +
  `text +44 7700 900000.`;

/**
 * If the studio is currently closed, sends a one-off holding reply to
 * each new, unanswered support thread.
 */
function autoReplyOutOfHours() {
  // During business hours there is nothing to do — staff will reply.
  if (isBusinessHours()) return;

  // Find unread support threads we have not already auto-replied to.
  const threads = GmailApp.search(
    'label:support is:unread -label:support/auto-replied newer_than:1d'
  );
  if (!threads.length) return;

  // Find or create the label that marks an auto-replied thread.
  const tag = GmailApp.getUserLabelByName(REPLIED_LABEL)
    || GmailApp.createLabel(REPLIED_LABEL);

  for (const thread of threads) {
    // Skip threads where someone at Northwind has already written —
    // those are not waiting on a holding reply.
    const fromUs = thread.getMessages()
      .some((m) => m.getFrom().includes('@northwind.studio'));
    if (fromUs) continue;

    // Send the holding reply and tag the thread so it is skipped next time.
    thread.reply(HOLDING_REPLY);
    thread.addLabel(tag);
  }
}

/**
 * Returns true if the current time is within Northwind's London
 * business hours: Monday to Friday, OPEN_HOUR to CLOSE_HOUR.
 */
function isBusinessHours() {
  const now = new Date();
  const hour = parseInt(Utilities.formatDate(now, TZ, 'H'));
  const day = parseInt(Utilities.formatDate(now, TZ, 'u')); // 1=Mon .. 7=Sun
  return day <= 5 && hour >= OPEN_HOUR && hour < CLOSE_HOUR;
}

How it works

  1. autoReplyOutOfHours first calls isBusinessHours. If the studio is open it returns straight away — staff will handle the email.
  2. Out of hours, it searches Gmail for threads that are labelled support, still unread, not already labelled support/auto-replied, and newer than a day — so old threads are never revisited.
  3. If the search finds nothing it returns.
  4. It finds the support/auto-replied label, creating it the first time the script runs.
  5. For each thread it checks whether any message came from a @northwind.studio address. If so, someone has already engaged and the thread is skipped.
  6. Otherwise it sends the holding reply with thread.reply and adds the support/auto-replied label, which is what stops the same thread being replied to on the next run.
  7. isBusinessHours uses Utilities.formatDate with the London timezone to read the current hour and weekday, returning true only Monday to Friday between the opening and closing hours.

Example run

It is Saturday at 10:30am London time. A client sends:

Subject: Can’t access the shared brand folder The link in your last email gives me a permission error.

The script runs on its timer, sees the studio is closed, and the client immediately receives:

Thanks for emailing Northwind. Our team is offline right now and will reply on the next working day. For urgent issues, text +44 7700 900000.

The thread gets the support/auto-replied label, so when the script runs again ten minutes later it is skipped — the client gets exactly one holding reply.

Trigger it

Run this on a frequent timer so out-of-hours senders hear back quickly:

  1. In the Apps Script editor open Triggers (the clock icon).
  2. Add a trigger for autoReplyOutOfHours, Time-driven, Minutes timer, every 10 minutes.
  3. Approve the authorisation prompt. New out-of-hours emails now get a holding reply within ten minutes.

Watch out for

  • The search window is newer_than:1d. If the script is paused for more than a day, anything older than that is never auto-replied to — widen the window if you expect long gaps.
  • The support/auto-replied label is the only guard against double replies. If someone removes it from a thread, that thread gets another holding reply.
  • isBusinessHours does not know about public holidays — the studio will be treated as open on a bank holiday. Add a holiday check if that matters.
  • The reply goes to whoever is on the thread, so a thread that already includes internal staff is skipped by the @northwind.studio check — keep that domain accurate.
  • Gmail enforces daily sending limits. A normal support inbox is well within them, but a sudden flood of messages could hit the cap.

Related