Skip to content

Instantly share code, notes, and snippets.

@benbjurstrom
Last active September 10, 2024 10:16
Show Gist options
  • Save benbjurstrom/00cdfdb24e39c59c124e812d5effa39a to your computer and use it in GitHub Desktop.
Save benbjurstrom/00cdfdb24e39c59c124e812d5effa39a to your computer and use it in GitHub Desktop.
PurgeOldEmails

PurgeOldEmails

A Google Apps Script script to automatically delete unarchived mail after 7 days that hasn't been starred or marked as important

Quick Start

  1. Backup your emails using Google Takeout.
  2. Load this script into a new Google Apps Script project.
  3. Execute the setPurgeTrigger() function to set a trigger that will call the purge() function every day.

A detailed blog post with more information can be found at https://benbjurstrom.com/purge-email

Acknowledgements

Thanks to this gist by jamesramsay for getting me started in the right direction.

/*
|--------------------------------------------------------------------------
| PurgeOldEmails
|--------------------------------------------------------------------------
| https://gist.github.com/benbjurstrom/00cdfdb24e39c59c124e812d5effa39a
|
*/
// Purge messages automatically after how many days?
var DELETE_AFTER_DAYS = 7
// Maximum number of message threads to process per run.
var PAGE_SIZE = 150
/**
* Create a trigger that executes the purge function every day.
* Execute this function to install the script.
*/
function setPurgeTrigger() {
ScriptApp
.newTrigger('purge')
.timeBased()
.everyDays(1)
.create()
}
/**
* Create a trigger that executes the purgeMore function two minutes from now
*/
function setPurgeMoreTrigger(){
ScriptApp.newTrigger('purgeMore')
.timeBased()
.at(new Date((new Date()).getTime() + 1000 * 60 * 2))
.create()
}
/**
* Deletes all triggers that call the purgeMore function.
*/
function removePurgeMoreTriggers(){
var triggers = ScriptApp.getProjectTriggers()
for (var i = 0; i < triggers.length; i++) {
var trigger = triggers[i]
if(trigger.getHandlerFunction() === 'purgeMore'){
ScriptApp.deleteTrigger(trigger)
}
}
}
/**
* Deletes all of the project's triggers
* Execute this function to unintstall the script.
*/
function removeAllTriggers() {
var triggers = ScriptApp.getProjectTriggers()
for (var i = 0; i < triggers.length; i++) {
ScriptApp.deleteTrigger(triggers[i])
}
}
/**
* Wrapper for the purge function
*/
function purgeMore() {
purge()
}
/**
* Deletes any emails from the inbox that are more then 7 days old
* and not starred or marked as important.
*/
function purge() {
removePurgeMoreTriggers()
var search = 'in:inbox -in:starred -in:important older_than:' + DELETE_AFTER_DAYS + 'd'
var threads = GmailApp.search(search, 0, PAGE_SIZE)
if (threads.length === PAGE_SIZE) {
console.log('PAGE_SIZE exceeded. Setting a trigger to call the purgeMore function in 2 minutes.')
setPurgeMoreTrigger()
}
console.log('Processing ' + threads.length + ' threads...')
var cutoff = new Date()
cutoff.setDate(cutoff.getDate() - DELETE_AFTER_DAYS)
// For each thread matching our search
for (var i = 0; i < threads.length; i++) {
var thread = threads[i]
// Only delete if the newest message in the thread is older then DELETE_AFTER_DAYS
if (thread.getLastMessageDate() < cutoff) {
thread.moveToTrash();
}
}
}
@vedanta28
Copy link

@jtlarson Is the script in the video working as intended? or we have to make some changes?

@Heady23
Copy link

Heady23 commented May 6, 2024

@jtlarson Is the script in the video working as intended? or we have to make some changes?

I am a newbie this so just created a time based Trigger to run the "purge" function. It ran but processed 0 threads.....still trying to figure out how to run it in the background. I also deployed it but have no idea what that does.

@jtlarson
Copy link

jtlarson commented May 6, 2024

@jtlarson Is the script in the video working as intended? or we have to make some changes?

@vedanta28 I assume it should work as posted, but here's my modified version that only deletes messages with specific labels I don't want to retain:

Edited: updated the description of what my modified search does, and removed the commented-out original search line

/*
|--------------------------------------------------------------------------
| PurgeOldEmails 
|--------------------------------------------------------------------------
| https://gist.github.com/benbjurstrom/00cdfdb24e39c59c124e812d5effa39a
|
*/

// Purge messages automatically after how many days?
var DELETE_AFTER_DAYS = 180

// Purge messages with these labels:
var LABELS_TO_DELETE = [
  "maillist",
  "Updates",
  "Social",
  "Promotions"
];

// Maximum number of message threads to process per run. 
var PAGE_SIZE = 150

/**
 * Create a trigger that executes the purge function every day.
 * Execute this function to install the script.
 */
function setPurgeTrigger() {
  ScriptApp
    .newTrigger('purge')
    .timeBased()
    .everyDays(1)
    .create()
}

/**
 * Create a trigger that executes the purgeMore function two minutes from now
 */
function setPurgeMoreTrigger(){
  ScriptApp.newTrigger('purgeMore')
  .timeBased()
  .at(new Date((new Date()).getTime() + 1000 * 60 * 2))
  .create()
}

/**
 * Deletes all triggers that call the purgeMore function.
 */
function removePurgeMoreTriggers(){
  var triggers = ScriptApp.getProjectTriggers()
  for (var i = 0; i < triggers.length; i++) {
    var trigger = triggers[i]
    if(trigger.getHandlerFunction() === 'purgeMore'){
      ScriptApp.deleteTrigger(trigger)
    }
  }
}

/**
 * Deletes all of the project's triggers
 * Execute this function to unintstall the script.
 */
function removeAllTriggers() {
  var triggers = ScriptApp.getProjectTriggers()
  for (var i = 0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i])
  }
}

/**
 * Wrapper for the purge function
 */
function purgeMore() {
  purge()
}


/**
 * Deletes emails from the "LABELS_TO_DELETE" variable that are older than the DELETE_AFTER_DAYS variable setting
 */
function purge() {
  removePurgeMoreTriggers()
  
  var search = "(label:" + LABELS_TO_DELETE.join(" OR label:") + ") older_than:" + DELETE_AFTER_DAYS + 'd'

  var threads = GmailApp.search(search, 0, PAGE_SIZE)
  
  if (threads.length === PAGE_SIZE) {
    console.log('PAGE_SIZE exceeded. Setting a trigger to call the purgeMore function in 2 minutes.')
    setPurgeMoreTrigger()
  }
  
  console.log('Processing ' + threads.length + ' threads...')
  
  var cutoff = new Date()
  cutoff.setDate(cutoff.getDate() - DELETE_AFTER_DAYS)
  
  // For each thread matching our search
  for (var i = 0; i < threads.length; i++) {
    var thread = threads[i]
    
    // Only delete if the newest message in the thread is older then DELETE_AFTER_DAYS
    if (thread.getLastMessageDate() < cutoff) {
      thread.moveToTrash();
    }
  }
}

@jtlarson
Copy link

jtlarson commented May 6, 2024

I am a newbie this so just created a time based Trigger to run the "purge" function. It ran but processed 0 threads.....still trying to figure out how to run it in the background. I also deployed it but have no idea what that does.

@Heady23 "processed 0 threads" just means the conditions in your var 'search' didn't fit any messages in your account. The original script example only fits messages in the inbox old than 'DELETE_AFTER_DAYS' (7 days) by default, so perhaps you have your messages in alternative folder labels? You can consult my modified version in the reply before this for another search example.

Make sure the 'purge' function is working when run manually in the editor first, then the trigger should work as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment