appscript.dev
Automation Advanced Gmail

Quarantine phishing-pattern emails

Flag suspicious sender and link patterns into a review label so they never sit in the active inbox.

Published Feb 3, 2026

Northwind has been spear-phished twice — once a fake invoice, once a “your mailbox is full, reset your password” email that looked close enough to the real thing. Both got read and very nearly acted on because they were sitting in the inbox alongside genuine work, carrying the same weight as everything else.

This script adds a quiet layer of defence. Every few minutes it checks new inbox mail against a set of phishing red-flags — known spoofed-domain spellings, classic scam phrasings, and a same-domain impersonation check — and anything matching is moved out of the inbox into a quarantine label. It does not delete and it does not block; it just gets suspicious mail off the main view so it can be reviewed deliberately rather than reacted to in a hurry.

What you’ll need

  • A Gmail account to protect — typically the shared or owner mailbox most exposed to outside senders.
  • Nothing else. The script creates the quarantine label itself on first run.
  • A few minutes to tune RED_FLAGS and SPOOFED_DOMAINS to the kinds of attack Northwind actually sees.

The script

// Body phrases that commonly appear in phishing attempts.
const RED_FLAGS = [
  /verify your account/i,
  /reset your password.+(click|tap)/i,
  /wire transfer.+urgent/i,
  /gift card/i,
];

// Look-alike spellings of well-known domains (note the digit/letter swaps).
const SPOOFED_DOMAINS = ['rnicrosoft', 'g00gle', 'paypa1'];

// The label suspicious mail is moved into for review.
const QUARANTINE_LABEL = 'quarantine';

// Your own domain — used to catch outsiders impersonating internal staff.
const OWN_DOMAIN = 'northwind.studio';

/**
 * Scans recent inbox mail for phishing red-flags and moves anything
 * suspicious into the quarantine label, out of the inbox.
 */
function quarantineSuspicious() {
  // 1. Get (or create) the quarantine label.
  const quarantine = GmailApp.getUserLabelByName(QUARANTINE_LABEL)
    || GmailApp.createLabel(QUARANTINE_LABEL);

  // 2. Look only at inbox mail from the last day not already quarantined.
  const threads = GmailApp.search(
    'in:inbox newer_than:1d -label:' + QUARANTINE_LABEL
  );
  if (!threads.length) {
    Logger.log('No new inbox mail to scan.');
    return;
  }

  // 3. Quarantine every thread whose first message looks suspicious.
  let moved = 0;
  for (const thread of threads) {
    const msg = thread.getMessages()[0];
    if (!suspicious(msg)) continue;

    thread.addLabel(quarantine);
    thread.moveToArchive();
    moved++;
  }
  Logger.log('Quarantined ' + moved + ' thread(s).');
}

/**
 * Returns true if a message trips any phishing red-flag: a spoofed
 * sender domain, a scam phrase in the body, or an outsider claiming
 * to be an internal address.
 */
function suspicious(msg) {
  const from = msg.getFrom().toLowerCase();
  const body = msg.getPlainBody();

  // a. Sender domain is a known look-alike spelling.
  if (SPOOFED_DOMAINS.some((d) => from.includes(d))) return true;

  // b. Body contains a classic phishing phrase.
  if (RED_FLAGS.some((re) => re.test(body))) return true;

  // c. An outside sender, but the body name-drops our own domain —
  //    a hallmark of impersonation ("this is Awadesh from Northwind").
  const senderDomain = (from.match(/@([\w.-]+)/) || [, ''])[1];
  if (
    senderDomain &&
    senderDomain !== OWN_DOMAIN &&
    body.includes('@' + OWN_DOMAIN)
  ) {
    return true;
  }

  return false;
}

How it works

  1. quarantineSuspicious fetches (or creates) the quarantine label, then searches the inbox for mail from the last day that is not already quarantined. If nothing is new, it stops.
  2. For each thread it reads the first message and passes it to suspicious.
  3. suspicious runs three independent checks and returns true if any one of them trips:
    • Spoofed domain — the From address contains a known look-alike spelling such as rnicrosoft (an “rn” posing as an “m”) or paypa1 (a digit “1” for the letter “l”).
    • Red-flag phrase — the body matches a scam phrasing like “verify your account” or “wire transfer … urgent”.
    • Impersonation — the sender is from an outside domain but the body mentions a @northwind.studio address, a common trick for a stranger pretending to be a colleague.
  4. A thread that trips any check is labelled quarantine and archived, which removes it from the inbox in one move. It is not deleted — it is simply out of the way.
  5. The function logs how many threads were moved so you can see at a glance whether a run did anything.

Example run

Three emails arrive in the inbox in the last hour:

FromSubjectOutcome
[email protected]Your monthly invoiceLeft in inbox — no red-flags
[email protected]Verify your account nowQuarantined — spoofed domain and red-flag phrase
[email protected]Quick favourQuarantined — outsider name-dropping @northwind.studio in the body

After the run, the genuine invoice is untouched while both suspicious threads have moved to the quarantine label and out of the inbox, ready for a deliberate review.

Trigger it

Run this on a frequent time-driven trigger so suspicious mail is pulled out before anyone has a chance to act on it:

  1. In the Apps Script editor, open Triggers (the clock icon).
  2. Click Add trigger.
  3. Choose function quarantineSuspicious, event source Time-driven, type Minutes timer, every 10 minutes.

Ten minutes keeps the window of exposure small while staying comfortably within Gmail quota.

Watch out for

  • False positives are inevitable. A genuine email from IT really might say “reset your password”, and a real supplier might mention a Northwind address. Review the quarantine label regularly — at least weekly — and never delete from it automatically.
  • This is a tripwire, not a filter. It catches patterns, not intent. A well-crafted phish that avoids these phrases will sail straight through; treat the script as one layer, alongside Gmail’s own filtering and basic staff awareness.
  • Only the first message is scanned. A clean opener followed by a malicious reply in the same thread is not caught. For high-risk mailboxes, loop over every message in the thread.
  • Tune the lists to your reality. The default SPOOFED_DOMAINS and RED_FLAGS are starting points. Add the look-alikes and phrasings from phishing attempts Northwind has actually received — those are the patterns most likely to return.
  • Archiving is reversible but quiet. Quarantined threads leave the inbox with no notification. If a senior colleague needs to know mail was held, add a summary email or a Chat message at the end of the run.
  • HTML-only links are invisible here. getPlainBody drops markup, so a phishing link hidden behind a styled button has no surrounding text for RED_FLAGS to match. Inspect raw content if link-based attacks are your main threat.

Related