i've this simple script that should send an email when a cell is changed
function onEdit(e) {
var doc = e.source;
var r = doc.getActiveRange().getValue();
if (r == "Niccolò"){
var a = doc.getActiveRange().setBackground('#ff0000');
var b = GmailApp.sendEmail('name#gmail.com', 'subject', 'body');
}
}
This function change also cell colour.
THe problem is that the cell colour works, so it's change while doesn't send any email.
It looks so simple i don't understand why doesn't works!
Simple triggers like onEdit(), onOpen() or onFormSubmit() have a limited set of possible actions because they run without authorization , see the documentation for further details.
So this behavior you describe is normal.
You should use an installable trigger instead as explained in the same doc page.
here is an summary of the documentation :
These simple triggers run in response to actions in Google Spreadsheets, and they run as the active user. For example, if Bob opens the Spreadsheet, then the onOpen function runs as Bob, irrespective of who added the script to the Spreadsheet. For this reason, the simple triggers are restricted in what they are permitted to do:
They cannot execute when the Spreadsheet is opened in read-only mode.
They cannot determine the current user.
They cannot access any services that require authentication as that user. For example, the Google Translate service is anonymous and can be accessed by the simple triggers. Google Calendar, Gmail, and Sites are not anonymous and the simple triggers cannot access those services.
They can only modify the current Spreadsheet. Access to other Spreadsheets is forbidden.
For more information on event permissions, see Executing from a Container-Specific Trigger.
Related
I'm new to GAS and I struggle with the permission system.
I'm a normal Google drive user and I started a spreadsheet and tried to add some code to it. My code is working, but only if I'm in the code editor. I want to use the onEdit() function so it's important for me that it works within the sheet as well. When I ran my code in the editor for the first time it opened a new window where I needed to enter my credentials to allow the script, then it worked. If I do some changes to a cell in my sheet and the onEdit() function is triggered I receive an error message that says something like this(translated):
Exception: You are not permitted to call UrlFetchApp.fetch. Required permission: https://www.googleapis.com/auth/script.external_request
In the editor I displayed the manifest file and added the permission to the oauthScopes but within the sheet I still receive the message. This is how my code looks like (simplified):
function onEdit(e)
{
var data = {
'key1': 'value1',
'key2': 'value2'
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
try{
var response = UrlFetchApp.fetch('https://a-working-url.com', options); //error happening in this line
//some more data wizardry
}catch(error)
{
Browser.msgBox(error)
}
}
Any ideas how I can open this permission screen in my sheet or any hints how to solve it in a different way? I want to create a sheet with some code running in the back online. I want to share the sheet with some friends, tried it with Excel and VBA before until I realized that it's not working with Excel Online, so I switched to GAS.
onEdit(), like all simple triggers, is bound by the following restrictions (see official documentation):
The script must be bound to a Google Sheets, Slides, Docs, or Forms file, or else be an add-on that extends one of those
applications.
They do not run if a file is opened in read-only (view or comment) mode.
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause
the spreadsheet's onEdit trigger to run.
They cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail
service requires authorization, but a simple trigger can translate
a phrase with the Language service, which is anonymous.
They can modify the file they are bound to, but cannot access other files because that would require authorization.
They may or may not be able to determine the identity of the current user, depending on a complex set of security restrictions.
They cannot run for longer than 30 seconds.
In certain circumstances, editor add-ons run their onOpen(e) and onEdit(e) simple triggers in a no-authorization mode that presents some additional complications. For more information, see the guide
to the add-on authorization lifecycle.
Simple triggers are subject to Apps Script trigger quota limits.
The ones highlighted in bold apply to your question.
Basically, it boils down to this - UrlFetchApp.fetch() is a service that requires authorization, so you won't be able to execute it from your onEdit(e) trigger, even if you have its associated scope set in your manifest file.
Use installable trigger instead and write your own "onEdit" function (with a different name) that you bind to your installable trigger.
https://developers.google.com/apps-script/guides/triggers/installable#g_suite_application_triggers
This solved the issue for me.
I have written the script below to hid all rows that have a specific box checked. I set a trigger using the clock and every 10 minutes but instead seems to run every time I check a box and it screws up the view every time I check it. I would like to change it to a manual trigger that is a button along the top bar that someone manually clicks. Can anyone help me edit it?
function onEdit(e) {
var s = SpreadsheetApp.getActive().getSheetByName('2 Week Snapshot');
s.showRows(1, s.getMaxRows());
s.getRange('C:C')
.getValues()
.forEach( function (r, i) {
if (r[0] == 1)
s.hideRows(i + 1);
});
}
As mentioned by I'-'I, the name given to your function causes your script to run when an edit is made to the sheet. From the Apps Script documentation on Simple Triggers:
To use a simple trigger, simply create a function that uses one of these reserved function names:
- onOpen(e) runs when a user opens a spreadsheet, document, presentation, or form that the user has permission to edit.
- onEdit(e) runs when a user changes a value in a spreadsheet.
- onInstall(e) runs when a user installs an add-on.
- doGet(e) runs when a user visits a web app or a program sends an HTTP GET request to a web app.
- doPost(e) runs when a program sends an HTTP POST request to a web app.
The e parameter in the function names above is an event object that is passed to the function. The object contains information about the context that caused the trigger to fire, but using it is optional.
Renaming your function to avoid binding this simple trigger will prevent edits of your sheet from triggering your function.
Documentation to look at:
Guide to Menus
Guide to Triggers
I'm trying to build a simple log for sheets that makes use of cell notes.
Somehow i can't include the email of the user who triggers the onEdit-event.
function onEdit(e){
var email = Session.getActiveUser().getEmail();
var date = String(Utilities.formatDate(new Date(), 'Europe/Berlin', 'HH:mm dd/MM/yy'));
var range = e.range;
range.setNote(email + " # " + date);
}
The note appears on the cell but the email is empty. Could that have to do with missing permissions? I assume if something would be wrong with my code the note wouldn't appear at all on the edited cell in sheets...
Here's what Google documentation says about the Session class
The Session class provides access to session information, such as the
user's email address (in some circumstances) and language setting.
In regards to 'getActiveUser()' method, it states
If security policies do not allow access to the
user's identity, User.getEmail() returns a blank string. The
circumstances in which the email address is available vary: for
example, the user's email address is not available in any context that
allows a script to run without that user's authorization, like a
simple onOpen(e) or onEdit(e) trigger, a custom function in Google
Sheets, or a web app deployed to "execute as me" (that is, authorized
by the developer instead of the user). However, these restrictions
generally do not apply if the developer and the user belong to the
same G Suite domain.
Because you use the simple trigger - onEdit() - the code will not execute unless explicitly authorized by the user. For installable triggers, that would mean executing the function manually from the script editor.
You can publish the project as a sheets add-on. In this case, users will be asked to grant permissions declared in the add-on manifest.
More info https://developers.google.com/apps-script/reference/base/session
Is it possible after making some changes to sheet document on PC and successful sync to google drive, to run specific script (on Google side, kind of cron in unix) to import changes from this sheet to Google Calendar service?
P.S. I already know how to import changes from Sheets to Calendar, the question is about automatic run of this import process on document change(edit).
You can check this documentation about Installable Triggers which let Apps Script run a function automatically when a certain event occurs. It is similar to simple triggers for Google Apps like onOpen(), but they can respond to additional events, and they behave differently.
You can use an installable edit trigger that runs when a user modifies a value in a spreadsheet.
Based from this forum:
The onEdit() trigger is the way to go. Here's a simple example
pulled straight from the documentation:
function onEdit(event)
{
var ss = event.source.getActiveSheet();
var r = event.source.getActiveRange();
r.setComment("Last modified: " + (new Date()));
}
Inside the body of the function you can do a variety of things. If you
need access to authorized services (such as Gmail, Calendar, etc) then
you'll need to create an installable trigger instead.
Hope this helps!
I am trying to create a google sheets custom menu based on the user email.
Code is as follows:
var AllowedReportRecipients = ["u1#gmail.com", "u2#gmail.com", "u3#gmail.com"];
var ReportRecipient = null;
function onOpen()
{
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Custom');
menu.addItem('Edit', 'editHtm')
.addItem('History', 'historyHtm');
var usr = Session.getActiveUser().getEmail();
var isReportee = false;
for (var i=0;i<AllowedReportRecipients.length; i++)
if (AllowedReportRecipients[i] == usr)
{
ReportRecipient = usr;
isReportee = true;
}
if (isReportee)
menu.addItem('Request abc', 'sendABC');
menu.addToUi();
}
This is an unpublished sheet script. As others have reported the call to getActiveUser().getEmail() returns blank when the sheet is opened by the non-owner of the sheet. However, a call to getActiveUser().getEmail() executed at a later time correctly returns the logged in user email. For example, when called in historyHtm in response to the "History" menu item click it works. Why the difference? How do I properly load my menus?
The onOpen() function is a special reserved function, one of the [Simple Trigger][1] functions built into Google Apps Script. These functions run without requiring user authorization, so there are restrictions on what capabilities of the system they may access.
For your case, the important restriction is this:
They may or may not be able to determine the identity of the current user, depending on a [complex set of security restrictions][2].
ref
For users with consumer accounts or accounts that are not in the same Google Apps Domain as the developer, the onOpen() function will not be able to obtain the email address of the person running the script.
When you run other functions, for example those that are invoked via menu, they kick off the authorization cycle for the script, after which they are able to do more than the simple triggers.
That seems inconsistent - but is by design.
I think you need to rethink your user interface - I haven't been able to find a work-around that will produce the "privileged" portion of your menu upon opening the spreadsheet.
An installed onOpen trigger will have greater abilities than the simple trigger, but will run under the authority of the developer so it won't help your situation, as it will come up with your email, not the active user's.
Setting a timed trigger in the onOpen to update the menu seemed promising... except for the restriction that the timed trigger function has no access to the spreadsheet UI, of course.