Gmail thread object unexpected behavior - google-apps-script

I am trying to write a Google Apps Script that will process all emails that have a specific label.
I am using the GmailApp.search function to retrieve all of the relevant emails, but when I try to use the functions document in the GmailThread class, I get an error message that says that it can't find the function.
Here is my code;
var incoming = "To_Bot"
function readBotsEmail()
{
var emails = GmailApp.search("label:" + incoming);
Logger.log("This is the 'emails' object:" + emails)
var emailsLoopIndex = 0
for (var email in emails)
{
emailsLoopIndex += 1;
try
{
Logger.log("iteration " + emailsLoopIndex + " " + email.getMessageCount());
}
catch(e)
{
Logger.log("iteration " + emailsLoopIndex + " " + e);
}
}
}
Here is the logger output.
[14-01-26 03:40:00:909 EST] This is the 'emails' object:GmailThread,GmailThread
[14-01-26 03:40:00:911 EST] iteration 1 TypeError: Cannot find function getMessageCount in object 0.
[14-01-26 03:40:00:914 EST] iteration 2 TypeError: Cannot find function getMessageCount in object 1.
Where am I going wrong?

You should avoid using ambiguous variable names, "email" and "emails" are really bad choice when talking about threads on one side and index integer on the other...
Your issue comes mainly from this confusion between both variables, you used email instead of email*S* and also seem to forget that your value was an array of threads thus needing to be indexed.
Here is your working code, just one letter difference ;-) and a couple of brackets...
function readBotsEmail()
{
var emails = GmailApp.search("label:" + incoming);
Logger.log("This is the 'emails' object:" + emails)
var emailsLoopIndex = 0
for (var email in emails)
{
emailsLoopIndex += 1;
try
{
Logger.log("iteration " + emailsLoopIndex + " " + emails[email].getMessageCount());
}
catch(e)
{
Logger.log("iteration " + emailsLoopIndex + " " + e);
}
}
}
That said, you still have a lot of work on this script to make it return something interesting... for now it informs you on the number of threads and how many message they have... Anyway, that's a good start...
Good luck !

Related

Creating a custom formula with array having multiple arguments in columns with different data

Up to this point I've managed to get it to work for a single argument (body) but without the second argument (photoUrl):
function SendTelegram(body,photoUrl) {
if (body.map) {
var response = body.map(function(b) {return SendTelegram(b);});
} else {
var response = UrlFetchApp.fetch(
"https://api.telegram.org/bot" + 'AAA' +
"/sendPhoto?caption=" + encodeURIComponent(body) +
"&photo=" + encodeURIComponent(photoUrl) +
"&chat_id=" + 'BBB' +
"&disable_web_page_preview=true&parse_mode=HTML"
);
}
}
I'm not able to understand how I should proceed to work with this two different arguments, for example, the function in the spreadsheet would be:
=ARRAYFORMULA(SendTelegram(A1:A,B1:B))
In my attempts when I try to add the second argument, it always uses the first row value in all calls, it doesn't follow the array one by one.
In your script, at SendTelegram(b) of var response = body.map(function(b) {return SendTelegram(b);});, the 2nd argument is not set. By this, at 2nd loop, photoUrl is not declared. I thought that this might be the reason of your issue.
And, in your script, I thought that it might be required to return the response value. So, how about the following modification?
Modified script:
function SendTelegram(body, photoUrl) {
if (body.map) {
return body.map((b, i) => SendTelegram(b, photoUrl[i]));
} else if (body && photoUrl) {
return UrlFetchApp.fetch(
"https://api.telegram.org/bot" + 'AAA' +
"/sendPhoto?caption=" + encodeURIComponent(body) +
"&photo=" + encodeURIComponent(photoUrl) +
"&chat_id=" + 'BBB' +
"&disable_web_page_preview=true&parse_mode=HTML", { muteHttpExceptions: true }
).getContentText();
}
return null;
}
Note:
This is a simple modification. Because I cannot understand your expected value from the URL. So, please modify the script for your situation.

Getting response with NodeJS request module

I just started using the twitch kraken api and I have a few questions.
Whenever I attempt to get a JSON object there is no response. I am attempting to run this function through Amazon AWS Lambda, and don't have access to a console.
In the code below my callback function will always print out "SUCCESS got streamers ERROR". I am pretty certain right now the "ERROR" comes from my initial setting of result.
How come result does not get changed into the proper JSON?
I have used postman and it returns the proper thing with the query and param, and headers:
function getJSON(callback){
var result = "ERROR";
request.get(url(games[0]),function(error,response,body){
console.log("requested for url: " + url(games[0]));
var d = JSON.parse(body);
result = d.streams[0];//.channel.display_name;
// for(var i = 0; i < limit; i++){
// streamers.push(d.streams[i].channel.display_name)
// }
streamers.push(result);
});
if (streamers.length < 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
}
function url(game){
return {
url: "https://api.twitch.tv/kraken/streams/",//twitchlimit,
qs : {
'game' : 'overwatch',
'limit' : 2
},
headers: {
'Client-ID': clientID,
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
}
};
}
I think your streamers code
if (streamers.length < 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
should be included in the request callback because currently it's not waiting for the request to finish, it's just carrying on so therefore the value of result will not change. Also the array length cannot be less than 0 so it will always go to the else and say "SUCCESS got streamers ERROR"
Thank you guys for the suggestions. I did have a few oversights and attempted to fix them.
I have implemented you suggestions and it seems to have worked a bit. I ended up putting the json.parse into a try/catch block, and moved the if/else statements inside the getJSON method. However, now I don't get any output.
This is how I am invoking the getJSON method:
function handleGameResponse(intent,session,callback){
//gets the game
var game = intent.slots.game.value;
if (!games.includes(game)){
var speechOutput = "You asked for: " + intent.slots.game.value;
//var speechOutput = "You asked for: " + games[game] + " That game is currently not an option. These are your current options: " + arrayToString(games)
var repromptText = "Please ask one from the current options.";
var header = "Invalid Game";
}else {
getJSON(function(data){
if(data !== "ERROR"){
var speechOutput = data; //capitalizeFirst(game) + " top three streamers are: " + arrayToString(streamers) + '.';
var repromptText = "Do you want to hear more about games?";
var header = capitalizeFirst(game);
}else{
var speechOutput = "I'm sorry, something went wrong and I could not get the streamers.";
}
//speechOutput = data;
});
//speechOutput = games[0] + " games[0], game= " + game; //this executes so the getJSON isn't executing
}
var shouldEndSession = false;
callback(session.attributes,buildSpeechletResponse(header,speechOutput,repromptText,shouldEndSession));
}
Does the above execute the same way? As in the shouldEndSession and callback execute before the getJSON has time to give a response?
For ref, this is the getJSON method now:
function getJSON(callback){
var result = "ERROR";
request.get(url(games[0]),function(error,response,body){
try{
var d = JSON.parse(body);
} catch (err){
callback("Sorry, something seems to have malfunctioned while getting the streamers");
}
result = d.streams[0].channel.display_name;
// for(var i = 0; i < limit; i++){
// streamers.push(d.streams[i].channel.display_name)
// }
streamers.push(result);
if (streamers.length <= 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
});
}

Intermittant DriveWriteVolume rateMax exception

I have been struggling with this error since about a week before DriveApp was released. I have a section of code that fails intermittantly with the error:
Service invoked too many times in a short time: driveWriteVolume rateMax. Try Utilities.sleep(1000) between calls.
Here is the code in question:
for(var a = 0; a<attachments.length; a++){
if(a > 0){
child = "." + (a + 1) + " ";
}
else{
child = ".1 ";
}
var parent = (m + 1);
Utilities.sleep(5000);
var file = attachmentFolder.createFile(attachments[a]);//This is the line that causes the error.
Utilities.sleep(1000);
file.rename(parent + child + attachments[a].getName());
}
I started with 1000ms, then gradually worked up to 5000 and it still throws the error every ~200 iterations. This is using DocsList.
I have had a similar problem in a script I'm working on.
The problem arises when I loop through the attachments to the message and attempt to save them too. If I skip the attachments, I don't have a problem, even with the same number of total file creations and the same sleep time between them. This is the code I'm using. newFolder.createFile(pdfBlob) does not cause a problem. newFolder.createFile(attachmentBlob) does.
// Create the message PDF inside the new folder
var htmlBodyFile = newFolder.createFile('body.html', messageBody, "text/html");
var pdfBlob = htmlBodyFile.getAs('application/pdf');
pdfBlob.setName(newFolderName + ".pdf");
newFolder.createFile(pdfBlob);
Utilities.sleep(sleepTime); // wait after creating something on the drive.
htmlBodyFile.setTrashed(true);
// Save attachments
Logger.log("Saving Attachments");
for(var i = 0; i < messageAttachments.length; i++) {
Logger.log("Saving Attachment " + i);
var attachmentBlob = messageAttachments[i].copyBlob();
newFolder.createFile(attachmentBlob);
Utilities.sleep(sleepTime); // wait after creating something on the drive.
} // each attachment

Unexpected exception upon serializing continuation Google Apps Script

I recently started getting the error "Unexpected exception upon serializing continuation" on a spreadsheet Google Apps Script when trying to debug. The error seem to start after I created a connection to the Google CloudSQL api. This error still occurs even after commenting out the jdbc object constructor. It appears that others have had this issue and needed a Google Tech to resolve the issue.
I have searched all of the discussion boards for a solution to this issue with no luck. Any chance there is a Google tech out there who could take a look under the hood for me? I would post code if I could determine what line was actually triggering the error.
EDIT:
Ok, I think I have discovered where the error is occuring. Seems to be the
var response = UrlFetchApp.fetch(url + nextPage,oauth_options);
in the while loop. Here is the entire function code.
function retrieveEvents(endTimeMinimum, updatedAfter, orderBy){
//var url = 'https://www.googleapis.com/calendar/v3/calendars/' + source_cal + '/events?key=' + api_key + "&futureevents=true&orderBy=updated&sortOrder=descending&updatedMin=" + last_sync_date_formated;
//var url = 'https://www.googleapis.com/calendar/v3/calendars/' + source_cal + '/events?key=' + api_key + "&orderBy=updated&sortOrder=descending&updatedMin=" + last_sync_date_formated;
var url = 'https://www.googleapis.com/calendar/v3/calendars/' + source_cal + '/events?key=' + api_key + "&singleEvents=true";
if ((orderBy != null) && (orderBy != "")){
url += "&orderBy=" + orderBy;
}
else url += "&orderBy=updated";
if ((updatedAfter != null) && (updatedAfter != "")){
url += "&updatedMin=" + updatedAfter;
}
else url += "&updatedMin=" + last_sync_dateTime;
//if no endTimeMinimum is specified, the current time will be used.
if (endTimeMinimum == null || endTimeMinimum == ""){
endTimeMinimum = date_rfc339("Today");
}
url += "&timeMin=" + endTimeMinimum;
Logger.log("Request URL:" + url);
var largeString = "";
var events = new Array();
var nextPage = "";
var jsonObj
while(true){
var response = UrlFetchApp.fetch(url + nextPage,oauth_options);
largeString = response.getContentText();
if ((largeString != null) && (largeString != "")) {
jsonObj = JSON.parse(largeString);
}
if ('items' in jsonObj) events = events.concat(jsonObj.items);
if ('nextPageToken' in jsonObj){
nextPage = "&pageToken=" + jsonObj.nextPageToken;
continue;
}
break;
}
if (events.length == 0)return null;
return events;
}
OK, so I was able to make the problem go away by removing the try catch block inside a function that was called from inside a try catch block in the main function. I no longer am seeing the "Unexpected exception upon serializing continuation" when running the program from the debugger.
I wish I had a more solid answer on what causes this error and how to correct it.
In my experience, this is not an error caused by that line (or any other) specifically, but because an error is triggered within a loop. I haven't pinned down the exact replicable cause, but GAS seems to lose the loop pointer certain errors.
The best I can suggest is that any line that you suspect to causing an error within the while loop wrap with a try-catch that logs the error to the logger and proceeds. The loop pointer is then not lost and will debug as expected.

typeof fails on trigger object property

I am trying to add an dumpObject function to a Spreadsheet Container bound Script.
Ideally, it is for visibility into variables passed through triggers.
I can run it all day long from within the Script Editor, but when setup as either an onEdit event or onEdit Installible trigger, it dies with no error.
I did some trial and error toast messages and confirmed the code in dumpObject is being executed from the Trigger.
If you take this code below, setup onEdit2 as an installable trigger, you might see it.
To see it work as a Trigger, uncommment the first line //e of onEdit2.
Best I can figure, is something in the e object coming from the trigger that is not quite what is expected of an object?
This test should be limiting the maxDepth to 5, so I don't think I'm hitting the 1000 depth limit.
UPDATE: The problem is calling typeof on the trigger object properties. For example, "typeof e.user" reports the following error: Invalid JavaScript value of type
Thanks,
Jim
function onEdit2(e) {
//e = {fish:{a:"1",b:"2"},range:SpreadsheetApp.getActiveSpreadsheet().getActiveRange(),B:"2"};
Browser.msgBox(typeof e);
Browser.msgBox("U:" + Utilities.jsonStringify(e));
e.range.setComment("Edited at: " + new Date().toTimeString());
Browser.msgBox("ShowOBJ:"+dumpObject(e, 5));
}
function dumpObject(obj, maxDepth) {
var dump = function(obj, name, depth, tab){
if (depth > maxDepth) {
return name + ' - Max depth\n';
}
if (typeof obj === 'object') {
var child = null;
var output = tab + name + '\n';
tab += '\t';
for(var item in obj){
child = obj[item];
if (typeof child === 'object') {
output += dump(child, item, depth + 1, tab);
} else {
output += tab + item + ': ' + child + '\n';
}
}
}
return output;
};
return dump(obj, '', 0, '');
}
You're not getting quite what you expect from the event object. If you throw in:
for(var q in e) {
Logger.log(q + " = " + e[q])
}
and then check the View->Logs menu item in the script editor you get
source = Spreadsheet
user = <your user>
So, checking the docs, you can come up with this as an alternative to your e.range.setComment("Edited at: " + new Date().toTimeString());:
e.source.getActiveSheet().getActiveCell().setComment("Edited at: " + new Date().toTimeString());
note: you can debug an error like you were (secretly) getting by wrapping your statement in a try catch like so:
try {
e.range.setComment("Edited at: " + new Date().toTimeString());
} catch (ex) {
Logger.log(ex);
}
and then checking the logs as mentioned above (or dumping to Browser.msgBox(), if you prefer).
This might not be a great "answer" but it works.
I found that replacing typeof with Object.prototype.toString.call(obj) I got something usable.
Of note, the e object returns [object Object] but the properties (e.user) return [object JavaObject]
if (Object.prototype.toString.call(obj).indexOf("object") != -1) {
var child = null;
var output = tab + name + '\n';
tab += '\t';
for(var item in obj){
child = obj[item];
if (Object.prototype.toString.call(child).indexOf("object") != -1) {
output += dump(child, item, depth + 1, tab);