Google Script star an e-mail - google-apps-script

I have a Google Script that processes the inbox looking for missing e-mails, and then sends out a summary of missing e-mails to my inbox:
var user;
var summary = "";
Logger.log("Checking last emails...");
user_list.forEach(function(user) {
var no_user_hit = true;
var query = 'from:'+user.user+' in:anywhere newer_than:' + user.deadline + 'd';
Logger.log(query);
var threads = GmailApp.search(query);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
if (check_subject(messages[j].getSubject(), user.subject)) {
no_user_hit = false;
}
}
}
if (no_user_hit == true) {
Logger.log("Sending email with summary...");
summary = summary + "No messages from "+user.user+" with subject "+user.subject+" for the last "+user.deadline+" days \n";
}
});
if (summary.length > 0) {
GmailApp.sendEmail(me, email_subject_to_your, summary);
}
}
I would like to star each e-mail being sent as a summary, I have tried starMessage(message) but that hasn't worked out.

The problem appears to be that the GmailApp.starMessage() accepts a GmailMessage object, but you are supplying the method with a string (as seen from the error message you are getting).
After you have sent your message, you will need to find it again in user's mailbox and then star it.
There is an answered question about retrieving a just-sent message for further processing - that might help with this.

Related

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);
}
}
}
}

permanently delete only one gmail message from a thread using a google script

I want to permanently delete a Gmail message inside a thread already in the trash.
I merged a few scripts around there, so I can delay and track emails. It works by saving a draft, then the script copy the draft into a new email, send it at the specified time and send the original draft to trash. The problem is that once in a while, the drafts that are in the trash are sent again (i haven't been able to figure out why yet)...
As a workaround, I was using the following code that that was originally posted here: delete forever emails 1:
function cleanUp() {
var threads = GmailApp.search("in:trash is:draft");
Logger.log(threads.length);
for (var i = 0; i < threads.length; i++) {
Logger.log(threads[i].getId());
Gmail.Users.Message.remove('me',threads[i].getId());
}
}
This was working fine, until a while ago. If the draft was inside a thread with more than 1 message, only the draft was deleted... I got now an error on line 6 that says: "Cannot call method "remove" of undefined".
In this post: delete forever emails 2, it is suggested to replace line 6 by
Gmail.Users.Threads.remove('me',threads[i].getId());
This dosn't get any errors, but if the draft is in a thread with more than one message, the whole thread is deleted instead of only the draft...
So, is there a way to get only the draft erased?
I tried calling the message id of the draft inside the thread and use the original line 6:
function cleanUp2() {
var threads = GmailApp.search("in:trash is:draft");
Logger.log(threads.length);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
Logger.log(messages.length);
for (var j = 0; j < messages.length; j++){
if (messages[j].isDraft()){
Logger.log('id msg: ' + messages[j].getId());
Gmail.Users.Message.remove('me',messages[j].getId());
}
}
}
}
But I got the same error, now on line 10...
I also tried using this function:
function deleteMessage(userId, messageId) {
var request = gapi.client.gmail.users.messages.delete({
'userId': userId,
'id': messageId
});
request.execute(
function(resp) { });
}
That you can find in the developers page of google: here. In the "try this API" section it works, but in my implementation i got an error on line 2 that says (translated from Spanish so i don't know if it will be exact): "a name (?) is missing behind (after?) operator "."" And if i copy the function in a separated tab, i can save it and the same error is showed...
Any help will be appreciated...
Regards,
i finally made it trough an http request:
function cleanUp2() {
var threads = GmailApp.search("in:trash is:draft");
Logger.log(threads.length);
var userId = 'xxxxx#gmail.com';
var options = {
'method' : 'delete',
'muteHttpExceptions': true
};
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
Logger.log(messages.length);
for (var j = 0; j < messages.length; j++){
if (messages[j].isDraft()){
Logger.log('id msg: ' + messages[j].getId());
var url = 'https://www.googleapis.com/gmail/v1/users/' + userId + '/messages/' + messages[j].getId();
var response = UrlFetchApp.fetch(url,options);
Logger.log(response);
}
}
}
}

Time-Driven trigger for mail forwarding

I'm attempting to test a script that I'm working on. The script is fine, it executes successfully when I trigger it manually. When I add a time driven script of every minute interval the scrips starts throwing an exception after couple of hrs .
Exception: Service invoked too many times for one day: gmail
I checked the daily quota of email and found that i still have mail quota left
var quota = MailApp.getRemainingDailyQuota();
Logger.log(quota);
Also I am able to receive the try catch email but the mails are not forwarded .
Is this because of the execution time quota associated with the trigger? Below is the code
function MailForward() {
try{
var glabel = createLabel_("Mail-Forwarded");
var rtm_email = 'abc#abc.com';
var from_email = Session.getActiveUser().getEmail();
var threads = GmailApp.search('in:inbox is:unread newer_than:1d');
var mForward = 0;
for (var i=0;i<threads.length;i++) {
var messages=threads[i].getMessages();
for (var m = 0; m < messages.length; m++){
if (messages[m].isUnread()){
mForward = 0;
var mlabels = threads[i].getLabels();
for (var j = 0; j < mlabels.length; j++) {
Logger.log(mlabels[j].getName());
if (mlabels[j].getName() === "Mail-Forwarded") {
mForward = 1;
}
}
if (mForward===0) {
// Logger.log(messages.length)
// Logger.log(messages[m].getFrom());
var from = messages[m].getFrom();
//Logger.log(messages[m].getDate());
var date = messages[m].getDate();
// Logger.log(messages[m].getSubject());
var subject = messages[m].getSubject();
// Logger.log(messages[m].getTo());
var to = messages[m].getTo();
var body = messages[m].getBody();
var attachment = messages[m].getAttachments();
var emailoptions = ("---------- Forwarded message ----------" +'<br>'+'From: '+from+ "<'" + from.replace(/^.+<([^>]+)>$/, "$1") +"'>"+'<br>'+ 'Date: '+date+'<br>'+ 'Subject: ' +subject+'<br>'+
'To: ' +to+ "<'" + to.replace(/^.+<([^>]+)>$/, "$1") +"'>"+'<br>'+'<br>'+'<br>');
messages[m].forward(rtm_email,{htmlBody: emailoptions + body , Attachment: attachment});
glabel.addToThread(threads[i]);
Logger.log(glabel.getName());
messages[m].markRead();
mForward = 1;
}
}
}
}
} catch(e) {
MailApp.sendEmail("abc#abc.com", "Exception found in Sript", e );
Logger.log(e);
}
}
You checked quota using MailApp.getRemainingDailyQuota(); not GmailApp. These are two different services.
The quota method returns only "the number of remaining emails a user can send for the rest of the day." But the limit you are hitting is the number of times you invoked the service, for whatever purpose.
You are using GmailApp a lot to access existing messages, not so much to send new ones. In particular, you are checking every message in every thread from today, and do it every minute. That's a lot of API calls: getMessages, isUnread, etc.
One way to reduce the number of API calls is to have more targeted search. The after: search parameter accepts Unix timestamp, which makes it possible to do the following:
function doSomethingWithNewEmail() {
var interval = 5; // if the script runs every 5 minutes; change to 1 if it runs every minute
var date = new Date();
var timeFrom = Math.floor(date.valueOf()/1000) - 60 * interval;
var threads = GmailApp.search('is:inbox after:' + timeFrom);
for (var i = 0; i < threads.length; i++) {
// do something
}
}
I successfully used the above approach with 5 minute interval. It may work with 1 minute too, since most of the time search will be the only API call made by the script.

Google Apps Script - Read data from gmail specific label returns messages from all labels

There are 2 user defined labels in my gmail named x & y. I need to retrieve the messages present in that specific label, but am getting the data from all the labels.
I need Msg body, label and date received and update it in spreadsheet
Following is my code:
var ulables = GmailApp.getUserLabels();
for(var x=0; x < ulables.length; x++){
var threads = GmailApp.getUserLabelByName(ulables[x].getName()).getThreads();
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
var label = ulables[x].getName();
for (var m = 0; m < messages.length; m++) {
var msg = messages[m].getBody();
var cmsg = convertHtmlToText(msg);
var subject = messages[m].getSubject();
if(subject == reqSub){
var recDate = Utilities.formatDate(messages[m].getDate(),"GMT","MM/dd/yyyy");
if(isDateInRange(recDate, startDate, endDate)){
var arr =[recDate,label,cmsg];
mailSheet.getRange(++lastRow, 1,1,3).setValues([arr]).activate();
}
}
}
}
}
Ex:- Label x has 10 emails
Label y has 10 emails
Inbox has 50 emails
For each label, am getting 60 emails which is the problem, but I expect 10,10,50 emails.
Have been struggling it from last 2 days, but not succeeded. Please help me. Thanks a ton in advance.
Please let me know the details, have been waiting for it from last one week. Is there any way getting messages without using threads?

google apps script and GmailApp: get just new messages

I'm trying to implement a simple google script that processes each message that is received by a Gmail user.
I've found an example that does something like this:
var threads = GmailApp.getInboxThreads();
for (var i=0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j=0; j < messages.length; j++) {
if (!messages[j].isUnread()) {
continue;
}
//process message
}
}
That is: I iterate through all messages in the inbox and search for the unread ones. This is very slow on just 1800 messages.
Ideally, I'm looking for a trigger that gets fired once each new message is received.
If there is no such thing, I would try to make use of this that I saw:
GmailApp.getMessageById(id)
Sorry for the late response but I just had the same type of problem and I ended up using GmailApp.search() ... hope this helps.
// find unread messages
var threads = GmailApp.search('is:unread');
....
WARNING
This call will fail when the size of all threads is too large for the system to handle. Where the thread size is unknown, and potentially very large, please use the 'paged' call, and specify ranges of the threads to retrieve in each call.
Take a look at GmailApp.search(query) and
GmailApp.search(query, start, max)
Unfortunately there in no trigger that fires for each recieved message. There is however a good workaround:
Set up a filter rule that assigns a special label, "ToBeProcessedByScript" as example, to all incoming messages. Since wildcards don't really work in Gmail filters use the to: field.
Run a time-triggered script that collects all new message threads with GmailApp.getUserLabelByName("ToBeProcessedByScript").getThreads(). Remove the special label just before processing the new messages.
you can use
GmailApp.getInboxThreads(0, 50);
to initialize the variable with first fifty mail.
I have extended the code with checking if the first message is really the one which is unread. If it is not it will check the next message and will continue untill it finds the unread message:
function getUnreadMails() {
var ureadMsgsCount = GmailApp.getInboxUnreadCount();
var threads;
var messages;
var k=1;
if(ureadMsgsCount>0)
{
threads = GmailApp.getInboxThreads(0, ureadMsgsCount);
for(var i=0; i<threads.length; i++)
{
if(threads[i].isInInbox())
{
messages = threads[i].getMessages();
for(var j=0; j<messages.length; j++)
{
while (messages[j].isUnread() === false)
{
threads=GmailApp.getInboxThreads(k, ureadMsgsCount);
messages = threads[i].getMessages();
k++;
}
Logger.log(messages[j].getSubject());
// process unread message
}
}
}
}
}
You can create a time trigger as djtek mentioned but instead of labeling all messages and then retrieve labeled messages, you can just get the number of the unread messages, and retrieve threads from 0 to the number of the unread messages, following a code that works for me:
function getUnreadMails() {
var ureadMsgsCount = GmailApp.getInboxUnreadCount()
if(ureadMsgsCount>0)
{
var threads = GmailApp.getInboxThreads(0, ureadMsgsCount);
for(var i=0; i<threads.length; i++)
{
if(threads[i].isInInbox())
{
var messages = threads[i].getMessages();
for(var j=0; j<messages.length; j++)
{
Logger.log(messages[j].getSubject());
// process unread message
}
}
}
}
}
function getUnreadMessages(threadLimit) {
function flatten(arr) { return [].concat.apply([], arr) }
var threadsWithUnreadMessages = GmailApp.search('is:unread', 0, threadLimit)
var messageCollection = threadsWithUnreadMessages.map(function(thread) {
return thread.getMessages()
})
var unreadMessages = flatten(messageCollection).filter(function(message) {
return message.isUnread()
})
return unreadMessages
}
getUnreadMessages(100)