applyGmailLabelRules(rules) takes rule objects {query, label, archive}, creates any label that does not exist, applies it to matching threads in batches of 100, and returns a count per rule. Set archive: true to move those threads out of the Inbox as well.
When to use
- A rules tab that labels billing mail, newsletters, or client threads
- A time-driven trigger that keeps the Inbox tidy
- Any repeatable Gmail cleanup you do not want to click through by hand
How to use this snippet
/**
* Apply Gmail label rules. Creates missing labels.
* Each rule: {query, label, archive}. Threads are fetched and labeled
* in batches of 100 (the GmailApp.addToThreads / moveThreadsToArchive limit).
* A -label: term is added so already-labeled threads are not processed again.
*
* @param {{query: string, label: string, archive?: boolean}[]} rules
* @return {{query: string, label: string, archive: boolean, applied: number, skipped?: boolean}[]}
*/
function applyGmailLabelRules(rules) {
var counts = [];
(rules || []).forEach(function (rule) {
var query = String((rule && rule.query) || '').trim();
var name = String((rule && rule.label) || '').trim();
var archive = !!(rule && rule.archive);
if (!query || !name) {
counts.push({ query: query, label: name, archive: archive, applied: 0, skipped: true });
return;
}
var label = GmailApp.getUserLabelByName(name) || GmailApp.createLabel(name);
var term = /[\s"]/.test(name) ? '-label:"' + name.replace(/"/g, '') + '"' : '-label:' + name;
var q = query + ' ' + term;
var applied = 0;
for (;;) {
var threads = GmailApp.search(q, 0, 100);
if (!threads.length) break;
label.addToThreads(threads);
if (archive) GmailApp.moveThreadsToArchive(threads);
applied += threads.length;
if (threads.length < 100) break;
}
counts.push({ query: query, label: name, archive: archive, applied: applied });
});
return counts;
}
Example
function runInboxRules() {
var rules = [
{ query: 'from:billing@example.com newer_than:7d', label: 'Invoices', archive: true },
{ query: 'from:news@example.com', label: 'Newsletters', archive: true }
];
Logger.log(applyGmailLabelRules(rules));
}
Notes
GmailLabel.addToThreadsandGmailApp.moveThreadsToArchiveaccept at most 100 threads per call. The helper pages in chunks of 100 until the query is exhausted or the six-minute runtime is hit.- Already-labeled threads are skipped by appending
-label:YourLabelto the query. Leave that term out of the sheet; the helper adds it. - Gmail has daily read/write quotas. A 15-minute trigger is a safe interval (
everyMinutesallows 1, 5, 10, 15, or 30). A huge first-run backlog may take several trigger firings to finish. - Empty query or label rows are skipped (
skipped: true).
Happy Coding!
