Get Gmail categories - google-apps-script

I used to have a working apps script that deleted old promotional emails in my Gmail account.
It used the code
var label = GmailApp.getUserLabelByName("Promotions");
to get the label and then it iterated through label.getThreads() to decide whether each thread was old enough to delete.
However, Google have now changed Gmail so the auto categorisations are now under the Categories section in the UI, rather than within the list of labels so the above now returns null.
How can I fix my code to retrieve the Promotions category? I have tried Categories/Promotions too but it also comes up null.

Gmail categories can easily be searched.
Here is a small code that looks for every promotion mail. The result is an array of threads, you can add Label to each of them so that your old script will be happy again ;-)
var threads = GmailApp.search('category:promotions');// check the category Gmail added to the thread
documentation here

Here is a script I use to delete old promotional emails as well as some other categories and custom labels.
function auto_delete_email(){
delete_Label ("Cameras",30);
delete_Label ("Travel",365);
delete_Category ("Social",90);
delete_Category ("Finance",365*3);
delete_Category ("Forums",90);
delete_Category ("Promos",365*3);
}
function delete_Label(mailLabel,delayDays) {
var label = GmailApp.getUserLabelByName(mailLabel);
if (!label) {return false;}
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays);
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
if (threads[i].getLastMessageDate()<maxDate){
threads[i].moveToTrash();
}
}
function delete_Category(mailCategory,delayDays) {
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays);
var threads = GmailApp.search('category:' + mailCategory);
for (var i = 0; i < threads.length; i++) {
if (threads[i].getLastMessageDate()<maxDate){
threads[i].moveToTrash();
}
}
}

You can also expand the search criteria to use (d, m, y) like "older_than:1y" which mimics the search box functionality in the Gmail app. This may be helpful as I've had significant issues getting the date comparison to work smoothly.
For example:
function delete_old_Category() {
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()- 180);
var threads = GmailApp.search("category:promos older_than:6m",0, 100);
for (var i = 0; i < threads.length; i++) {
threads[i].moveToTrash(); {
}
}
}

Related

Move emails with labels to trash after 1 day fail

When I use the script below, sourced from the web, it only works for one (Cam1) of the two labels . The labels within Gmail are associated with the emails and they are older than 1 day.
Why is this script only working as written on one label?
Im new at this so please keep it simple! Thanks
function oldEmailDeletion() {
//Age of email threads that will be deleted (i.e. older_than: # days)
var daysAgo = 1;
//Expiration date variable
var expirationDate = new Date();
//Set the older_than date. Any email older than this date will be deleted
expirationDate.setDate(expirationDate.getDate()-daysAgo);
//Labels associated with emails to be included in deletion
var labels = [
'Cam1',
'Cam2'
];
//Loop through each email label found in the "labels" variable array
for(var i = 0; i < labels.length; i++){
//Retrieve label information based on value in "labels" variable array
var label = GmailApp.getUserLabelByName(labels[i].toString());
//Access all email threads associated with the retrieved label
var emailThreads = label.getThreads(); //getThreads(###,###) if a specific range of email threads to retrieve
//Loop through each email thread set to "emailThreads" variable
for(var j = 0; j < emailThreads.length; j++){
//If an email thread is older than the expiration date, then delete
if(emailThreads[j].getLastMessageDate() < expirationDate){
emailThreads[j].moveToTrash();
}
}
}
}
Try it this way:
function oldEmailDeletion() {
var dt=new Date();
var exp=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()-1).valueOf();
var labels=['Cam1','Cam2'];
for(var i=0;i<labels.length;i++){
var label=GmailApp.getUserLabelByName(labels[i].toString());
var emailThreads=label.getThreads();
for(var j=0;j<emailThreads.length;j++){
if(emailThreads[j].getLastMessageDate().valueOf()<exp){
emailThreads[j].moveToTrash();
}
}
}
}
If you actually want to delete the messages delete the message older than one day then this approach should work for you. And you will need to Enable the Gmail API.
function oldEmailDeletion() {
const dt=new Date();
const exp=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()-1).valueOf();
const labels=['Cam1','Cam2'];
var idA=[];
for(var i=0;i<labels.length;i++){
var label=GmailApp.getUserLabelByName(labels[i].toString());
var emailThreads=label.getThreads();
for(var j=0;j<emailThreads.length;j++){
if(emailThreads[j].getMessageCount()>0) {
var msgs=emailThreads[j].getMessages();
for(var k=0;i<msgs.length;j++) {
var msg=msgs[k];
if(new Date(msg.getDate()).valuefOf()<exp) {
idA.push(msg.getId());
}
}
}
}
}
if(idA.length>0) {
var request={"ids":idA};
Gmail.Users.Messages.batchDelete(request, "me");
}
}
If you just want to move them to the trash. Then this approach should work for you.
function oldEmailTrash() {
const dt=new Date();
const exp=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()-1).valueOf();
const labels=['Cam1','Cam2'];
var idA=[];
for(var i=0;i<labels.length;i++){
var label=GmailApp.getUserLabelByName(labels[i].toString());
var emailThreads=label.getThreads();
for(var j=0;j<emailThreads.length;j++){
if(emailThreads[j].getMessageCount()>0) {
var msgs=emailThreads[j].getMessages();
for(var k=0;i<msgs.length;j++) {
var msg=msgs[k];
if(new Date(msg.getDate()).valueOf()<exp) {
idA.push(msg.getId());
}
}
}
}
}
if(idA.length>0) {
idA.forEach(function(msg){msg.moveToTrash();});
}
}
Thanks Cooper. I tried for days but lacked the skills to debug your scripts. I found and modified the script below and it works.
First I created a new filter in gmail that labeled all cam emails 'Clean' then set the script below on a trigger. This was the only way I was able to achieve my goal.
Thanks again!
function gmailCleaningRobot() {
var delayDays = 1; // will only impact emails more than 24h old
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays); // what was the date at that time?
// creating an array containing all the search strings matching the emails we want to be treated automatically
var searches = [
'label:Clean older_than:1d' //with label clean and older than 1d
//'"is now available on Spotify" from:spotify is:unread', // Spotify new album notification
//'YOUR NEW SEARCH STRING HERE', // any other search string
//'YOUR NEW SEARCH STRING HERE', // any other search string
//'YOUR NEW SEARCH STRING HERE', // any other search string
//'YOUR NEW SEARCH STRING HERE' // any other search string
];
// creating an array containing all the threads matching the searches above
var threads = [];
for (var i = 0; i < searches.length; i++) {
var tmp_threads = GmailApp.search(searches[i], 0, 500); // I limit the search to 500 results but you can adjust this one
var threads = threads.concat(tmp_threads);
}
// we archive all the threads if they're older than the time limit we set in delayDays
for (var i = 0; i < threads.length; i++) {
if (threads[i].getLastMessageDate()<maxDate)
{
threads[i].moveToTrash();
}
}
}

How to filter out all emails that came from a mailing list in Gmail

Is there a way to filter out all emails that came from a mailing list within Gmail or Google Apps Script using a search query. I know you can filter out a specific email address using list:info#example.com. But I want a catch-all type of query or even a query to catch-all from a specific domain such as list:#example.com. However, this does not work. Any ideas? Any help is greatly appreciated, thank you!
This function will trash all messages from all inbox thread that are not in the list.
function emailFilter() {
var list=['a#company.com','b#company.com','c#company.com','d#company.com','e#company.com'];
var threads=GmailApp.getInboxThreads();
var token=null;
for(var i=0;i<threads.length;i++) {
if(threads[i].getMessageCount()) {
var messages=threads[i].getMessages();
for(var j=0;j<messages.length;j++) {
if(list.indexOf(messages[j].getFrom()==-1)) {
messages[j].moveToTrash();
}
}
}
}
}
I haven't tested it because I keep my inbox empty all of the time. You might want to replace 'moveToTrash()' to 'star()' for testing
What I could understand from your question and your comments, you need to filter the emails in a user's inbox that he has received, which don't only contain a certain label, but also a certain domain. If I understood well this code can help you:
function checkLabels() {
// Get the threads from the label you want
var label = GmailApp.getUserLabelByName("Label Test List");
var threadArr = label.getThreads();
// Init variable for later use
var emailDomain = '';
// Iterate over all the threads
for (var i = 0; i < threadArr.length; i++) {
// for each message in a thread, do something
threadArr[i].getMessages().forEach(function(message){
// Let's get the domains from the the users the messages were from
// example: list:#example.com -> Result: example.com
emailDomain = message.getFrom().split('<').pop().split('>')[0].split('#')[1];
// if emailDomain is equal to example.com, then do something
if(emailDomain === 'example.com'){
Logger.log(message.getFrom());
}
});
}
}
Using the Class GmailApp I got a certain label with the .getUserLabels() method and iterate through the threads thanks to the .getInboxThreads method. With a second loop and the .getMessages() you can get all the messages in a thread and for knowing the one who sent them, just use the .getFrom() method.
Docs
For more info check:
Gmail Service.
Class GmailMessage.
Class GmailThread.
So I was able to avoid replying to emails that come from a mailing list address by using the getRawContent() method and then searching that string for "Mailing-list:". So far the script is working like a charm.
function autoReply() {
var interval = 5; // if the script runs every 5 minutes; change otherwise
var date = new Date();
var day = date.getDay();
var hour = date.getHours();
var noReply = ["email1#example.com",
"email2#example.com"];
var replyMessage = "Hello!\n\nYou have reached me during non-business hours. I will respond by 9 AM next business day.\n\nIf you have any Compass.com related questions, check out Compass Academy! Learn about Compass' tools and get your questions answered at academy.compass.com.\n\nBest,\n\nShamir Wehbe";
var noReplyId = [];
if ([6,0].indexOf(day) > -1 || (hour < 9) || (hour >= 17)) {
var timeFrom = Math.floor(date.valueOf()/1000) - 60 * interval;
var threads = GmailApp.search('from:#example.com is:inbox after:' + timeFrom);
var label = GmailApp.getUserLabelByName("autoReplied");
var repliedThreads = GmailApp.search('label:autoReplied newer_than:4d');
// loop through emails from the last 4 days that have already been replied to
for (var i = 0; i < repliedThreads.length; i++) {
var repliedThreadsId = repliedThreads[i].getMessages()[0].getId();
noReplyId.push(repliedThreadsId);
}
for (var i = 0; i < threads.length; i++) {
var message = threads[i].getMessages()[0];
var messagesFrom = message.getFrom();
var email = messagesFrom.substring(messagesFrom.lastIndexOf("<") + 1, messagesFrom.lastIndexOf(">"));
var threadsId = message.getId();
var rawMessage = message.getRawContent();
var searchForList = rawMessage.search("Mailing-list:");
var searchForUnsubscribe = rawMessage.search("Unsubscribe now");
// if the message is unread, not on the no reply list, hasn't already been replied to, doesn't come from a mailing list, and not a marketing email then auto reply
if (message.isUnread() && noReply.indexOf(email) == -1 && noReplyId.indexOf(threadsId) == -1 && searchForList === -1 && searchForUnsubscribe === -1){
message.reply(replyMessage);
threads[i].addLabel(label);
}
}
}
}

Getting the body of individual emails from gmail to google sheets

I'm really new at using Google Apps Script, so if what I'm trying doesn't make sense, or just isn't possible please let me know.
Everyday I get several emails that look like the following:
Your Name: FirstName LastName
Phone Number: 555 867 5309
Email Address: FakeEmail#email.com
What do you need help with? Request someone makes.
I'm attempting to automatically send the body of these emails to a new line in a Google Sheet when they come in.
As of right now I have every email get the label "myLabel" when it comes in. I then run the following script, which is a slightly modified version of something I found here:
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
var label = GmailApp.getUserLabelByName("MyLabel");
var threads = label.getThreads();
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var msg = messages[j].getBody();
ss.appendRow([msg])
}
threads[i].removeLabel(label);
}
}
I'm attempting to run this code with a timer trigger every 15 minutes. The issue I've run into is that every time the code runs it pulls from every email in the thread. I would like it to just pull from the emails that are new since the last time it ran. Any advice would be greatly appreciated.
Why not mark the messages as read when you finish processing them? Here is a sample from one of my scripts.
var pendingEmailLabel = "MyLabel";
var threads = GmailApp.getUserLabelByName(pendingEmailLabel).getThreads();
for (var t = 0; t < threads.length; ++t) {
var thread = threads[t];
var messages = thread.getMessages();
for (var m = 0; m < messages.length; ++m) {
var message = messages[m];
if (message.isUnread()) {
// INSERT YOUR CODE HERE THAT TAKES ACTION ON THE MESSAGE
message.markRead();
}
}
}
}

Google gmail script that triggers on incoming email

I've been reading through gmail addons. They have contextual triggers that trigger when you open an email.
Is it possible to trigger a service when an email is received by me? Best I can find is unconditional but that only triggers when the email is opened.
You can't create a trigger for every email, however you can do something similar as described in this answer.
For example you can:
Set up a filter that puts a special label on incoming emails that you want to process.
Set up a reoccurring script that runs every 10 minutes, or even every minute. In the script, you can pull all of the emails that have the given label, and process them accordingly, removing the label when you are done.
function processEmails() {
var label = GmailApp.getUserLabelByName("Need To Process");
var threads = label.getThreads();
for (var i = threads.length - 1; i >= 0; i--) {
//Process them in the order received
threads[i].removeLabel(label).refresh();
}
}
You can then set this on a time based trigger to have it run as often as you would like.
If you want to keep track of the emails you have processed, you can create another "processed" label and add that to the message when you are done processing.
I had a little trouble with getting the labels right so I'm including code to log your labels. I modified user3312395's code also to add new label also.
Thanks for the original answer too!
function emailTrigger() {
var label = GmailApp.getUserLabelByName('Name of Label to Process');
var newLabel = GmailApp.getUserLabelByName('New Label Name');
if(label != null){
var threads = label.getThreads();
for (var i=0; i<threads.length; i++) {
//Process them in the order received
threads[i].removeLabel(label);
threads[i].addLabel(newLabel);
//run whatever else here
}
}
}
function getLabels(){
var labels = GmailApp.getUserLabels();
for(i=0; i<labels.length; i++){
Logger.log(labels[i].getName());
}
}
Yes, you can trigger a function for every new email!
Just use the search query newer_than:1h. Have your trigger run every 10 minutes for example. Then you will essentially be running logic for every new email (with up to 10 minutes delay, which is probably fine).
var TRIGGER_NAME = 'handleNewEmails'
// Maximum number of threads to process per run.
var PAGE_SIZE = 150
var INTERVAL = 10
function Install() {
// First run 2 mins after install
ScriptApp.newTrigger(TRIGGER_NAME)
.timeBased()
.at(new Date(new Date().getTime() + 1000 * 60 * 2))
.create()
// Run every 10 minutes there after
ScriptApp.newTrigger(TRIGGER_NAME)
.timeBased().everyMinutes(INTERVAL).create()
}
function Uninstall() {
var triggers = ScriptApp.getProjectTriggers()
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() === TRIGGER_NAME) ScriptApp.deleteTrigger(triggers[i])
}
}
function handleNewEmails() {
var threads = GmailApp.search("newer_than:1h", 0, PAGE_SIZE)
for (var i = 0; i < threads.length; i++) {
var thread = threads[i]
// Do something with the thread.
}
}
Actually, they have somewhat complex pub/sub service that requires setting up OAuth authentication. With this service you'll must be able to get push notifications. But I also think its easier to set up a trigger to run every 10 or even 1 minute.

Removing label from Gmail email after X days using Google Apps Script

I created a Google Apps Script Code.gs as follows to remove the Gmail label from every thread that is older than X days and labeled Y.
function archiveYThreads() {
// Every thread, older than two days, and labeled "Unread Feeds".
var threads = GmailApp.search('label:"Unread Feeds" older_than:2d');
for (var i = 0; i < threads.length; i++) {
threads[i].removeLabel("Unread Feeds");
}
}
According to the documentation, the function removeLabel exists. Alternatively, I found some sources that use deleteLabel. However, with both I get the error that both functions do not exist, after having set a time-based trigger:
Can anybody please help me detecting why the function does not work?
You have to supply an object of type GmailLabel as the argument to removeLabel() method. Try this snippet.
function archiveYThreads() {
var label = GmailApp.getUserLabelByName("Unread Feeds");
var threads = GmailApp.search('label:"Unread Feeds" older_than:2d');
for (var i = 0; i < threads.length; i++) {
threads[i].removeLabel(label);
}
}