Gmail Script - label.getUnreadCount() issue - google-apps-script

Google Apps Script
https://developers.google.com/apps-script/reference/gmail/gmail-label
getUnreadCount()
// log the number of unread threads labeled with MyLabel
var label = GmailApp.getUserLabelByName("MyLabel");
Logger.log(label.getUnreadCount());
Gets the number of unread threads tagged with this label.
When i tried the sample code provided, it return a different unread value.
From the email, it shows 17 unread but the log file shows 12.
Any ideas?

I tested this script thoroughly and found that although, it gets a count of the emails marked with the label from the Inbox, however, it will not count the emails marked which are in maybe some other folder but have the same label. So if you have 17 unread emails with a label (assuming it like your question) "MyLabel", then my guess is 12 of those are in the Inbox but 5 of those have skipped/been moved from the Inbox and hence are not being counted by the function.
However, one of the work-arounds is to use:
var threads = label.getThreads();
and move add of all of these to Inbox while keeping these files marked with your label. Now, if you count, your function should return 17. But ideally you shouldn't have to do that, so I would suggest that you also file it as a defect here and make use of the work-around in the meanwhile.

Related

Is deleting Gmail thread specific enough to delete only messages from a specific email?

I made the following algorithm in Google Script which deletes all mails from a specific adress from all folders:
function deleteForever() {
var labelName
labelName="some_mail_address"
var threads = GmailApp.search("in: all from:" + labelName);
for (var i = 0; i < threads.length; i++) {
Gmail.Users.Messages.remove("me", threads[i].getId());
}
}
Is this safe to use for my gmail account? (With a trigger such that it runs every minute)
In particular, I am wondering whether a thread can contain multiple mails, and whether this can result in deleting mails which are not from the unwanted sender.
Also, I have seen "in: anywhere" on some webpages. Is this different from "in: all"?
Short answer: No.
It's not "safe" because:
the thread id is the same id for the first thread message but the first message might be from other sender.
the message will be deleted permanently
running a script every minute might consume the daily quota so you might first getting error messages and lately the trigger might be disabled due to having so many errors.
in:anywhere is not the same as in:all. The first will return threads labeled as spam and trash but the later doesn't.
Instead using the thread id, iterate over the thread messages to check the sender, if it matches then "delete" the message
Instead of using "remove" use "trash"
If you use "trash" instead of "remove" don't use "in:anywhere" otherwise the same message will be processed over an over until it's deleted permanently.
Instead of using a trigger scheduled to run every minute, run it every ten minutes or use a lower frequency if you plan to use other time driven triggers.
Related
Same thread id does not return the same message
Unthread or permanently delete individual gmail messages, without turning off threading

how to label and check only one message ( Gmail email) in Google Script?

I want my Google script to parse all emails within a label. But just once. The emails come from my bank. They store transaction details. Because I use thread conversation view I worry that the script will either - process one message more than once or miss a message in a case I mark the thread with a label let's say "done" once the email message was processed.
The transaction details are coming with the same subject, so all of them will be part of one thread.
I do not want to store message ID or something like outside Google Script.
Could you think of any solution?
I was thinking that I can add email ID to the thread but the I would end up with too many labels.
I might be able to use Gmail API as suggested here
GmailApp - Add label to specific message, not the thread and
Google Apps Script - Changing label of individual email in Gmail
but I do not know how to check if a particular message got specific label.
You can query for messages containing a certain label with Gmail.Users.Messages.list specifying the id of a label
Sample:
var starredMessages = Gmail.Users.Messages.list("me", {"labelIds":"Label_981438383934575828"}).messages;
var starredIds = [];
starredMessages.forEach(function(message){starredIds.push(message.id)});
Once you have this, you can retrieve all inbox messages, push their ids into an array and filter them to remove the already labelled messages from the array:
var AllIds = [];
var allMessages = GmailApp.getInboxThreads().forEach(function(thread){thread.getMessages().forEach(function(message){AllIds.push(message.getId())})});
var filteredIds= AllIds.filter(function (id) { return starredIds.indexOf(id) == -1;});
As a result, you obtain an array with message Ids that do not have the specified label (yet).
Now, do with those messages what you desire, e.g. in a loop and subsequently add the label to them with e.g.
filteredIds.forEach(function(id){Gmail.Users.Messages.modify({'addLabelIds': [LabelId]}, 'me', id)});
UPDATE
Another way to retrieve messages without the label is with the query parameter q.
Thereby, the query should be specified as -label:MY LABEL :
var NotStarredMessages = Gmail.Users.Messages.list("me", {"q":"-label:MY LABEL"}).messages;
HOWEVER, KEEP IN MIND THAT IF ONE MESSAGE OF A THREAD HAS THE LABEL, THIS SECOND METHOD WILL NOT EXCLUDE ALL MESSAGES OF THE CORRESPONDING THREAD FROM THE LIST.
So in your case the second method is not recommended.

GmailApp.getMessagesForThreads() returns too many messages

I want to return a list of all email subjects received at a specified day, at my Gmail account. If there is more than one message with the same subject, I want to have a number of how many there are. This is what I did:
var emailThreads = GmailApp.search("subject:<partial_subject> after:2020/8/30 before:2020/8/31");
var messages = GmailApp.getMessagesForThreads(emailThreads);
This returns "an array of arrays of messages, where each item in the outer array corresponds to a thread and the inner array contains the messages in that thread".
I try to access data I need like this:
for (i = 0; i < messages.length; i++) {
messages[i][0].getSubject() // a subject
messages[i].length // number of messages with the same subject
}
However, this returns more messages than is displayed in Gmail UI.
Here's what I've noticed:
it only happens to threads with more than one message
it doesn't happen to all threads with more than one message
every time a run my script for the same day, the result is the same
when I run my script for different days, the result is different even though the same emails were received
Considering that this code is very simple and I'm only using methods delivered by google, I assume I must have misunderstood something or Gmail is doing something weird with messages in threads.
Any ideas what could this be and how to work around it?
Edit:
I've noticed that there is a "Don't include chats" checkbox in gmail filter, which adds "-in:chats" into search query, but it didn't help either.
I also tried adding "in:inbox" to the query, but with no change in the result.
Explanation:
The reason you are getting too many messages is because your current
filter criteria does not query only emails but also hangout
messages or other threads rather than emails.
Use this to get the subjects of all emails:
var emailThreads = GmailApp.search("is:inbox after:2020/8/30 before:2020/8/31");
Solution:
This is how the full code would look like:
function myFunction() {
var emailThreads = GmailApp.search("is:inbox after:2020/8/30 before:2020/8/31");
var messages = GmailApp.getMessagesForThreads(emailThreads);
var messageArr = [];
for (i = 0; i < messages.length; i++) {
Logger.log(messages[i][0].getSubject()) // a subject
Logger.log(messages[i].length) // number of messages with the same subject
}
messages.forEach(m=>{
messageArr.push({
subject: m[0].getSubject(),
num_messages:m.length
})});
}
I also created for you a json array messageArr which contains all the
subject names and the number of message for each subject.
From the question
However, this returns more messages than is displayed in Gmail UI.
There might be some reasons for that
Messages in Trash and Spam are not displayend on the search results on the Gmail UI (unless you include in:anywhere, textually)
The UI is not showing all messages because the results might be paged and you missed that
After the receive/import/deletion of a large number of messages there is a noticible delay on getting them displayed on the UI, so even if it looks that you reached the last search results page, wait some minutes and regresh the Gmail webpage.
getMessagesForThreads return messages that might not be shown on the Gmail UI search results because they were sent to the Spam or Trash.
To correctly compare the results from the Gmail UI with the results of this method, on the Gmail UI include in:anywhere as part of your search. The complete search statement will look something like this:
in:anywhere subject:<partial_subject> after:2020/8/30 before:2020/8/31
As mentionend on the first part of this answer, you might have to refresh the Gmail webpage several times to be sure that there aren't messages recently made available through the web UI.
Related
How to keep gmail threads from coming back
Resources
Search operators you can use with Gmail

Google Apps Script - GMail to Google Sheets - Get Oldest Unread Email in Thread's .csv Attachment

First off: JavaScript novice. Any help/direction you could provide would be greatly appreciated.
I have a new business case in which a GMail box is going to receive an e-mail 4 times a day with the same subject line, but with a new .csv attachment each time. I've created the label within GMail, and it is attaching successfully to each email. I need to be able to use Apps Script to only process the oldest unread e-mail. The part to parse the .csv is already tested/successful/completed. However, each time I run it, it's looping through all the files, and processing them again.
Here is the current code for getting information from the GMail Box
// GMail Details
var gmailLabel = ('_Projects/ProjectLabel');
var label = GmailApp.getUserLabelByName(gmailLabel);
var unreadCount = label.getUnreadCount();
var gmailThreads = GmailApp.getUserLabelByName(gmailLabel).getThreads();
Logger.log(label.getUnreadCount());
for (var i = 0; i < gmailThreads.length; i++) {
Logger.log(gmailThreads[i].getFirstMessageSubject());
}
}
The log does show that there are 2 unread threads correctly, and does display the subject line in the logger. However, within the gmailThreads array, I can only see the object numbers for the threads. How could I get object numbers for each of the e-mails belonging to those threads? This would be the e-mail that I would need to parse the .csv attachment first, then mark as read (or change the label of) within the loop.
Thanks again for looking!
To get the IDs of the first messages in a given Gmail Thread, you need to call getMessages() to retrieve all the messages, and then access the first message in the resulting array, with [0]:
var firstMessage = thread.getMessages()[0];
Then you can do a number of things with this GmailMessage, such as retrieve its ID (.getId()) or attachments (.getAttachments()).

Google Apps Script to count number of emails received yesterday, that has certain label, then save # daily to spreadsheet

Basically what the title says, but I want to:
1) Automatically count the number of emails received to my gmail account, that has a certain label on it
2) Count once everyday, even if zero
3) And report daily to a Google Spreasheet
4) So I can make a monthly report like such:
Date / #
Date / #
Date / #
.
.
.
Total for October / #
Average per day / #
I'm sure this is piece of cake using Google Script for script gurus, but I have no clue. Please teach me!
Open a new Untitled spreadsheet and go to Tools -> open Script editor and paste the code given below.
function CountEmail()
{
var label = GmailApp.getUserLabelByName("LabelName");
var labelname = label.getName();
var mails = label.getThreads();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var date = new Date();
sheet.appendRow([labelname,date,mails.length]);
}
To run the script daily you will need to set a project trigger in the app script.For that follow the steps given below:
Resources -> Current Project's Trigger -> Add trigger -> Time driven -> Hour timer -> select the time when you want the script to run.
The total number of emails and the average emails/day can be calculated in the spreadsheet itself by just using the Sum() function.
Referencing the code Suyash Gandhi has posted (citing it here in case it gets removed so there is no confusion).
NOTE: not my code!!! Credit to Suyash Gandhi
function CountEmail()
{
var label = GmailApp.getUserLabelByName("LabelName");
var labelname = label.getName();
var mails = label.getThreads();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var date = new Date();
sheet.appendRow([labelname,date,mails.length]);
}
NOTE: not my code!!! Credit to Suyash Gandhi
See the picture below
What you see here are 2 threads, 1 email in the bottom one, 3 emails in the top one and 1 draft in the top one. That given code will return a 2 here. If you wish to count all 4 (or 5 if you want the draft) you will need to use Gmail API (see reference here).
I have a script that gets all emails (every message) for a specific time period and outputs the receive date, sender, recipient and title to a spreadsheet. This is the code that actually fetches the emails. The rest of the code is mostly creating files, generating the query string and reset the script if it runs too close to 6 minutes.
queriedMessages =
Gmail.Users.Messages.list(userInfo.mail,
{
'q': queryString,
'pageToken': execProperties.nextPageId
});
userInfo.mail is the email address you are fetching the emails from. This is simply written like this because the script can be run with any account
queryString is a string that is used to search for emails and is exactly the same as you use in the gmail search box. So you would have label:labelname
pageToken is a code of the page of the search (basically what is needed when you click the next page button in gmail). It is returned as part of this function so you would be able to access it from queriedMessages.nextPageToken. So if you get more than 1 page, then you will need it to access the rest of the messages.
Also, keep in mind that you are getting all the messages fitting the query, so if you do this daily, you may want to include a trigger. Also, keep in mind that functions firing from triggers ignore your timezone (known bug), but you can figure out how to create a query that works for only 1 day fairly easily. Personally I just grab +1 day on the beginning and the end and just filter those messages out.