/** The name of the Gmail Label that is to be checked for purging */ const LABELS_TO_DELETE = [ "auto_delete" ]; /** Labels to never delete */ const LABELS_TO_NOT_DELETE = [ "do_not_delete" ] const TRIGGER_NAME = "dailyDeleteGmail"; /** Purge messages in the above label automatically after how many days? */ const DELETE_AFTER_DAYS = "30"; /** Maximum number of threads to process per run */ const PAGE_SIZE = 300; /** If number of threads exceeds page size, resume job after X mins (max execution time is 6 mins) */ const RESUME_FREQUENCY = 15; /** what hour to run the daily trigger at */ const DAILY_RUN_HOUR = 10; /** * Creates an initial trigger to run the project, * subsequent runs are automatically created */ function Install() { // First run 1 minute after install console.log("In Install, creating trigger to run after 1 minute"); ScriptApp.newTrigger(TRIGGER_NAME) .timeBased() .after(1000*60*1) .create(); } /** * Removes any lingering triggers. * During normal execution new triggers are created, * To stop/remove this project, run this manually */ function Uninstall() { const triggers = ScriptApp.getProjectTriggers(); console.log(`Found ${triggers.length} triggers to remove`); triggers.forEach(trigger => { ScriptApp.deleteTrigger(trigger); }) } function dailyDeleteGmail(ev) { console.log(`Running for ${Session.getActiveUser().getEmail() ?? "unknown"}`); const labels = LABELS_TO_DELETE.map(label => `label:${label}`).join(" OR "); const not_labels = LABELS_TO_NOT_DELETE.map(label => `label:${label}`).join(" OR "); const search = `(${labels}) NOT (${not_labels}) older_than:${DELETE_AFTER_DAYS}d`; console.log(`search query: ${search}`); try { Uninstall(); const threads = GmailApp.search(search, 0, PAGE_SIZE); if (threads.length === PAGE_SIZE) { const followupTime = 1000*60*RESUME_FREQUENCY; console.log(`More to do, scheduling a followup trigger to run after ${RESUME_FREQUENCY} minutes`); ScriptApp.newTrigger(TRIGGER_NAME) .timeBased() .after(followupTime) .create(); } else { console.log("Caught up, creating a followup trigger for tomorrow."); const nextRunTime = new Date(); nextRunTime.setDate(nextRunTime.getDate() + 1); nextRunTime.setHours(DAILY_RUN_HOUR); ScriptApp.newTrigger(TRIGGER_NAME) .timeBased() .at(nextRunTime) .create(); } console.log("Processing " + threads.length + " threads..."); const age = new Date(); age.setDate(age.getDate() - DELETE_AFTER_DAYS); let deleted = 0; threads.forEach(thread => { if (thread.getLastMessageDate() < age) { thread.moveToTrash(); deleted += thread.getMessageCount(); } else { const messages = GmailApp.getMessagesForThread(thread); messages.forEach(email => { if (email.getDate() < age) { email.moveToTrash(); deleted++ } }) } }) console.log(`Run completed and moved ${deleted} mails to trash.`) } catch (e) { console.error(e); } }