I have a google app script that collects information about Gmail messages and then pastes it into a google sheet. Trouble is it doesn't get ALL of the messages. It only picks up the first one of each thread. I feel like I am missing something to loop through each thread? Any suggestions?
function getMail(){
var myspreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = myspreadsheet.getSheetByName("Sheet3");
var start = 0;
var max = 99;
var count =0;
var row = mysheet.getLastRow()+1
var maxDate = mysheet.getRange("B1").getValue()
while(count < 4)
{
var threads = GmailApp.getInboxThreads(start , max);
var messages = GmailApp.getMessagesForThreads(threads);
var froms = [];
messages.get
for(var i = 0; i < threads.length; i++)
{
var msgDate = messages[i][0].getDate();
if(msgDate>maxDate){
froms.push([messages[i][0].getDate(),messages[i][0].getFrom(),messages[i][0].getSubject(),messages[i][0].getPlainBody()]);
}
}
if(froms.length>0){
mysheet.insertRows(2, froms.length)
mysheet.getRange(2,1,froms.length,4).setValues(froms);
}
start = start + 100;
count++;
}
}
Your current script is only grabbing messages[i][0], the first message in that group for the thread. Instead you need to loop through all of the messages using two for loops, as you can see in the script below I use messages[i][j].
function getMail() {
var mySpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mySheet = mySpreadsheet.getSheetByName("Sheet3");
var start = 0;
var max = 99;
var count = 0;
var maxDate = mySheet.getRange("B1").getValue();
while(count < 4) {
var threads = GmailApp.getInboxThreads(start, max);
var messages = GmailApp.getMessagesForThreads(threads);
var froms = [];
for(var i = 0; i < messages.length; i++) {
for(var j = 0; j < messages[i].length; j++) {
var msgDate = messages[i][j].getDate();
if(msgDate > maxDate) {
froms.push([msgDate,messages[i][j].getFrom(),messages[i][j].getSubject(),messages[i][j].getPlainBody()]);
}
}
}
if(froms.length > 0) {
mySheet.insertRows(2, froms.length);
mySheet.getRange(2, 1, froms.length, 4).setValues(froms);
}
start = start + 100;
count++;
}
}
Notable changes:
removed var rows because it wasn't used anywhere in the script.
changed first for loop to run for messages.length rather than
threads.
added another for loop to loop through every message in
messages[i].
you were getting messages[i][0].getDate() twice, so I just used the variable already defined for adding to the array.
minor grammatical/spacing changes for consistency across script.
Related
I have two codes, the first of which works and shows all attachments and the second shows only the first. "getAttachmentAndMessage" is used by several of my scripts so I need to have it in a separate function in order not to duplicate my configuration. Please help.
//this function get me all attachments
//this function is just an example of how I built my code below;
function searchEmailsData(){
var search = GmailApp.search('in:inbox newer_than:3d');
var threads = GmailApp.getMessagesForThreads(search);
for (var i = 0 ; i < threads.length; i++) {
var thread = threads[i];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
for (var k = 0; k < attachments.length; k++) {
var attachment = attachments[k];
Logger.log(attachment.getName());
}
}
}
}
//this functions get me only first attachment but I need all of them;
function searchEmailsData2(){
var search = GmailApp.search('in:inbox newer_than:3d');
var threads = GmailApp.getMessagesForThreads(search);
for (var i = 0 ; i < threads.length; i++) {
var thread = threads[i];
var obj = getAttachmentAndMessage(thread);
Logger.log(obj[1].getName())
}
}
function getAttachmentAndMessage(thread){
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
for (var k = 0; k < attachments.length; k++) {
var attachment = attachments[k];
var obj = [message, attachment];
return obj;
}
}
}
In order to return not the first attachment but rather all of them, you can modify the getAttachmentAndMessage() function as follows:
function getAttachmentAndMessage(thread) {
var results = [];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
var obj = {'message': message, 'attachments': attachments};
results.push(obj);
}
return results;
}
The above will return a list of objects, in which each objects contains a property message, and a property attachments (which is a list of attachments).
In order to return a list containing only the attachments in the thread, you can use the following variation of the code above:
function getAttachmentAndMessage(thread) {
var results = [];
for (var j = 0; j < thread.length; j++) {
var message = thread[j];
var attachments = message.getAttachments();
results = results.concat(attachments);
}
return results;
}
Your original code
In your original getAttachmentAndMessage() code, you were using a return statement inside of the for loop. That means that upon finding the first message (first iteration of the outer loop) and upon finding its first attachment (first iteration of the inner loop) the function would simply return one value, which is a list containing the first message and its first attachment.
I'm trying to create a script that will allow me to search for e-mails and their attachments by label name or no user labels. If in searchForLabels is more than one entry, the script does not work.
function searchLabels(){
//if there is more than one entry here, the script does not work
var searchForLabels =
[
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d' + searchForLabels);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
if (searchForLabels == 'has:nouserlabels'){
for (var i = 0 ; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
}
}
}
I made two little changes over your code. After testing it, it works as you requested.
The first one is on the var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]); line. I used the l iterator on the searchForLabels array. I used it because, reading the context of the line, it seems appropriate. This change will iterate over the tags. Forgive me if this was not your original intention.
The second change is required for the script to work. I commented out the if (searchForLabels == 'has:nouserlabels') {, because it will never be true if the searchForLabels array has more than one element. This is the error that you detected. Please, notice how the correspondent } is commented out too.
This is the final and working version of the script:
function searchLabels() {
//if there is more than one entry here, the script does not work
var searchForLabels = [
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
//if (searchForLabels == 'has:nouserlabels') {
for (var i = 0; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
//}
}
}
I want to add that you can use the Gmail API on Apps Script to accomplish your request in a simple way. In particular, you can use Users.messages LIST to list all the mails with your selected tags. There you can see an example (click over JavaScript) where a function is ready to make a search. To enable this API you shall follow the guide for activating advanced services. Do not hesitate to ask for more clarifications or any question.
function searchLabels() {
var searchForLabels = [
'has:nouserlabels',
'label:Test1'
];
for (var l = 0; l < searchForLabels.length; l++) {
var threads = GmailApp.search('in:inbox newer_than:4d ' + searchForLabels[l]);
var msgs = GmailApp.getMessagesForThreads(threads);
Logger.log(searchForLabels)
if (searchForLabels[l] == 'has:nouserlabels') { //limits emails to those without tag
//if (searchForLabels[l] == 'label:Test1') { //or to those with tag
for (var i = 0; i < msgs.length; i++) {
for (var j = 0; j < msgs[i].length; j++) {
var message = msgs[i][j];
var from = message.getFrom();
var subject = message.getSubject();
var getAttachments = message.getAttachments();
var body = message.getPlainBody();
var getTo = message.getTo();
Logger.log(subject)
for (var k = 0; k < getAttachments.length; k++) {
var attachment = getAttachments[k];
var content = attachment.getContentType();
//rest of my code
}
}
}
}
}
}
i have create this script:
function myTest() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var label = GmailApp.getUserLabelByName("Label1");
var threads = label.getThreads();
var countMail = 0;
//get first message in first thread
for (var i = 0; i < threads.length; i++) {
var messages=threads[i].getMessages();
countMail = countMail + messages.length;
}
ss.getRange(1,1).setValue(countMail);
}
it runs nearly perfect. Here I get all eMails back which are connected with this treads (marked with Label1 or not).
Does anyone can share a simply script how I can count all eMails which are "realy" marked with the Label.
Thanks
Try this:
function labelMsgs(){
var labels = Gmail.Users.Labels.list("me").labels;
var lblId;
for (var i = 0; i < labels.length; i ++){
if (labels[i].name == "Label1"){
lblId = labels[i].id;
break;
}
}
var optionalArgs = {
"labelIds" : lblId,
"maxResults" : 200
}
var messages = Gmail.Users.Messages.list("me", optionalArgs).messages;
}
This method uses the Gmail API directly, for this you'll need to enable Google Advanced Services, it will return a list of all messages tagged with the "Label1" label. You can play around with maxResults and with the pageToken to see more results, but this is the general approach.
Im trying to save google groups emails into a spreadsheet but Im getting the 'maximum execution time' error. Any ideas?
function listGroupMembers() {
var GROUP_EMAIL = "prgg#googlegroups.com";
var group = GroupsApp.getGroupByEmail(GROUP_EMAIL);
var users = group.getUsers();
var sheet = SpreadsheetApp.create("Group Mail");
for (var i = 0; i < users.length; i++) {
sheet.appendRow([users[i]]);
}
}
What is probably taking much of the time is the appendRow() call.
you should build an array with all the values and write this at once in your sheet.
Code could be like this :
function listGroupMembers() {
var GROUP_EMAIL = "prgg#googlegroups.com";
var group = GroupsApp.getGroupByEmail(GROUP_EMAIL);
var users = group.getUsers();
var sheet = SpreadsheetApp.create("Group Mail");
var values = [];
for (var i = 0; i < users.length; i++) {
values.push([users[i]]);
}
sheet.getRange(1,1,values.length, values[0].length).setValues(values);
}
EDIT
I didn't check the begining of your initial code, SpreadsheetApp.create("Group Mail"); returns a spreadsheet, not a sheet... that's why it fails on getRange.
Since it's not clear what you wanted to get exactly I assumed you wanted to create a new Sheet with that name if it doesn't exist.
The appropriate code would be like this :
function listGroupMembers() {
var GROUP_EMAIL = "prgg#googlegroups.com";
var group = GroupsApp.getGroupByEmail(GROUP_EMAIL);
var users = group.getUsers();
if(SpreadsheetApp.getActive().getSheetByName("Group Mail") == null){
var sheet = SpreadsheetApp.getActive().insertSheet("Group Mail");
}else{
var sheet = SpreadsheetApp.getActive().getSheetByName("Group Mail");
}
var values = [];
for (var i = 0; i < users.length; i++) {
values.push([users[i]]);
}
sheet.getRange(1,1,values.length, values[0].length).setValues(values);
}
I would like to scan all my emails in Gmail, and extract only the mailer-daemon messages (to identify rejected email addresses).
When I'm using these methods, None of the mailer-daemon messages are returned - only the "valid" messages:
var ss = SpreadsheetApp.openById("1e29xgV1UU63SJEwF2aWQpWpcXMxyiylwEMGbuvbwADw");
var sheet = ss.getSheetByName("Email Addresses");
var row = 1;
sheet.getRange(row,1).setValue("Email Addresses");
row++;
var threads = GmailApp.getInboxThreads();
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
for (var j = 0 ; j < messages.length; j++) {
var txtBody = messages[i].getPlainBody();
var txtSender = messages[i].getFrom();
sheet.getRange(row,1).setValue(txtBody);
sheet.getRange(row,2).setValue(txtSender);
row++;
}
}
What can I use to process the mailer-daemon messages from the Mail Delivery Subsystem?
Thanks!
You should match the FROM: field of the message, something like:
var txtSender = messages[i].getFrom();
if (txtSender.indexOf("mailer-daemon") !== -1) {
// Log the entry in the spreadsheet
}
You should be filtering threads from the query itself, its more optimal (also paged).
function getBounced() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Bounced Addresses");
var row = 1;
var regExp = /[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}/i // "i" is for case insensitive
var threads = GmailApp.search('from:"mailer-daemon" subject:(failure|undeliverable)', 0, 50);
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
for (var j = 0 ; j < messages.length; j++) {
var txtSubject = messages[j].getSubject();
var txtBody = messages[j].getBody();
var bouncedEmail = regExp.exec(txtBody)[0];
sheet.getRange(row,1).setValue(bouncedEmail);
sheet.getRange(row,2).setValue(txtSubject);
row++;
}
}
}
I also added a little code to extract the bounced/rejected email with a RegExp