Tag VIP senders and prioritize their threads
Maintain a VIP list in a Sheet and auto-star and label their incoming mail.
Published Dec 9, 2025
Every inbox has a handful of people who must never be missed — the client whose brief unblocks the week, the partner waiting on a decision, the supplier holding a deadline. The trouble is they look exactly like everyone else in the inbox until you open the message and realise it has been sitting there for two hours.
Northwind keeps a short list of these must-respond-today contacts — eight names
in a Google Sheet. This script reads that list every few minutes and, the moment
mail arrives from one of them, stars the messages and applies a vip label.
The list lives in a Sheet rather than the code, so anyone on the team can add or
remove a contact without touching Apps Script.
What you’ll need
- A Google Sheet with a tab listing your VIP contacts. Put one email address per
row in column A, with a header such as
emailin row 1. - The spreadsheet’s ID, taken from its URL, dropped into the config below.
- Nothing else — the script creates the
viplabel itself if it does not exist.
The script
// The spreadsheet that holds your VIP contact list (one email per row).
const VIPS_SHEET_ID = '1abcVipsSheetId';
// The Gmail label applied to VIP threads.
const VIP_LABEL = 'vip';
// Only look at mail from the last day, so each run stays fast.
const SEARCH_WINDOW = 'newer_than:1d';
/**
* Reads the VIP list from the Sheet and, for each contact, stars and
* labels any of their recent threads that haven't been tagged yet.
* Designed to run on a short time-driven trigger.
*/
function tagVipThreads() {
// 1. Read column A of the VIPs sheet and drop blank rows.
const emails = SpreadsheetApp.openById(VIPS_SHEET_ID)
.getSheets()[0]
.getRange('A2:A')
.getValues()
.flat()
.filter(Boolean);
// 2. Bail out early if the list is empty — nothing to do.
if (emails.length === 0) {
Logger.log('VIP list is empty — nothing to tag.');
return;
}
// 3. Find the vip label, creating it on first run.
const label = GmailApp.getUserLabelByName(VIP_LABEL)
|| GmailApp.createLabel(VIP_LABEL);
// 4. For each VIP, search recent mail that isn't already labelled.
let tagged = 0;
for (const email of emails) {
const query = `from:${email} ${SEARCH_WINDOW} -label:${VIP_LABEL}`;
const threads = GmailApp.search(query);
for (const thread of threads) {
// Label the whole thread, then star every message in it.
thread.addLabel(label);
thread.getMessages().forEach((message) => message.star());
tagged++;
}
}
Logger.log(`Tagged ${tagged} VIP thread(s).`);
}
How it works
tagVipThreadsopens the VIPs spreadsheet and reads column A into a plain list of addresses, flattening the range and dropping any blank cells.- If the list is empty it logs a message and stops, so an empty Sheet never causes a wasted run.
- It looks up the
viplabel and creates it the first time the script runs, so there is no manual label setup. - For each VIP address it runs a Gmail search scoped to the last day and
excluding anything already carrying the
viplabel — the-label:vippart is what stops the same thread being processed on every run. - For each matching thread it applies the label and stars every message inside, so the conversation stands out both in the label view and in the inbox.
- It logs how many threads it tagged, which is handy when checking the trigger is doing its job.
Example run
Say the VIPs sheet looks like this:
| [email protected] |
| [email protected] |
| [email protected] |
If Priya sends a message in the last 24 hours, the next run finds the thread,
applies the vip label, and stars the message:
- Before: thread sits unmarked in the inbox among everything else.
- After: thread carries the
viplabel and a yellow star, so it is visible at a glance and reachable from theviplabel in one click.
Threads from non-VIP senders are ignored entirely, and a thread already labelled
vip is skipped on the next run.
Trigger it
This automation should feel near-real-time, so run it on a short interval:
- In the Apps Script editor, open Triggers (the clock icon).
- Click Add Trigger.
- Choose
tagVipThreads, event source Time-driven, type Minutes timer, and pick Every 5 minutes. - Save, and approve the authorisation prompt the first time it runs.
Watch out for
- The search uses
newer_than:1d, so a thread is only catchable within a day of arriving. If the trigger is paused for longer than that, older VIP mail will be missed. Widen the window if you expect gaps. from:${email}matches the address as Gmail sees it. If a VIP emails you from a different address — a personal account, a new domain — it will not be caught until you add that address to the Sheet.- The
-label:vipfilter is what prevents re-processing. If you remove the label from a thread by hand, the next run will re-tag and re-star it. - Every run reads the Sheet and runs one search per VIP. With a short list this is cheap; with hundreds of VIPs the searches add up, so keep the list to the contacts that genuinely need it.
- Starring touches every message in the thread. On a long existing thread that means a lot of stars at once — expected behaviour, but worth knowing.
Related
Convert long email threads into a summary note
Collapse a thread's history into a Doc for handover — perfect for client transitions or vacation cover.
Updated Jun 6, 2026
Pull event RSVPs from emails into a Sheet
Parse yes/no replies to event invites and tally attendance automatically.
Updated Jun 2, 2026
Turn forwarded emails into project tasks
Forward to [email protected] and a row lands in the Projects sheet under the right client.
Updated May 30, 2026
Turn starred emails into a task list
Sync every starred thread into the Northwind Tasks sheet automatically.
Updated May 26, 2026
Alert when a label hits a backlog threshold
Warn the Northwind team in Slack when a Gmail label has more than N unread threads.
Updated Mar 31, 2026