/** * Gmail Label Cleanup Script * Run from https://script.google.com * * What this does: * 1. Merges old labels into inbox-zero categories (relabels all threads) * 2. Archives + relabels cvlp threads to Newsletter * 3. Merges purchases into Receipt, deletes purchases * 4. Moves donations top-level, selling under business * 5. Deletes contract label (threads stay under business) * 6. Deletes empty/unused labels * * Safe to run multiple times - skips labels that don't exist. */ // ─── STEP 1: Merge old labels into inbox-zero categories ───────────────────── function mergeLabels() { var merges = [ { from: 'promo', to: 'Marketing' }, { from: 'mailing list', to: 'Newsletter' }, { from: 'twitter', to: 'Notification' }, { from: 'facebook', to: 'Notification' }, { from: 'tech', to: 'Newsletter' }, { from: 'To Reply', to: 'Awaiting Reply' }, ]; merges.forEach(function(m) { var fromLabel = GmailApp.getUserLabelByName(m.from); if (!fromLabel) { Logger.log('Skipping (not found): ' + m.from); return; } var toLabel = GmailApp.getUserLabelByName(m.to); if (!toLabel) { Logger.log('Creating label: ' + m.to); toLabel = GmailApp.createLabel(m.to); } Logger.log('Merging ' + m.from + ' -> ' + m.to); var threads = fromLabel.getThreads(0, 500); var total = 0; while (threads.length > 0) { toLabel.addToThreads(threads); fromLabel.removeFromThreads(threads); total += threads.length; Utilities.sleep(1000); threads = fromLabel.getThreads(0, 500); } Logger.log('Moved ' + total + ' threads: ' + m.from + ' -> ' + m.to); fromLabel.deleteLabel(); Logger.log('Deleted label: ' + m.from); }); } // ─── STEP 2: cvlp → Newsletter + archive ───────────────────────────────────── function archiveCvlp() { var cvlpLabel = GmailApp.getUserLabelByName('cvlp'); if (!cvlpLabel) { Logger.log('cvlp label not found, skipping'); return; } var newsletterLabel = GmailApp.getUserLabelByName('Newsletter'); if (!newsletterLabel) { newsletterLabel = GmailApp.createLabel('Newsletter'); } Logger.log('Processing cvlp: relabeling to Newsletter and archiving...'); var threads = cvlpLabel.getThreads(0, 500); var total = 0; while (threads.length > 0) { newsletterLabel.addToThreads(threads); cvlpLabel.removeFromThreads(threads); threads.forEach(function(t) { t.moveToArchive(); }); total += threads.length; Utilities.sleep(1000); threads = cvlpLabel.getThreads(0, 500); } Logger.log('Archived ' + total + ' cvlp threads'); cvlpLabel.deleteLabel(); Logger.log('Deleted label: cvlp'); } // ─── STEP 3: Merge purchases into Receipt ──────────────────────────────────── function mergePurchasesIntoReceipt() { var purchasesLabel = GmailApp.getUserLabelByName('purchases'); if (!purchasesLabel) { Logger.log('purchases label not found, skipping'); return; } var receiptLabel = GmailApp.getUserLabelByName('Receipt'); if (!receiptLabel) { receiptLabel = GmailApp.createLabel('Receipt'); } Logger.log('Merging purchases -> Receipt...'); var threads = purchasesLabel.getThreads(0, 500); var total = 0; while (threads.length > 0) { receiptLabel.addToThreads(threads); purchasesLabel.removeFromThreads(threads); total += threads.length; Utilities.sleep(1000); threads = purchasesLabel.getThreads(0, 500); } Logger.log('Moved ' + total + ' threads: purchases -> Receipt'); purchasesLabel.deleteLabel(); Logger.log('Deleted label: purchases'); } // ─── STEP 4: Restructure business nested labels ─────────────────────────────── function restructureBusinessLabels() { // Move donations top-level: rename business/donations -> donations var bizDonations = GmailApp.getUserLabelByName('business/donations'); if (bizDonations) { var donationsLabel = GmailApp.getUserLabelByName('donations'); if (!donationsLabel) { donationsLabel = GmailApp.createLabel('donations'); } Logger.log('Moving business/donations -> donations (top-level)'); var threads = bizDonations.getThreads(0, 500); var total = 0; while (threads.length > 0) { donationsLabel.addToThreads(threads); bizDonations.removeFromThreads(threads); total += threads.length; Utilities.sleep(1000); threads = bizDonations.getThreads(0, 500); } Logger.log('Moved ' + total + ' threads to top-level donations'); bizDonations.deleteLabel(); } else { Logger.log('business/donations not found - skipping'); } // Move selling under business: rename selling -> business/selling var sellingLabel = GmailApp.getUserLabelByName('selling'); if (sellingLabel) { var bizSelling = GmailApp.getUserLabelByName('business/selling'); if (!bizSelling) { bizSelling = GmailApp.createLabel('business/selling'); } Logger.log('Moving selling -> business/selling'); var threads = sellingLabel.getThreads(0, 500); var total = 0; while (threads.length > 0) { bizSelling.addToThreads(threads); sellingLabel.removeFromThreads(threads); total += threads.length; Utilities.sleep(1000); threads = sellingLabel.getThreads(0, 500); } Logger.log('Moved ' + total + ' threads to business/selling'); sellingLabel.deleteLabel(); } // Delete contract label (threads already have business label) var contractLabel = GmailApp.getUserLabelByName('business/contract'); if (!contractLabel) { contractLabel = GmailApp.getUserLabelByName('contract'); } if (contractLabel) { Logger.log('Removing contract label from all threads...'); var threads = contractLabel.getThreads(0, 500); var total = 0; while (threads.length > 0) { contractLabel.removeFromThreads(threads); total += threads.length; Utilities.sleep(1000); threads = contractLabel.getThreads(0, 500); } contractLabel.deleteLabel(); Logger.log('Deleted contract label (' + total + ' threads unaffected)'); } } // ─── STEP 5: Delete unused labels ──────────────────────────────────────────── function deleteUnusedLabels() { var toDelete = [ 'Notes', '[Mailbox]', 'Later', 'To Buy', 'To Read', 'To Watch', 'Cold Email', 'Oak Ridge Moms', 'music', ]; toDelete.forEach(function(name) { var label = GmailApp.getUserLabelByName(name); if (!label) { Logger.log('Not found (already gone?): ' + name); return; } var threads = label.getThreads(0, 500); var total = 0; while (threads.length > 0) { label.removeFromThreads(threads); total += threads.length; Utilities.sleep(500); threads = label.getThreads(0, 500); } if (total > 0) { Logger.log('Removed label from ' + total + ' threads: ' + name); } label.deleteLabel(); Logger.log('Deleted: ' + name); }); } // ─── RUN ALL ────────────────────────────────────────────────────────────────── function runAll() { Logger.log('=== Starting Gmail label cleanup ==='); Logger.log('--- Step 1: Merging labels ---'); mergeLabels(); Logger.log('--- Step 2: Archiving cvlp ---'); archiveCvlp(); Logger.log('--- Step 3: Merging purchases into Receipt ---'); mergePurchasesIntoReceipt(); Logger.log('--- Step 4: Restructuring business labels ---'); restructureBusinessLabels(); Logger.log('--- Step 5: Deleting unused labels ---'); deleteUnusedLabels(); Logger.log('=== Done! ==='); }