Google Apps Script - Gmail, delete forever e-mails in trash with specific label
Asked Answered
H

7

19

I'm trying to make a script that automatically deletes e-mails from a certain sender immediately and permanently, as Gmail only allows for a filter which sends an e-mail to trash for 30 days. Please do not suggest that the default filter is enough, as for my situation, it is vital that I do not know that I was sent an e-mail from this sender.

My current script looks like this:

function deleteForever(labelName) {
    var threads = GmailApp.search("in:trash label:" + labelName);
    for (var i = 0; i < threads.length; i++) {
      threads[i].moveToTrash(); // Where I would need a delete forever trigger
    }
};

However, I have been unable to figure out a way to use a GmailThread and to delete it permanently as there does not exist a function for this purpose. I was looking to see if there was a way I could finish the task using JavaScript, but have been unable figure out a method.

Does anyone have an idea how I can set these e-mails to delete themselves permanently when received?

Hamm answered 14/4, 2013 at 2:15 Comment(0)
C
12

It is not possible in GmailApp, by design, to permanently delete an email.

But you can use the advanced service Gmail, as written in the other answers here

Casias answered 14/4, 2013 at 4:46 Comment(3)
As I feared. Thank you for confirming.Hamm
Once it was the right answer but since we have the advanced services it is possible to remove an email.Vastah
Yep Edo's right, it's entirely possible to permanently and immediately delete emails using the Gmail Advanced Service now. See developers.google.com/apps-script/guides/services/advanced for how to enable an advanced service. See developers.google.com/apps-script/advanced/gmail for more details about the Gmail Advanced Service. And check out Daniel Bultas' script for the piece of code that will remove messages (Gmail.Users.Messages.remove).Mcguigan
G
21

@karan's answer already points to the solution which worked for me, but being inexperienced / not-a-professional-developer, it took me a little work to translate it into a working solution to the original question. Here's a concise description of the steps I used to perform this task:

  1. Create the following function in my script:

    function deleteForever(userId, labelName) {
      var threads = GmailApp.search("in:trash label:" + labelName);
      for (var i = 0; i < threads.length; i++) {
        Gmail.Users.Messages.remove(userId, threads[i].getId());
      }
    }
    
  2. To enable advanced services for this script, locate Resources on the menu, and select Advanced Google services...

  3. Enable Gmail API on the list.

  4. Before selecting OK, click on the Google Developers Console link. Search for gmail, and enable the service there as well.

  5. Done, select OK; the function should now work. (Comment: as mentioned in the link @karan provided, one can use "me" for userID, or alternatively provide one's Gmail address: "<address>@gmail.com".)

(Steps to enable advanced services for my script are based on Google's guide here.)

Gastroenterology answered 13/6, 2016 at 22:5 Comment(6)
Here is a link to Google App Scripts, where you'll need to be in order to perform the steps above. Just click that link, then click the Start Scripting button, and you'll be able to perform steps easily.Uranometry
@Bryce Larson I see that you suggested to change Messages into Threads. Have you tested the script that way? If so, and you can comment on the advantage of doing that, I'll be happy to accept. (FWIW it's been working for me the way it's currently written for the past year.)Gastroenterology
I would also recommend changing to threads Gmail.Users.Threads.remove. GmailApp.search returns an array of threads per link. In this case, I believe threads are being removed rather than messages. In my case, I was getting the following error (API call to gmail.users.messages.delete failed with error: Not Found) before realizing that I was passing a thread ID to the Gmail.Users.Messages.remove function.Parts
2022 UPDATE: with the new editor, just click on Services on the left side and select GMail API. After that the above code worked just fineTezel
@Shlomo: That is incorrect. Gmail class is only accessible after the Service has been added to the Google Apps script project (Steps 2-5 in OP's post). Permanent deletion as per OP's post still works as of this writing.Disbud
@AshutoshJindal You're right, thanks for the info. I deleted my previous comment so as not to misleadPaiz
C
12

It is not possible in GmailApp, by design, to permanently delete an email.

But you can use the advanced service Gmail, as written in the other answers here

Casias answered 14/4, 2013 at 4:46 Comment(3)
As I feared. Thank you for confirming.Hamm
Once it was the right answer but since we have the advanced services it is possible to remove an email.Vastah
Yep Edo's right, it's entirely possible to permanently and immediately delete emails using the Gmail Advanced Service now. See developers.google.com/apps-script/guides/services/advanced for how to enable an advanced service. See developers.google.com/apps-script/advanced/gmail for more details about the Gmail Advanced Service. And check out Daniel Bultas' script for the piece of code that will remove messages (Gmail.Users.Messages.remove).Mcguigan
C
9

This script works for Google Apps Script. You have to just connect and auth services together.

function myFunction() {

  var labelName = "deleteForever"

  var threads = GmailApp.search("in:trash label:" + labelName);
  for (var i = 0; i < threads.length; i++) { 
    Gmail.Users.Messages.remove('me', threads[i].getId());
  }
}
Customary answered 13/11, 2016 at 11:21 Comment(3)
how to do this in bulk?Educable
It won't work anymore, the Gmail class no longer exists (and its replacement - GmailApp has no such method)Paiz
@Shlomo: That is incorrect. Gmail class is only accessible after the Service has been added to the Google Apps script project (Steps 2-5 in https://mcmap.net/q/630972/-google-apps-script-gmail-delete-forever-e-mails-in-trash-with-specific-label). Permanent deletion as per OP's post still works as of this writing.Disbud
F
5

If it helps someone, it can be done using the advanced services.

https://developers.google.com/gmail/api/v1/reference/users/messages/delete

The method in advanced services is

Gmail.Users.Messages.remove(userId, id)

Fordone answered 24/12, 2015 at 13:25 Comment(1)
It's nice to know about this, but this is more a comment than an answer as long as it doesn't explain how to use that method in the original question; what lines should be added / changed? E.g., should the line in the loop be replaced with Gmail.Users.Messages.remove(me, threads[i].getId());?Gastroenterology
D
1

This is more of a supporting comment to @JonathanY's https://mcmap.net/q/630972/-google-apps-script-gmail-delete-forever-e-mails-in-trash-with-specific-label :

**** Pre-requisite****

Note that being able to permanently delete messages or threads relies on Gmail class which is only accessible once that Service has been added to the project like so:

Step 1: Click on + in Services

Click On Services

(Note that there are no Services currently listed here)

Step 2:

Scroll down to the Gmail Service, select it and then click Add

Add Gmail Service

Step 3:

Finally, confirm that the service now appears in the list of Services:

enter image description here


Sample Code

To re-iterate, the following sample code needs to be in a project which has the Gmail service added to it as above.

To test this code, choose any message in Bin and label it with deleteForever (create this label if needed).

Leave dryRun as true and execute the function. The output will show which threads and/or messages will get deleted.

In actual usage, if you are planning to delete entire threads via Gmail.Users.Threads.remove then you wouldn't use checkMessagesForContentBeforeDeleting since the latter checks individual message bodies for content before deleting them (i.e. will only delete individual messages matching 'body content has the specified regex' criteria) and not whole threads.

var dryRun = true;

String.prototype.indexOfRegex = function (regex) {
  var match = this.match(regex);
  return match ? this.indexOf(match[0]) : -1;
}

function testDeleteForever() {
  var labelName = "deleteForever"
  var badContentFilterForMessages = ".*08:29.*"
  var gmailSearchString = `in:trash label:${labelName}`

  var threads = GmailApp.search(gmailSearchString);
  const n = threads.length;
  if (n <= 0) {
    Logger.log("No threads matching search string \"%s\"", gmailSearchString);
    return
  } else {
    Logger.log("Found %s threads matching action **%s**", n, gmailSearchString);
  }

  for (var i = 0; i < threads.length; i++) {
    var thread = threads[i];
    Logger.log(`\t Processing Thread#${i} [ID: ${thread.getId()}]: [First message subject: ${thread.getFirstMessageSubject()}]`)

    if (!dryRun) {
      Logger.log(`\t \t Will delete forever the THREAD: ${thread.getFirstMessageSubject()}`)
      Gmail.Users.Threads.remove('me', thread.getId())
    } else {
      Logger.log(`\t \t **DRY RUN** would have deleted forever the THREAD: ${thread.getFirstMessageSubject()}`)
    }

    checkMessagesForContentBeforeDeleting(thread, badContentFilterForMessages);
  }
}

function checkMessagesForContentBeforeDeleting(thread, badContentFilterForMessages){
    Logger.log(`\t \t Checking messages in ${thread.getId()} for content matching "${badContentFilterForMessages}" before deleting forever`)
    var messages = thread.getMessages();
    Logger.log(`\t \t Number of messages in ${thread.getId()}: ${messages.length} `)

    for (var j = 0; j < messages.length; j++) {
      var message = messages[j];
      Logger.log(`\t \t \t Checking Message#${j}: [Subject: ${message.getSubject()}]`)

      var body = message.getRawContent();
      var containsSearchString = body.indexOfRegex(badContentFilterForMessages) > -1;

      if (containsSearchString) {
        Logger.log(`\t \t \t \t Message#${j} is a match! Will be deleted!`)
        if (!dryRun) {
          Logger.log(`\t \t \t \t Will delete forever the MESSAGE: ${message.getSubject()}`)
          Gmail.Users.Messages.remove('me', message.getId());
        } else {
          Logger.log(`\t \t \t \t **DRY RUN** would have deleted forever.`)
          Gmail.Users.Messages.remove('me', message.getId());
        }
      } else {
        Logger.log(`\t \t \t \t NOT deleting the MESSAGE (content does not match)`)
      }
    }
}

Disbud answered 2/6, 2023 at 16:48 Comment(0)
P
1

Better performance in the case of multiple messages, by using batchDelete instead of multiple calls to the remove method:

function deleteForever (labelName, emailAccount = 'me') {
    const threads = GmailApp.search('in:trash label:' + labelName);
    const messages = threads.map(thread => thread.getMessages()).flat();
    const messagesIds = messages.map(message => message.getId());
    if (!threads.length) {
        return console.log('not emails to delete');
    }
    Gmail.Users.Messages.batchDelete({ ids: messagesIds }, emailAccount);
    console.log(`${messages.length} messages in ${threads.length} threads deleted forever`);
}
// example call to function:
// deleteForever('labelName')

Note: before using the script, you need to enable the Gmail advanced service (from Google Guide):

Step 1: Click on + in Services

Click "+" On Services section: enter image description here

(Note that there are no Services currently listed here)

Step 2:

Scroll down to the Gmail Service, select it and then click Add

enter image description here

Step 3:

Finally, confirm that the service now appears in the list of Services:

enter image description here

Paiz answered 3/6, 2023 at 19:27 Comment(0)
C
0

try this

function delete_all_mail(){
var myspreadsheet = SpreadsheetApp.openById('1AG1fZ9BuS8***********');
var mysheet = myspreadsheet.getSheets()[0];
//0~500
var threads = GmailApp.getInboxThreads(0 , 500);
  for(var i = 0; i < threads.length; i++)
  {
   threads[i].moveToTrash();
  }
}
Cadmar answered 4/5, 2018 at 17:27 Comment(1)
It's not permanently deleted like the OP requestedPaiz

© 2022 - 2024 — McMap. All rights reserved.