0

I'm trying to clear an account of emails on Gmail. Doing it on the Gmail UI leads to errors probably because there are over 500k emails.

So I've started doing it with the Apps Script website https://script.google.com/ based on some scripts I have found and it works fine until around five or six minutes when it times out.

Right now the way I have it setup (code below), it runs fine but when it hits isTimeUp it just exits. The newTrigger is never running.

function myFunction() {
  console.log("myFunction")
  var batchSize = 100
  var today = new Date();
  while (true) {

    var threads = GmailApp.search('before:2020/05/20');
    for (j = 0; j < threads.length; j += batchSize) {
      console.log("Batch " + j)
      GmailApp.moveThreadsToTrash(threads.slice(j, j + batchSize));

    }
    if (isTimeUp(today)) {
      console.log("time up")
      var triggers = ScriptApp.getProjectTriggers();
      try {
        ScriptApp.deleteTrigger(triggers[0]);
      } catch (e) {

      }
      ScriptApp.newTrigger("myFunction")
        .timeBased()
        .after(1000)
        .create();
      break;
    }
  }
}


function isTimeUp(today) {
  var now = new Date();
  return now.getTime() - today.getTime() > 300000;

}

This is the log I see:

4:46:05 PM  Notice  Execution started
4:46:05 PM  Info    myFunction
4:46:06 PM  Info    Batch 0
4:46:19 PM  Info    Batch 100
4:46:32 PM  Info    Batch 200
4:46:45 PM  Info    Batch 300
4:46:58 PM  Info    Batch 400
4:47:11 PM  Info    Batch 0
4:47:23 PM  Info    Batch 100
4:47:37 PM  Info    Batch 200
4:47:49 PM  Info    Batch 300
4:48:01 PM  Info    Batch 400
4:48:14 PM  Info    Batch 0
4:48:28 PM  Info    Batch 100
4:48:40 PM  Info    Batch 200
4:48:53 PM  Info    Batch 300
4:49:05 PM  Info    Batch 400
4:49:18 PM  Info    Batch 0
4:49:31 PM  Info    Batch 100
4:49:43 PM  Info    Batch 200
4:49:58 PM  Info    Batch 300
4:50:18 PM  Info    Batch 400
4:50:33 PM  Info    Batch 0
4:50:46 PM  Info    Batch 100
4:50:59 PM  Info    Batch 200
4:51:12 PM  Info    Batch 300
4:51:26 PM  Info    Batch 400
4:51:39 PM  Info    time up
4:51:39 PM  Notice  Execution completed

What am I doing wrong?

Rubén
  • 34,714
  • 9
  • 70
  • 166
casolorz
  • 8,486
  • 19
  • 93
  • 200

2 Answers2

1

Taking a second look to the code and based on the comments, the problem looks to be related to have consumed the daily trigger execution time quota, but there is no error message because the catch (e) code block is empty. In order to make the script log the error message, replace

      } catch (e) {

      }

by

      } catch (e) {
        console.error(e.message, e.stack);
      }

Based on my own experience using after method of the Google Apps Script trigger builder, I think that 1000 milliseconds is a too small value. Try using something equal or greater than 60000 milliseconds (1 minute).


Considering that you want to process a very large number of messages, please bear in mind that:

  1. Google Apps Script has daily trigger total runtime quota, at the time of writing this the quotas are 90 minutes for free accounts, 6 hours for Google Workspace accounts. For the current quotas please checkout https://developers.google.com/apps-script/guides/services/quotas.
  2. GmailApp.search(query) might fail when there are too many threads (ref. search(query)). Instead of this method use search(query, start, max).

Also please bear in mind that Google Apps Script services are slow. If you found the use of GmailApp be too slow,

  1. try increasing the batch size (up to 500)
  2. try using the Advanced Gmail Service

If you found that it is still too slow and that you are exceeding the quotas you might try to use the Gmail API through the Url Fetch Service (Class UrlFetchApp). For this you should create a Google Cloud Project and set a billing method.

If you prefer to keep using the GmailApp or the Gmail (Advanced Gmail Service), you might create time-driven triggers to run at specific time for several days to initiate your myFunction or run it manually until you find that all the corresponding threads were trashed.

Related

Rubén
  • 34,714
  • 9
  • 70
  • 166
  • When I tested my proposed modified script, even when `after(1000)` is used, it seems that the script is run after 1 minute. Couldn't the time-driven trigger with several seconds be used? – Tanaike May 22 '22 at 23:51
  • @Tanaike Thank very much for your reply. I haven't tried your proposed script or something similar (using a web app / versioned deployment to create a trigger using the after method). – Rubén May 22 '22 at 23:57
  • Thank you for replying. When I tested the time-driven trigger with the several seconds before, I thought that the trigger might have worked. But, I'm not sure whether that was probably my mistake. So, I thought that if you have the information, I would like to know it. About installing the time-driven trigger by the script running with the trigger, it seems that it's a bug of the V8 runtime. – Tanaike May 23 '22 at 00:05
  • @Tanaike : [Gmail bulk Emails manipulation](https://webapps.stackexchange.com/q/160232/88163) is Q/A from Web Applications. At the time that I posted my answer there (Nov 2021), creating a trigger using the after method with 60000 as parameter worked fine for me. – Rubén May 23 '22 at 01:06
  • Thank you for the information. I would like to test it. When I tested with `after(1000)` (in this case, it seems 1 minute.), I confirmed the bug. So I proposed the workaround. But, from your reply, if the bug has been removed by `after(60000)`, I think that it is a good news. – Tanaike May 23 '22 at 01:17
  • 1
    First, I tested the script less than `after(60000)`. The trigger is installed by 1st run. When the script is run by the time-driven trigger, the trigger occurs "Disabled". It seems that after 2nd run, the script is not run. In the case of more than `after(60000)`, I confirmed that after the trigger could be reinstalled without "Disabled" error. I thought that this might be related to `after(1000)` becomes 1 minute. By this test, I understand that in this case, my proposed workaround is not required to be used. So, I would like to delete it. Thank you for your information. – Tanaike May 23 '22 at 01:31
  • I changed it to `60000` and had the same issue, just says `execution completed` at the end. – casolorz May 23 '22 at 14:06
  • @casolorz Add `console.log(threads.length);` after `var threads = GmailApp.search('before:2020/05/20');` to be sure that there are threads to be trashed. – Rubén May 23 '22 at 14:51
  • There should be a lot of threads. I have over 500k emails to delete. I am now however getting this error `Exception: Service invoked too many times for one day: premium gmail.` – casolorz May 23 '22 at 15:44
  • @casolorz The message is self-explanatory, anyway, I updated my answer. – Rubén May 23 '22 at 15:53
  • Yeah I know, I'm just mentioning it so it is clear that I can't really test more changes today. It is a bit odd though, I didn't run it that many times today, the other day I ran it a lot more. – casolorz May 23 '22 at 16:49
  • Just read your update, the batch can't be increased I don't think. I remember it giving me an error about 100 being the limit. – casolorz May 23 '22 at 16:51
  • @casolorz Regarding the batch size, I suggest you to post a new question including a [mcve] (this implies to include the textual error message) – Rubén May 28 '22 at 03:09
1

Try this:

function removeAllThreads() {
  Gmail.Users.Threads.list("me").threads.map(t => t.id).forEach(id => Gmail.Users.Threads.remove("me",id))
}
Cooper
  • 59,616
  • 6
  • 23
  • 54