Skip to content

Instantly share code, notes, and snippets.

@jordanlambrecht
Last active August 14, 2024 18:31
Show Gist options
  • Save jordanlambrecht/ec6ad36b5a48271fcbb4bb811512e477 to your computer and use it in GitHub Desktop.
Save jordanlambrecht/ec6ad36b5a48271fcbb4bb811512e477 to your computer and use it in GitHub Desktop.
Auto Delete / Archive Emails in Gmail
function autoDelete() {
console.log('Started autoDelete run.');
var delayDays = 2;
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays);
var label = GmailApp.getUserLabelByName("delete me");
var threads = label.getThreads();
if(threads.length > 0){
console.log('Found ' + threads.length + ' emails marked for deletion.');
var counter = 0;
try {
for(var i =0; i < threads.length; i++){
if (threads[i].getLastMessageDate()<maxDate){
Logger.log('deleted email: ' + threads[i].getFirstMessageSubject());
threads[i].markUnimportant();
threads[i].markRead();
threads[i].moveToTrash();
counter++;
}
}
console.log('Successfully moved ' + counter + 'emails to the trash.');
}
catch(e){
console.error('Could Not Start Run: ' + e);
}
}
else{
console.log('Found ' + threads.length + 'emails marked for deletion. Exiting.');
}
}
function autoArchive() {
console.log('Started autoArchive run.');
var delayDays = 2;
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays);
var label = GmailApp.getUserLabelByName("archive me");
var threads = label.getThreads();
if(threads.length > 0){
console.log('Found ' + threads.length + ' emails marked for archival.');
var counter = 0;
try {
for(var i =0; i < threads.length; i++){
if (threads[i].getLastMessageDate()<maxDate){
Logger.log('archived email: ' + threads[i].getFirstMessageSubject());
threads[i].markRead();
threads[i].moveToArchive();
threads[i].markUnimportant();
counter++;
}
}
console.log('Successfully archived ' + counter + 'emails.');
}
catch(e){
console.error('Could Not Start Run: ' + e);
}
}
else{
console.log('Found ' + threads.length + 'emails marked for archival. Exiting.');
}
}
@samsawyer
Copy link

samsawyer commented Feb 20, 2024

Thanks for a great first pass at this.

One issue with timing out might be that it's going to process every thread under a label every time — for deleted threads, that'll resolve after 30 days when they get permanently deleted out of trash, but for archived threads, the label will stay on them forever and they'll keep getting "rearchived".

Here's some refactored code that handles a couple of things:

  1. It'll process any sets of labels of the form Automate/DeleteAfterN or Automate/ArchiveAfterN, where N is the number of days after which to take action. So you can have multiple timing options without having to continually extend and modify the code.
  2. It'll remove the label on which it's acting, so in the archival case it won't have to keep re-processing the same threads over and over.

Ideas for extending this in the future:

  • add some batch processing so it will only attempt to deal with 500 messages per day or something until the inbox is under control
  • use GmailApp.search instead of getting all messages under a label, to apply the date filtering to the search instead of iterating through each message
  • switch to a paged query if there are still too many messages to process as search results
function gmailLabelAutoActions() {
  GmailApp.getUserLabels()
    .filter(label => label.getName().startsWith('Automate/'))
    .forEach(takeAction);
}

function takeAction(label) {
  const match = label.getName().match(/^Automate\/(Delete|Archive)After([0-9]+)$/);
  let count = 0;
  if (match) {
    let maxDate = new Date();
    maxDate.setDate(maxDate.getDate()-match[2]);
    label.getThreads()
      .filter(thread => thread.getLastMessageDate() < maxDate)
      .forEach(function (thread) {
        try {
          if (match[1] === 'Delete') {
            thread.moveToTrash();
          } else if (match[1] === 'Archive') {
            thread.moveToArchive();
          }
          count++;
          // If action has worked, then mark as unimportant and read
          thread.markUnimportant();
          thread.markRead();
          // Also remove label to prevent a thread from being reprocessed on next run
          thread.removeLabel(label);
        } catch (e) {
          Logger.log(`Could not process thread ${thread.getFirstMessageSubject()}: ${e}`);
        }

        if (count > 0) { 
          Logger.log(`For label ${match[1]}After${match[2]}: ${match[1]}d ${count} threads.`);
        }
      });
  }
}

@samsawyer
Copy link

And just saw in the forks that someone has already done a much more complete version of this:
https://gist.github.com/zoidy/38773c6f128d4dfb94e77df99af7c446

@jordanlambrecht
Copy link
Author

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