Skip to content

Instantly share code, notes, and snippets.

@r4um
Created August 15, 2025 05:23
Show Gist options
  • Save r4um/b167de83593a1214139afb4d6f1073b3 to your computer and use it in GitHub Desktop.
Save r4um/b167de83593a1214139afb4d6f1073b3 to your computer and use it in GitHub Desktop.
gmailCleanup
/ Cleanup emails.
//
// Create label ending with ;Na e.g. test;6m where Na is the age, N number 1,2,3.. etc a is d,m,w,y days,months,weekly,years
// Starred emails and emails label as indef are not deleted.
function gmailCleanup() {
function getDateBeforeToday(daysBefore) {
let today = new Date();
// Subtract the specified number of days
today.setDate(today.getDate() - daysBefore);
// Extract year, month, and day
let year = today.getFullYear();
let month = today.getMonth() + 1; // Months are zero-based
let day = today.getDate();
// Format month and day with leading zero if needed
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
// Return the formatted date
return `${year}/${month}/${day}`;
}
function translateDurationToDays(durationString) {
const match = durationString.match(/^(\d+)([dwmy])$/); // Extract number and unit using regex
if (!match) {
Logger.log(`Invalid duration string: ${durationString}`); // Log invalid strings
return null;
}
const value = parseInt(match[1]); // Parse the number
const unit = match[2]; // Get the unit (d, w, m, or y)
switch (unit) {
case 'd': // Days
return value;
case 'w': // Weeks, multiply by 7 days
return value * 7;
case 'm': // Months, approximate as 30 days per month
return value * 30;
case 'y': // Years, approximate as 365 days per year
return value * 365;
default:
Logger.log(`Unknown duration unit: ${unit}`);
return null;
}
}
function autoTrash(emailLabel, emailAge) {
const labelInDef = 'indef'
var threads;
var counter = 0;
var errors = 0;
var query = `label:${emailLabel} before:${getDateBeforeToday(emailAge)} -is:starred -label:${labelInDef}`
do {
Logger.log(`Searching with query ${query}`)
threads = GmailApp.search(query);
if (threads.length > 0) {
console.log('Found ' + threads.length + ' emails marked for deletion.');
try {
let nextProgressMark = 20;
for (var i = 0; i < threads.length; i++) {
try {
threads[i].moveToTrash();
counter++;
const currentPercentage = Math.floor(((i + 1) / threads.length) * 100);
if (currentPercentage >= nextProgressMark) {
Logger.log(`${nextProgressMark}% done this iteration. Total Processed ${counter} emails.`);
nextProgressMark += 20;
}
} catch (e) {
Logger.log(`Error moving thread to trash: ${threads[i].getFirstMessageSubject()}`);
}
}
} catch (e) {
errors++;
console.error(`Could Not Complete Run: ${e}`);
}
} else {
console.log('No emails marked for deletion. Exiting.');
}
} while (threads.length > 0);
console.log(`100% done. Moved ${counter} emails to the trash with ${errors} errors.`);
}
const labels = GmailApp.getUserLabels(); // Get all user-created labels
for (let i = 0; i < labels.length; i++) {
const label = labels[i];
const fullLabelName = label.getName();
let labelName = "";
let labelAge = "";
if (fullLabelName.includes(';')) {
const parts = fullLabelName.split(';');
labelName = parts[0].trim();
labelAge = parts[1].trim();
} else {
labelName = fullLabelName.trim();
labelAge = null;
}
if(labelAge) {
var labelDuration = translateDurationToDays(labelAge)
Logger.log(`Processing label ${fullLabelName} age ${labelAge} duration ${labelDuration} days.`)
autoTrash(fullLabelName, labelDuration)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment