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();
}
}
}
@Beginneronhunt
Copy link

Thanks for sharing this code and really like your video on Youtube.
Kindly share some tips and video for learning Automation testing.

@mohmdshbbr
Copy link

Hi,
My code is running only twice and doesn't trigger again after 2 mins. May I know what can be done?

Thank you.

chrome_4NjUtKWpfI

@sat2493
Copy link

sat2493 commented Oct 26, 2020

Thank you for sharing this code! :)

@blackstatic42
Copy link

Is their somehow to make it skip by labeled messages as well? Any insight would be greatly appreciated.

@aaronsomek
Copy link

I noticed that the script was picking up important and starred emails. Perhaps Gmail has updated their label parameters.
In line 76 I changed in:inbox -in:starred -in:important to -in:sent -is:starred -is:important
This searches ALL my mail - even archived, and doesn't grab any starred or important threads.

@loeasy68
Copy link

Thanks for sharing this code and really like your video on Youtube. Kindly share some tips and video for learning Automation testing.

I agree

@jacendvs
Copy link

jacendvs commented Oct 30, 2021

I searched for something like this because the search parameter "older_than" was not working. After I completed the script setup, the script was not working, I removed the parameter "older_than" and the script started running the Purge More automatically, the way it should.

This is unfortunate, and I dont know how to get around this problem.

edit: actually, the script might not be running automatically. :sigh:

update:

It is running .... but with the fact that I cant search "older_than" or something... im stuck.

image

@mmck345
Copy link

mmck345 commented Nov 24, 2021

Thanks for sharing the code and blog with the detailed video! 👍

@mmck345
Copy link

mmck345 commented Nov 25, 2021

image

Does anyone have any idea why this is happening?

@el-el22
Copy link

el-el22 commented May 19, 2022

Hi Ben,

Do you have a google app script that gets the unregistered emails in my Gmail inbox and extract the email address and its content and generate it to a text file or to a google spreadsheet automatically.

For example, 123@XYZ.com is an unregistered email in my gmail and this email contains the following content 112233445566. And the generated Text file for example should be like:

123@XYZ.com 112233445566

Ben, is it possible for me to do this, I would really appreciate your help on this.

My email: el.el86@outlook.com

Best regards,

@JacobTr97
Copy link

Hi, My code is running only twice and doesn't trigger again after 2 mins. May I know what can be done?

Thank you.

chrome_4NjUtKWpfI

Same problem... Anyone have a solution for this? Would be greatly appreciated.

@jtlarson
Copy link

Ben--thanks for this!

@blackstatic42

Is their somehow to make it skip by labeled messages as well? Any insight would be greatly appreciated.

I think every message in gmail is 'labeled' with at least a folder label, so omitting them would be effectively omitting ALL messages. You could probably skip specific labels like this

Add your label list near the top like this:
// Purge messages with these labels: var LABELS_TO_SAVE = [ "mailinglist", "Updates", "Social", "Promotions" ];

Then change line 76 (starts with 'var search') to this:
var search = "(-label:" + LABELS_TO_SAVE.join(" OR -label:") + ") in:inbox -in:starred -in:important older_than:" + DELETE_AFTER_DAYS + 'd'

You can also make this a list of labels to delete--just rename the var to "LABELS_TO_DELETE" in both places for clarity, and remove the "-" before both 'label:' entries.

@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