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
Related
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.
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()).
i will get a simply list with all eMail which a have in my inbox - with settings "Conversation view off". My script currently looks like this:
function getAllMail(){
var threads = GmailApp.search('in:inbox');
for (var i = 0 ; i < threads.length; i++) {
var id = threads[i].getId();
var message = GmailApp.getMessageById(id);
Logger.log(i);
}
}
So i get a list with the view: "Conversation view on".
Where is my thinkingfault?
As per my understanding, you need something that will list all the threads or conversation in your inbox. Try to manage threads.
The Gmail API uses Thread resources to group email replies
with their original message into a single conversation or thread. This
allows you to retrieve all messages in a conversation, in order,
making it easier to have context for a message or to refine search
results.
To retrieve threads, here is what you need.
Threads provide a simple way of retrieving messages in a conversation
in order. By listing a set of threads you can choose to group messages
by conversation and provide additional context. You can retrieve a
list of threads using the threads.list method, or retrieve a specific
thread with threads.get. You can also filter threads using the same
query parameters as for the Message resource. If any message in a
thread matches the query, that thread is returned in the result.
You can study the sample codes provided in the quickstart guides.
I get every day multiple automatic emails. One has the subject 'Daily Report' and one has the subject 'Daily Report details'. This is the script I was using, but once the emails started coming without chronological order, I sometimes catch the wrong one.
var threads = GmailApp.search('Daily Report') //search gmail with the given query(partial name using * as a wildcard to find anything in the current subject name).
var msgs = GmailApp.getMessagesForThreads(threads);
Is there a way to tell the search that I want the mail with exact subject 'Daily Report' and not the one with 'Daily Report Details'?
Thanks
Like #Pierre-Marie Richard and #Cooper mentioned, you can use the built-in Gmail search functions. Here are a list of the Gmail Search Functions, like #Cooper mentioned you may be best using something like:
var threads = GmailApp.search('subject:"Daily Report"-Details')
var msgs = GmailApp.getMessagesForThreads(threads);
The quotes ("") work as an exact match and the minus ('-') is to exclude a word.
If that still doesn't work let me know and I will look further into it.
Good Luck :)
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.