Add Gmail label cleanup script for inbox-zero migration
This commit is contained in:
@@ -0,0 +1,235 @@
|
|||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
GmailApp.addLabelToThreads(threads, toLabel);
|
||||||
|
GmailApp.removeLabelFromThreads(threads, fromLabel);
|
||||||
|
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) {
|
||||||
|
GmailApp.addLabelToThreads(threads, newsletterLabel);
|
||||||
|
GmailApp.removeLabelFromThreads(threads, cvlpLabel);
|
||||||
|
GmailApp.moveThreadsToArchive(threads);
|
||||||
|
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) {
|
||||||
|
GmailApp.addLabelToThreads(threads, receiptLabel);
|
||||||
|
GmailApp.removeLabelFromThreads(threads, purchasesLabel);
|
||||||
|
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) {
|
||||||
|
GmailApp.addLabelToThreads(threads, donationsLabel);
|
||||||
|
GmailApp.removeLabelFromThreads(threads, bizDonations);
|
||||||
|
total += threads.length;
|
||||||
|
Utilities.sleep(1000);
|
||||||
|
threads = bizDonations.getThreads(0, 500);
|
||||||
|
}
|
||||||
|
Logger.log('Moved ' + total + ' threads to top-level donations');
|
||||||
|
bizDonations.deleteLabel();
|
||||||
|
} else {
|
||||||
|
// Try top-level donations label
|
||||||
|
Logger.log('business/donations not found - checking for top-level donations label');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
GmailApp.addLabelToThreads(threads, bizSelling);
|
||||||
|
GmailApp.removeLabelFromThreads(threads, sellingLabel);
|
||||||
|
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, just remove contract)
|
||||||
|
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) {
|
||||||
|
GmailApp.removeLabelFromThreads(threads, contractLabel);
|
||||||
|
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 count = label.getThreads(0, 1).length;
|
||||||
|
if (count > 0) {
|
||||||
|
Logger.log('WARNING: ' + name + ' still has threads - removing label from them first');
|
||||||
|
var threads = label.getThreads(0, 500);
|
||||||
|
while (threads.length > 0) {
|
||||||
|
GmailApp.removeLabelFromThreads(threads, label);
|
||||||
|
Utilities.sleep(500);
|
||||||
|
threads = label.getThreads(0, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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! ===');
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user