getMessageById() slows down - google-apps-script

I am working on a script that works with e-mails and it needs to fetch the timestamp, sender, receiver and subject for an e-mail. The Google script project has several functions in separate script files so I won't be listing everything here, but essentially the main function performs a query and passes it on to a function that fetches data:
queriedMessages = Gmail.Users.Messages.list(authUsr.mail, {'q':query, 'pageToken':pageToken});
dataOutput_double(sSheet, queriedMessages.messages, queriedMessages.messages.length);
So this will send an object to the function dataOutput_double and the size of the array (if I try to get the size of the array inside the function that outputs data I get an error so that is why this is passed here). The function that outputs the data looks like this:
function dataOutput_double(sSheet, messageInfo, aLenght) {
var sheet = sSheet.getSheets()[0],
message,
dataArray = new Array(),
row = 2;
var i, dateCheck = new Date;
dateCheck.setDate(dateCheck.getDate()-1);
for (i=aLenght-1; i>=0; i--) {
message = GmailApp.getMessageById(messageInfo[i].id);
if (message.getDate().getDate() == dateCheck.getDate()) {
sheet.insertRowBefore(2);
sheet.getRange(row, 1).setValue(message.getDate());
sheet.getRange(row, 2).setValue(message.getFrom());
sheet.getRange(row, 3).setValue(message.getTo());
sheet.getRange(row, 4).setValue(message.getSubject());
}
}
return;
};
Some of this code will get removed as there are leftovers from other types of handling this.
The problem as I noticed is that some messages take a long time to get with the getMessageById() method (~ 4 seconds to be exact) and when the script is intended to work with ~1500 mails every day this makes it drag on for quite a while forcing google to stop the script as it takes too long.
Any ideas of how to go around this issue or is this just something that I have to live with?

Here is something I whipped up:
function processEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var messages = Gmail.Users.Messages.list('me', {maxResults:200, q:"newer_than:1d AND label:INBOX NOT label:PROCESSED"}).messages,
headers,
headersFields = ["Date","From","To","Subject"],
outputValue=[],thisRowValue = [],
message
if(messages.length > 0){
for(var i in messages){
message = Gmail.Users.Messages.get('me', messages[i].id);
Gmail.Users.Messages.modify( {addLabelIds:["Label_4"]},'me',messages[i].id);
headers = message.payload.headers
for(var ii in headers){
if(headersFields.indexOf(headers[ii].name) != -1){
thisRowValue.push(headers[ii].value);
}
}
outputValue.push(thisRowValue)
thisRowValue = [];
}
var range = ss.getRange(ss.getLastRow()+1, ss.getLastColumn()+1, outputValue.length, outputValue[0].length);
range.setValues(outputValue);
}
}
NOTE: This is intended to run as a trigger. This will batch the trigger call in 200 messages. You will need to add the label PROCESSED to gmail. Also on the line:
Gmail.Users.Messages.modify( {addLabelIds:["Label_4"]},'me',messages[i].id);
it shows Label_4. In my gmail account "PROCESSED" is my 4th custom label.

Related

Apps Script custom function working in script editor but not in Google Sheet custom function

I have built a simple custom function in Apps Script using URLFetchApp to get the follower count for TikTok accounts.
function tiktok_fans() {
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g);
var handle = '#charlidamelio';
var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText();
var match_text = raw_data.exec(web_content);
var result = (match_text[2]);
Logger.log(result)
return result
}
The Log comes back with the correct number for followers.
However, when I change the code to;
function tiktok_fans(handle) {
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g);
//var handle = '#charlidamelio';
var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText();
var match_text = raw_data.exec(web_content);
var result = (match_text[2]);
Logger.log(result)
return result
}
and use it in a spreadsheet for example =tiktok_fans(A1), where A1 has #charlidamelio I get an #ERROR response in the cell
TypeError: Cannot read property '2' of null (line 6).
Why does it work in the logs but not in the spreadsheet?
--additional info--
Still getting the same error after testing #Tanaike answer below, "TypeError: Cannot read property '2' of null (line 6)."
Have mapped out manually to see the error, each time the below runs, a different log returns "null". I believe this is to do with the ContentText size/in the cache. I have tried utilising Utilities.sleep() in between functions with no luck, I still get null's.
code
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g);
//tiktok urls
var qld = UrlFetchApp.fetch('https://www.tiktok.com/#thisisqueensland?lang=en').getContentText();
var nsw = UrlFetchApp.fetch('https://www.tiktok.com/#visitnsw?lang=en').getContentText();
var syd = UrlFetchApp.fetch('https://www.tiktok.com/#sydney?lang=en').getContentText();
var tas = UrlFetchApp.fetch('https://www.tiktok.com/#tasmania?lang=en').getContentText();
var nt = UrlFetchApp.fetch('https://www.tiktok.com/#ntaustralia?lang=en').getContentText();
var nz = UrlFetchApp.fetch('https://www.tiktok.com/#purenz?lang=en').getContentText();
var aus = UrlFetchApp.fetch('https://www.tiktok.com/#australia?lang=en').getContentText();
var vic = UrlFetchApp.fetch('https://www.tiktok.com/#visitmelbourne?lang=en').getContentText();
//find folowers with regex
var match_qld = raw_data.exec(qld);
var match_nsw = raw_data.exec(nsw);
var match_syd = raw_data.exec(syd);
var match_tas = raw_data.exec(tas);
var match_nt = raw_data.exec(nt);
var match_nz = raw_data.exec(nz);
var match_aus = raw_data.exec(aus);
var match_vic = raw_data.exec(vic);
Logger.log(match_qld);
Logger.log(match_nsw);
Logger.log(match_syd);
Logger.log(match_tas);
Logger.log(match_nt);
Logger.log(match_nz);
Logger.log(match_aus);
Logger.log(match_vic);
Issue:
From your situation, I remembered that the request of UrlFetchApp with the custom function is different from the request of UrlFetchApp with the script editor. So I thought that the reason for your issue might be related to this thread. https://stackoverflow.com/a/63024816 In your situation, your situation seems to be the opposite of this thread. But, it is considered that this issue is due to the specification of the site.
In order to check this difference, I checked the file size of the retrieved HTML data.
The file size of HTML data retrieved by UrlFetchApp executing with the script editor is 518k bytes.
The file size of HTML data retrieved by UrlFetchApp executing with the custom function is 9k bytes.
It seems that the request of UrlFetchApp executing with the custom function is the same as that of UrlFetchApp executing withWeb Apps. The data of 9k bytes are retrieved by using this.
From the above result, it is found that the retrieved HTML is different between the script editor and the custom function. Namely, the HTML data retrieved by the custom function doesn't include the regex of ("followerCount":)([0-9]+). By this, such an error occurs. I thought that this might be the reason for your issue.
Workaround:
When I tested your situation with Web Apps and triggers, the same issue occurs. By this, in the current stage, I thought that the method for automatically executing the script might not be able to be used. So, as a workaround, how about using a button and the custom menu? When the script is run by the button and the custom menu, the script works. It seems that this method is the same as that of the script editor.
The sample script is as follows.
Sample script:
Before you run the script, please set range. For example, please assign this function to a button on Spreadsheet. When you click the button, the script is run. In this sample, it supposes that the values like #charlidamelio are put to the column "A".
function sample() {
var range = "A2:A10"; // Please set the range of "handle".
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g);
var sheet = SpreadsheetApp.getActiveSheet();
var r = sheet.getRange(range);
var values = r.getValues();
var res = values.map(([handle]) => {
if (handle != "") {
var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText();
var match_text = raw_data.exec(web_content);
return [match_text[2]];
}
return [""];
});
r.offset(0, 1).setValues(res);
}
When this script is run, the values are retrieved from the URL and put to the column "B".
Note:
This is a simple script. So please modify it for your actual situation.
Reference:
Related thread.
UrlFetchApp request fails in Menu Functions but not in Custom Functions (connecting to external REST API)
Added:
About the following additional question,
whilst this works for 1 TikTok handle, when trying to run a list of multiple it fails each time, with the error TypeError: Cannot read property '2' of null. After doing some investigating and manually mapping out 8 handles, I can see that each time it runs, it returns "null" for one or more of the web_content variables. Is there a way to slow the script down/run each UrlFetchApp one at a time to ensure each returns content?
i've tried this and still getting an error. Have tried up to 10000ms. I've added some more detail to the original question, hope this makes sense as to the error. It is always in a different log that I get nulls, hence why I think it's a timing or cache issue.
In this case, how about the following sample script?
Sample script:
In this sample script, when the value cannot be retrieved from the URL, the value is tried to retrieve again as the retry. This sample script uses the 2 times as the retry. So when the value cannot be retrieved by 2 retries, the empty value is returned.
function sample() {
var range = "A2:A10"; // Please set the range of "handle".
var raw_data = new RegExp(/("followerCount":)([0-9]+)/g);
var sheet = SpreadsheetApp.getActiveSheet();
var r = sheet.getRange(range);
var values = r.getValues();
var res = values.map(([handle]) => {
if (handle != "") {
var web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText();
var match_text = raw_data.exec(web_content);
if (!match_text || match_text.length != 3) {
var retry = 2; // Number of retry.
for (var i = 0; i < retry; i++) {
Utilities.sleep(3000);
web_content = UrlFetchApp.fetch('https://www.tiktok.com/'+ handle + '?lang=en').getContentText();
match_text = raw_data.exec(web_content);
if (match_text || match_text.length == 3) break;
}
}
return [match_text && match_text.length == 3 ? match_text[2] : ""];
}
return [""];
});
r.offset(0, 1).setValues(res);
}
Please adjust the value of retry and Utilities.sleep(3000).
This works for me as a Custom Function:
function MYFUNK(n=2) {
const url = 'my website url'
const re = new RegExp(`<p id="un${n}.*\/p>`,'g')
const r = UrlFetchApp.fetch(url).getContentText();
const v = r.match(re);
Logger.log(v);
return v;
}
I used my own website and I have several paragraphs with ids from un1 to un7 and I'm taking the value of A1 for the only parameter. It returns the correct string each time I change it.

Using Google Apps Script to get responses from multiple forms and send an email once to each respondent

I have been puzzling this over for some time and have searched extensively, but found no solution.
I'm using Google Apps Script and I run events for a large organization and we have about 80 different registration Google Forms for these events. I want to get the registrant's email address and send them an email when they submit their form. This is easy to accomplish by setting up each individual form. Ideally, I would set up the onSubmit trigger for the form and then copy that form for each new event. However, it seems you cannot install a trigger programmatically without going to the form and running the script manually, and then authorize it. When a form is copied it also loses all its triggers. Am I wrong about this? Doing this for each form is not realistic given that events are added all the time and I have other responsibilities.
Is there no way to set a trigger for these files without running and authorizing each one?
My other solution is:
I am trying to get all the forms in a folder and then get the responses and send a single email to each registrant. This seems overly complicated and requires checking all the forms regularly since there are no triggers for the individual forms. I tried setting triggers in my spreadsheet for the forms and this works, but the number of triggers for a spreadsheet is limited to 20, so doesn't work here. Running my script every minute and then checking if an email has been sent to each respondent seems possible, but complex and possibly prone to errors...
Thanks for any help you can offer!
pgSystemTester's answer worked for me.
I added two bits of code.
One, to declare the time stamp value to zero if there wasn't one
there.
Two, the code needed a "-1" when you get dRange or you insert a new
row which each run.
function sendEmailsCalendarInvite() {
const dRange = sheet.getRange(2, registrationFormIdId, sheet.getLastRow() - 1, 2);
var theList = dRange.getValues();
for (i = 0; i < theList.length; i++) {
if (theList [i][1] == ''){
theList[i][1] = 0;
}
if (theList[i][0] != '') {
var aForm = FormApp.openById(theList[i][0]);
var latestReply = theList[i][1];
var allResponses = aForm.getResponses();
for (var r = 0; r < allResponses.length; r++) {
var aResponse = allResponses[r];
var rTime = aResponse.getTimestamp();
if (rTime > theList[i][1]) {
//run procedure on response using aForm and aResponse variables
console.log('If ran')
if (rTime > latestReply) {
//updates latest timestamp if needed
latestReply = rTime;
}
//next reply
}
}
theList[i][1] = latestReply;
//next form
}
}
//updates timestamps
dRange.setValues(theList);
}
This is probably a simple solution that will work. Setup a spreadsheet that holds all Form ID's you wish to check and then a corresponding latest response. Then set this below trigger to run every ten minutes or so.
const ss = SpreadsheetApp.getActiveSheet();
const dRange = ss.getRange(2,1,ss.getLastRow(),2 );
function loopFormsOnSheet() {
var theList = dRange.getValues();
for(i=0;i<theList.length;i++){
if(theList[i][0]!=''){
var aForm = FormApp.openById(theList[i][0]);
var latestReply = theList[i][1];
var allResponses = aForm.getResponses();
for(var r=0;r<allResponses.length;r++){
var aResponse = allResponses[r];
var rTime = aResponse.getTimestamp();
if(rTime > theList[i][1]){
//run procedure on response using aForm and aResponse variables
if(rTime >latestReply){
//updates latest timestamp if needed
latestReply=rTime;
}
//next reply
}
}
theList[i][1] = latestReply;
//next form
}
}
//updates timestamps
dRange.setValues(theList);
}

Script onForm Submit trigger not working properly

I created a google form that will take the latest response and move the selected choice to the other section. So if someone checks out a laptop, once they submit the form the laptop choice will appear in the check in section. When I manually run the script it works perfectly fine but once I add the trigger it works for the first few times then it starts creating multiple triggers for one submission which then creates multiple new checkboxes on the form that all say the same thing. Like for example I'll have three different laptop choices when there should only be one. So I had to take the trigger off and I've looked at other similar questions about this problem but they all involve spreadsheets but mine is purely working with the google form so I'm not sure if those solutions will work for me.
I didn't add all my code since part of it is the same thing just with different variables for moving choices from check in to checkout.
var form = FormApp.openById('1I5uMesHbeVZ_RSP8wxmmpPA7-Sgcc4b6dzzH305c8K8');
/**
Responds to a form submission event when the on formSubmit trigger is
enabled
*
* #param {Event} e The event parameter created by a form submission
*/
//function that gets checkout responses
function myFunction(e) {
//getting form responses
var formResponses = form.getResponses();
//getting latest response
var latestFR = formResponses[form.getResponses().length-1];
//getting the item/question responses, checkout check in
var itemResponses = latestFR.getItemResponses();
//looping through item responses to see which item has a response
for (var i=0; i<itemResponses.length; i++) {
switch (itemResponses[i].getItem().getTitle()) {
//if only response to checkout
case "Checkout":
var outAnswer = itemResponses[i].getResponse();
outAnswer.forEach(addOut);
outAnswer.forEach(deleteOut);
break;
//if only response to check in
case "Check In":
var inAnswer = itemResponses[i].getResponse();
inAnswer.forEach(addToCheckOut);
inAnswer.forEach(deleteIn);
break;
//if response to both check out/in
case "Checkout" && "Check In":
var outAnswer = itemResponses[i].getResponse();
var inAnswer = itemResponses[i].getResponse();
outAnswer.forEach(addOut);
outAnswer.forEach(deleteOut);
inAnswer.forEach(addToCheckOut);
inAnswer.forEach(deleteIn);
break;
}}
//getting email response to send email
var email = itemResponses[0].getResponse();
//testing to see if it gets the latest submission
//delete my email later
var subject = 'Response';
var emailTo = [email];
var body = 'Response is' + outAnswer + inAnswer;
MailApp.sendEmail(emailTo, subject, body, {
htmlBody: body});
}
//function that adds the latest response from checkout to check in
section
function addOut(outAnswer) {
//getting check in section item with its choices
var a = form.getItems(FormApp.ItemType.CHECKBOX)[1].asCheckboxItem();
//getting choices from check in
var choices = a.getChoices();
//creating new choice for check in
var choice = a.createChoice(outAnswer);
//adding the choice to the choices
choices.push(choice);
//setting the choices with new choice for check in
a.setChoices(choices);
}
//function that deletes answer from checkout
//only works when its a string so convert outAnswer to string value with
toString but only works with a single choice
function deleteOut(outAnswer) {
var del = form.getItems(FormApp.ItemType.CHECKBOX)
[0].asCheckboxItem();
del.setChoices(del.getChoices().filter(function (choice) {
return choice.getValue() !== outAnswer.toString(); }));
}
You're going to need to do the same kind of thing as the spreadsheet answers suggested, create a script lock and use it to dump quick successive triggers.
Just add the following lines to the top of your script:
var lock = LockService.getScriptLock();
try {
lock.waitLock(3000);
} catch (e) {Logger.log('Could not obtain lock after 3 seconds.');}
Utilities.sleep(3000);
You can also add a "lock.releaseLock();" to the end of your script, but it isn't necessary, locks release on their own.
All this code does is reject any new submissions in the next three seconds after it is triggered. If that isn't enough, change the time in the waitlock AND the sleep to 5000 (forms generally take less than three seconds to run a script like this so you are forcing the script to take longer).

Fill multiple rows in google spreadsheet via google script

I am currently working on a semester project for my university in which we want to log data from an Arduino to a Google Sheet.
I was following the numerous tutorials and examples that I could find on Google and it worked so far really, really well. My Arduino is able to upload data to said spreadsheet.
Unfortunately all those examples always only deal with one row to be filled. For our project we would like to fill 2 or 3 lines simultaneously.
I will shortly show what I have done so far and maybe you can help me solve my (probably easy) problem.
I created a google spreadsheet in which I want to log my data
I used the script from a tutorial that should fill one row.
By typing the following line in my browserhttps://script.google.com/macros/s/<gscript id>/exec?tempData=datahereI am now able to fill row one with my data in enter in the end of the url.
But how do I progress now, when I want to fill two or three rows of the table? I say that the author of the code already implemented an option to fill the third row, yet I can't find out what to input in my url then to fill it with data.
All my attempts to write something like
https://script.google.com/macros/s/<gscript id>/exec?tempData=datahere&tempData1=value2
just ended in writing
datahere&tempData1=value2
in my first row, not filling datahere into the first and value2 in to the second row.
How can I provide and write multiple rows of data?
The code in this script is:
/*
GET request query:
https://script.google.com/macros/s/<gscript id>/exec?tempData=data_here
*/
/* Using spreadsheet API */
function doGet(e) {
Logger.log( JSON.stringify(e) ); // view parameters
var result = 'Ok'; // assume success
if (e.parameter == undefined) {
result = 'No Parameters';
}
else {
var id = '<ssheet id>'; // Spreadsheet ID
var sheet = SpreadsheetApp.openById(id).getActiveSheet();
var newRow = sheet.getLastRow() + 1;
var rowData = [];
//var waktu = new Date();
rowData[0] = new Date(); // Timestamp in column A
for (var param in e.parameter) {
Logger.log('In for loop, param='+param);
var value = stripQuotes(e.parameter[param]);
//Logger.log(param + ':' + e.parameter[param]);
switch (param) {
case 'tempData': //Parameter
rowData[1] = value; //Value in column B
break;
case 'tempData1':
rowData[2] = value; //Value in column C
break;
default:
result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));
// Write new row below
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
// Return result of operation
return ContentService.createTextOutput(result);
}
/**
* Remove leading and trailing single or double quotes
*/
function stripQuotes( value ) {
return value.replace(/^["']|['"]$/g, "");
}
I would suggest the following:
Create a 2d array of your data you wish to write to the spreadsheet. If your client on Arduino were using JavaScript this might look like :
var data = [
["row1value1", "row1value2"],
["row2value1", "row2value2"]
];
Convert this to JSON, again in JavaScript this might look like:
var json = JSON.stringify(data);
This gives you a string representation of your array.
Now make your request using this data. I would suggest you should look at using doPost instead of doGet, as you are sending data to the spreadsheet that updates state. However, for the purposes of getting something working, your URL would look like:
https://script.google.com/<.....>/exec?myarray=<stringified JSON>
In Apps Script, in your doGet (again, consider using doPost instead), you could then use:
// Get the JSON representation of the array:
var json = e.parameter.myarray;
// Convert back to 2d array
var data = JSON.parse(json);
Now you can write this to a Range in Sheets using setValues, e.g. assuming a rectangular 2d array:
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
Hope this helps

Logging (lots of) Gmail Data into a Google Sheet

The object of my Google App Script is to log all basic data from email within a certain range of time (not yet implemented), from within all labels, into a Google Sheet.
This currently works to a limited degree. It will collect a small number of emails, but if I increase this (I have a lot of emails to log), this code will either ‘Exceeded maximum execution time’ if I pause for 500 or 1000 milliseconds (as below), otherwise I hit the other ratemax quota Service invoked too many times in a short time: gmail rateMax. Try Utilities.sleep(1000) between calls.
In the code below, I believe I attempted to repeat the main FOR loop 20 times with a WHILE loop, this was a way of seeing if I could perform this single grab n load var labelThreads = GmailApp.getUserLabelByName(label).getThreads(start, 1), 20 times. This would be one way to begin tracking "batches" -- It didn't quite work and I believe there is a better way to approach this, need some help.
function whenV24() {
function setColumnNames(range, columnNames){
var cell = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange(range);
cell.setValues(columnNames);
}
setColumnNames("A1:G1", [["Date","Label","To","From","Subject","Body","File Names"]]);
betterGetV24();
}
function betterGetV24() {
var myspreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = myspreadsheet.getSheets()[0];
var threads = GmailApp.getInboxThreads();
var messages = GmailApp.getMessagesForThreads(threads);
// ** LABEL NAME COLLECTION **
var labels = GmailApp.getUserLabels();
// ** CREATE EMPTY DATA ARRAYS **
var emailFrom = [];
var emailTo = [];
var emailBody = [];
var emailDate = [];
var emailLabel = [];
var emailSubject = [];
// ** LOAD "INBOX EMAIL DATA" INTO EMPTY ARRAYS **
for(var i = 0; i < threads.length; i++) {
emailBody.push([" "]);
emailFrom.push([messages[i][0].getFrom()]);
emailTo.push([messages[i][0].getTo()]);
emailSubject.push([messages[i][0].getSubject()]);
emailDate.push([Utilities.formatDate(messages[i][0].getDate(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'")]);
emailLabel.push(["Inbox"]);
};
// ** LOAD "LABELED EMAIL DATA" INTO EMPTY ARRAYS **
for (var l = 0; l < labels.length; l++) { // ** Runs a for-loop over "labels array".
var label = labels[l].getName(); // Gets "this" label name.
var start = 0; // sets start number as 0
var tracker = 0;
// this section of code has to loop based on a separate set of logic
while (start < 20){
tracker++;
Logger.log("tracker :" + tracker);
var labelThreads = GmailApp.getUserLabelByName(label).getThreads(start, 1); // Gets threads in "this" label. (*Set Limits Here*)
var labelMessages = GmailApp.getMessagesForThreads(labelThreads); // Gets array with each email from "this" thread.
Utilities.sleep(500); // pause in the loop for 500 milliseconds
for (var t = 0; t <labelThreads.length; t++){ // ** Runs a for-loop over threads in a label.
Logger.log("part 1 - inside for-loop over message number: " + labelMessages[t][0].getId());
Utilities.sleep(500);// **pause in the loop for 500 milliseconds
if (labelMessages[t] == undefined){} // If it's empty, skip.
else { // If it's not empty.
Logger.log("part 2 - inside if statement in for-loop > push emailData into arrays");
emailBody.push([" "]);
emailFrom.push([labelMessages[t][0].getFrom()]);
emailTo.push([labelMessages[t][0].getTo()]);
emailDate.push([Utilities.formatDate(labelMessages[t][0].getDate(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'")]);
emailSubject.push([labelMessages[t][0].getSubject()]);
emailLabel.push([labels[l].getName()]);
mysheet.getRange(2,2,emailLabel.length,1).setValues(emailLabel);
}
}
Logger.log("part 3 - outside if statement -> start += 2")
var start = start + 3;
}
Logger.log("part 4 - outside while loop");
}
// ** THEN, LOG THE FILLED DATA ARRAYS TO ROWS **
//getSheetValues(startRow, startColumn, numRows, numColumns)
mysheet.getRange(2,4,emailFrom.length,1).setValues(emailFrom);
mysheet.getRange(2,3,emailTo.length,1).setValues(emailTo);
mysheet.getRange(2,1,emailDate.length,1).setValues(emailDate);
mysheet.getRange(2,5,emailSubject.length,1).setValues(emailSubject);
mysheet.getRange(2,6,emailBody.length,1).setValues(emailBody);
}
I think at this point I should be using triggers, but it seems like I also have to track the previous batch of emails-logged and continue to the next batch. I'm also not aware of how to tie this in with triggers.
Thanks for reading. Any help is appreciated.
EDIT
I was setting data to the spreadsheet incorrectly here. For each loop I was trying to set data in the spreadsheet. I'm not sure how I ended up doing that. Simply moving this out of the loop and setting it later fixed my issue. updated code here: http://pastie.org/9793256#96,100,109,117,123-125,131,135-139
for (var t = 0; t <labelThreads.length; t++){ // ** Runs a for-loop over threads in a label.
Logger.log("part 1 - inside for-loop over message number: " + labelMessages[t][0].getId());
Utilities.sleep(500);// **pause in the loop for 500 milliseconds
if (labelMessages[t] == undefined){} // If it's empty, skip.
else { // If it's not empty.
Logger.log("part 2 - inside if statement in for-loop > push emailData into arrays");
emailBody.push([" "]);
emailFrom.push([labelMessages[t][0].getFrom()]);
emailTo.push([labelMessages[t][0].getTo()]);
emailDate.push([Utilities.formatDate(labelMessages[t][0].getDate(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'")]);
emailSubject.push([labelMessages[t][0].getSubject()]);
emailLabel.push([labels[l].getName()]);
// ** INCORRECTLY TRYING TO SET DATA PER LOOP **
mysheet.getRange(2,2,emailLabel.length,1).setValues(emailLabel);
}
}
You can use PropertiesService to locally store the index of the last processed email. You can then add the "start" parameter to the GmailApp.search() method to begin searching from the last position and set this whole thing to trigger every 5 or 10 minutes.
function myTrigger() {
var start = PropertiesService.getScriptProperties().getProperty("startIndex");
var threads = GmailApp.search("in:inbox", start, 200);
for (var t in threads) {
// Log the thread using your existing code
start++;
}
PropertiesService.getScriptProperties().setProperty("startIndex", start);
}