I'm struggling to get my script to auto-run at 6AM (ish). I have the trigger set up to run this script, "Time-Driven", on a "day timer" between "6-7 am". I'm getting no failure notifications (set up to email to me immediately), but the script isn't running. It works exactly as I want it to when I manually run it, but the whole point was to automate it, so I'm not sure what I am doing wrong here. I looked up other instances, and they seem to have been fixed by deleting and re-adding the triggers, but that doesn't solve the issue for me. Is it something in my script preventing an auto-run?
function getMessagesWithLabel() {
var destArray = new Array();
var label= GmailApp.getUserLabelByName('Personal/Testing');
var threads = label.getThreads(0,2);
for(var n in threads){
var msg = threads[n].getMessages();
var body = msg[0].getPlainBody();
var destArrayRow = new Array();
destArrayRow.push('thread has '+threads[n].getMessageCount()+' messages');
for(var m in msg){
destArrayRow.push(msg[m].getPlainBody());
}
destArray.push(destArrayRow);
}
Logger.log(destArray);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
if(ss.getLastRow()==0){sh.getRange(2,1).setValue('getMessagesWithLabel() RESULTS')};
sh.getRange(2,1,destArray.length,destArray[0].length).setValues(destArray);
}
I'm not 100% sure, but the reason for this could be that during a trigger there's no "ActiveSpreadsheet" if the script isnt directly linked to spreadsheet (As the spreadsheet is closed). So you should try using:
var ss = SpreadsheetApp.openById(id); // id is the id of the spreadsheet
// https://docs.google.com/spreadsheets/d/id_is_here/
var sh = ss.getSheetByName(name); // name of the actual sheet ("Sheet 1" for example)
Otherwise i see nothing wrong with your code (other than you using label.getThreads(0,2) which sets the maximum number of threads to be brought in to 2, but i assume that's intentional)
Also, you're setting 2,1 instead of what i assume needs to be 1,1 in
if(ss.getLastRow()==0){sh.getRange(2,1).setValue('getMessagesWithLabel() RESULTS')};
The problem is due to the use of getActiveSheet as it retrieves the sheet displayed on the UI but when your time-driven trigger runs there isn't a sheet displayed on the UI.
Replace getActiveSheet by getSheetByName or better get the sheet by it's ID (for details see Get Google Sheet by ID?)
Reference:
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getactivesheet
Related
I have had a look online and on previosuly asked questions but have not come across anything that is suited.
Essenitally I am looking for a script that populates a changes log of when a cell is edited.
I would like to keep a log of the previous comment, updated comment, user of who changed the cell and a timestamp
Any help / advice would be appreciated
Thank you
previoulsy used below; but it does not like the source
function edit(e) {
var logsheet = SpreadsheetApp.getActive().getSheetByName('Change Log');
var esheet = e.source.getActiveSheet();
var ecell = esheet.getActiveCell();
var ecol = ecell.getColumn();
var erow = ecell.getRow();
var editor = Session.getActiveUser().getEmail();
var newcontents = ecell.getValue();
var origValue = e.oldValue
var Avals = logsheet.getRange('A1:A').getValues();
var Alast = Avals.filter(String).length;
var maxRows = logsheet.getMaxRows();
logsheet.getRange(Alast+1,1).setValue(new Date()).setNumberFormat('dd"/"mm"/"yy hh:MM');
logsheet.getRange(Alast+1,2).setValue(editor);
logsheet.getRange(Alast+1,3).setValue(esheet.getName());
logsheet.getRange(Alast+1,4).setValue(ecell.getA1Notation());
logsheet.getRange(Alast+1,5).setValue(origValue);
logsheet.getRange(Alast+1,6).setValue(newcontents);
}
Your code works just fine(*). Here is example of output on the sheet 'Change log':
All you need is to rename the function from edit(e) to onEdit(e).
And it doesn't work from Script editor of course. It fires only when you edit the table.
(*) Except editor column, perhaps. onEdit() may not be able to get editor names due the restrictions for simply triggers: https://developers.google.com/apps-script/guides/triggers
They may or may not be able to determine the identity of the current user, depending on a complex set of security restrictions.
So I keep getting this error message in my spreadsheet when I try to run my code in google script:
You do not have permission to call setFormula.
I tried with both setValue() and setFormula() and the error is the same. I saw somewhere that setFormula() only works with simple formulas (ex. A2*B2/C2).
This is a simple function to concat a hyperlink to the content of the selected cell and forma a hyperlink sintax.
function HIPERLINK() {
var ws = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cell = ws.getActiveCell();
var auto = cell.getValue();
var link = '=HIPERLINK("https://projudi.tjpr.jus.br/projudi/processo/buscaProcesso.do?actionType=pesquisaSimples&-H&Host:&projudi.tjpr.jus.br&-H&User-Agent:&Mozilla/5.0&(Windows&NT&6.3;&WOW64;&rv:49.0)&Gecko/20100101&Firefox/49.0&-H&Accept:&text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&-H&Accept-Language:&pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3&--compressed&-H&Referer:&https://projudi.tjpr.jus.br/projudi/processo/buscaProcesso.do?actionType=iniciarSimples&-H&Cookie:&projudiContCookie=0;&JSESSIONID=053165f8dd5f8532c326f3eb06d7;&projudi-route=4;&dtLatC=54;&dtPC=-;&dtCookie=49542FA50EF89B032E8685F08394F120|UHJvanVkaSstK0V4dGVybm98MQ&-H&Connection:&keep-alive&-H&Upgrade-Insecure-Requests:&1&--data&page=1&flagNumeroUnico=true&flagNumeroFisicoAntigo=false&numeroProcesso='
+auto+'";"'+auto+'")';
cell.setFormula(link);
}
If anyone knows a way to do this without the error message, thanks.
I tried this way and it worked for me without issues:
function setCustomLink(){
var ss = SpreadsheetApp.getActive().getActiveSheet();
var cell = ss.getActiveCell();
var cellValue = cell.getValue();
cell.setValue("https://projudi.tjpr.jus.br/projudi/processo/buscaProcesso.do?actionType=pesquisaSimples&-H&Host:&projudi.tjpr.jus.br&-H&User-Agent:&Mozilla/5.0&(Windows&NT&6.3;&WOW64;&rv:49.0)&Gecko/20100101&Firefox/49.0&-H&Accept:&text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&-H&Accept-Language:&pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3&--compressed&-H&Referer:&https://projudi.tjpr.jus.br/projudi/processo/buscaProcesso.do?actionType=iniciarSimples&-H&Cookie:&projudiContCookie=0;&JSESSIONID=053165f8dd5f8532c326f3eb06d7;&projudi-route=4;&dtLatC=54;&dtPC=-;&dtCookie=49542FA50EF89B032E8685F08394F120|UHJvanVkaSstK0V4dGVybm98MQ&-H&Connection:&keep-alive&-H&Upgrade-Insecure-Requests:&1&--data&page=1&flagNumeroUnico=true&flagNumeroFisicoAntigo=false&numeroProcesso=" + cellValue + ";" + cellValue);
}
Let me know if you get different result.
Tip:
you can create a button and assign setCustomLink function to it, and when you need reformatting just click the button.
Here is the link how to accomplish this: Clickable images and drawings in Google Sheets.
I have tried to find a solution to this problem already for a while.
This is the code
function CHECK(INPUT) {
var url = "GOOGLE SHEET URL" + INPUT;
var response = UrlFetchApp.fetch(url);
var json = response.getContentText("UTF-8");
var data = JSON.parse(json);
var price = data;
SpreadsheetApp.flush();
return price;
}
This function pulls values from google sheet and, as a result, display it in another google sheet. The problem is that when the source changed the destination value do not change.
All that I need is something which will force to recalculate values in google sheet, or refresh function or something else but will keep values up-to-date.
P.S. =CHECK(INPUT, **DATE**) is not a solution
You want to forcibly recalculate the custom function using Google Apps Script.
If my understanding is correct, how about this sample script? I think that there are several answers for your situation. So please think of this as just one of several answers.
In this sample script, in order to recalculate the function, the function is replaced by the same function.
Sample script 1:
In this sample script, when =CHECK(INPUT) is the cell "A1" of "Sheet1", the function is replaced by the same function.
var sheetName = "Sheet1"; // Please modify this for your situation.
var cell "A1"; // Please modify this for your situation.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getSheetByName(sheetName).getRange(cell);
var formula = range.getFormula();
range.clearContent();
SpreadsheetApp.flush();
range.setFormula(formula);
Sample script 2:
In this sample script, all functions in "Sheet1" are replaced by the same function.
var sheetName = "Sheet1"; // Please modify this for your situation.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getSheetByName(sheetName).getDataRange();
var values = range.getValues();
var formulas = range.getFormulas();
var replacedValues = values.map(function(e, i) {return e.map(function(f, j) {return formulas[i][j] || f})});
range.clearContent();
SpreadsheetApp.flush();
range.setValues(replacedValues);
Note:
When the above sample scripts are run, the function is recalculated. For example, one of sample scripts is installed as the time-driven trigger, the function you want to recalculate is forcibly updated by the time-driven trigger.
References:
getFormula()
getFormulas()
setFormula(formula)
setFormulas(formulas)
Time-driven triggers
If I misunderstood your question and this was not the direction you want, I apologize.
I am using the below script to extract email addresses from gmail based upon some search criteria and output them to a google spreadsheet. Functionally, the script works and does what I want it do.
However, I am constantly getting "Exceeded maximum execution time" when I run the script as the maximum execution time for gmail scripts appears to be five minutes. I have tested this with a smaller label in gmail with a handful of emails and the script runs successfully and outputs emails as expected. However when I attempt to extract anything in larger batches with more emails the script cannot finish.
This script is cobled from other stuff I found on the web. I have attempted to amend this time out issue by adding for loops in a try block with the exception being caught and sent to sleep so that the script could pause execution and not exceed the time limit, however this did not work. I have also tried other methods of sending the script to sleep to prevent time out from occuring but these where unsccessful.
Could someone help me in preventing the time out from occurring or else use some more efficient way of searching through email threads to grab the emails out?
Edit: I have amended the code with the suggestions added, however it still cannot complete without reaching execution time limit. Any ideas why the script is not pausing? I have also attempted to search just one message using GmailApp.search(search, 0, 1) however the script will not complete when I search my Inbox.
function extractEmailAddresses() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var userInputSheet = ss.getSheets()[0];
var labelName = userInputSheet.getRange("B2").getValue();
var keyword = userInputSheet.getRange("C2").getValue();
var sheetName = "Label: " + labelName;
var sheet = ss.getSheetByName (sheetName) || ss.insertSheet (sheetName, ss.getSheets().length);
sheet.clear();
var messageData = [];
var search = "label:" + label + "is:unread " + keyword;
// Process 50 Gmail threads in a batch to prevent script execution errors
var threads = GmailApp.search(search, 1, 1);
var messages, from, email, subject, mailDate;
try {
for (var x=0; x<threads.length; x++) {
var message = threads[x].getMessages()[0]; //Get message for thread
from = message.getFrom();
mailDate = message.getDate();
from = from.match(/\S+#\S+\.\S+/g);
if ( from.length ) {
email = from[0];
email = email.replace(">", "");
email = email.replace("<", "");
//push emails to array
messageData.push ([email, mailDate]);
}
}
}
catch (e) {
//Pause script to prevent exceeded timeout error
Logger.log(e.toString());
Utilities.sleep(5000);
}
//Adding our emails to the spreadsheet
sheet.getRange (1, 1, messageData.length, 2).setValues (messageData);
}
Two quick ideas, I've not looked at it in detail and don't know the API well:
Don't call getMessages twice:
Replace:
from = threads[x].getMessages()[0].getFrom();
mailDate = threads[x].getMessages()[0].getDate();
with:
var message = threads[x].getMessages()[0];
from = message.getFrom();
mailDate = message.getDate();
Avoid using setValue on each iteration: Single cell updates to the spreadsheet will be slow, as each time will involve communicating with Sheets infrastructure and committing a value. Instead, build up a bigger array of cell values to change and set it all at once using setValues(Object[][])
Those are just thoughts from a quick glance, sorry.
I was interested in automating data validation of a Google Spreadsheet against another Google Spreadsheet using Google Scripts. I can't seem to find a way to reference the range of another spreadsheet using the openById method. Any thoughts?
function externalSheetDataValidation() {
var cell = SpreadsheetApp.getActiveRange();
//var dataValidationSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dataValidationRules");
//var dataValidationSheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/10Z2s1bSRIhZzBBrMfPmhEphnPx-kJdV3LLlbv0L59g8/edit#gid=0");
var dataValidationSheet = SpreadsheetApp.openById("10Z2s1bSRIhZzBBrMfPmhEphnPx-kJdV3LLlbv0L59g8");
var sheet = dataValidationSheet.getSheets()[0];
var range = SpreadsheetApp.getActiveSheet().getRange("A3:A4");
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(range, true)
.setAllowInvalid(false)
.build();
cell.setDataValidation(rule);
Logger.log(dataValidationSheet.getName());
}
If I am understanding correctly, the issue you are having is selecting a data range from an external spreadsheet?
Im assuming dataValidationSheet is supposed to be the external sheet. It looks like you were on the right track. It looks like the issue is that you are expecting the sheet to be active once you grab it.
Try this change:
var range = sheet.getRange("A3:A4");
Currently you are grabbing the external sheet, but then getting the range from the sheet that was already active. Hopefully this helps!