I am using a script in a shared spreadsheet to send update emails to the working team.
I am using a simple call:
MailApp.sendEmail(mail_address, subject, msg);
It worked fine for some time.. But now I have a strange behavior: the script runs successfully but the emails are actually sent randomly by one of the users which the spreadhsheet is shared with..
I can't understand how that is possible since they are not shared accounts and it shouldn't be possible to send emails like that..
Edit: The script is executed by a trigger based on the editing of the spreadsheet.
Situation:
You have installed an onEdit trigger for all users which have edit access to the spreadsheet.
The function trigged by this trigger sends an email.
You are noticing that the emails are not always being sent by the user that edited the spreadsheet.
Issue:
The problem is that, as you can see here:
Installable triggers always run under the account of the person who created them.
This means the email will not be sent by the user that edited the spreadsheet, but by the one who installed the trigger. Since several users installed this trigger, your project might contain several duplicate triggers, each of which will run on behalf of a different account. Because of this, you might end up receiving multiple emails for one single spreadsheet edition, each of them sent by a different account.
Solution:
If you want to send a single email every time the spreadsheet is edited, and send this email from the account that edited the spreadsheet, you can use the methods getActiveUser() and getEffectiveUser():
Session.getActiveUser() refers to the current user, that is to say, the user that just edited the spreadsheet.
Session.getEffectiveUser() refers to the user under whose authority the script is running. That is to say, the user who installed the trigger.
The idea is to check whether the active user and the effective user are the same one, and send an email only if that's the case. This way, even if multiple functions are trigged by a single edition (one for each account that installed the trigger), only one email will be sent (the one corresponding to the user who edited the spreadsheet).
Code sample:
function onEditTrigger(e) {
var activeUser = Session.getActiveUser().getEmail();
var effectiveUser = Session.getEffectiveUser().getEmail();
if (activeUser === effectiveUser) {
// Rest of code
MailApp.sendEmail(mail_address, subject, msg);
}
}
Note:
If you have installed the trigger, you better not name your function onEdit: this name is reserved for a simple trigger.
Reference:
Installable triggers: Restrictions
Related
This can't be right. What am I missing?
I have a Google Sheet with scripts. The scripts are using certain ui functions that require authentication and special permissions coming from an onEdit() event. Therefore, I had to create onSpecialEdit() and the custom trigger to run that function with event source of the spreadsheet and event type onEdit(). This all works fine. Script does what it should.
From what I've seen, each person who needs to have this ability and access the special edit will need their own trigger. That is created for them automatically. Triggers all work for each person.
Now, what I see is that when I do an action that triggers onEdit(), it appears to run the onSpecialEdit() 20 times...once for each person who has that trigger....I'm assuming.
This can't be right. What am I missing? Is there another way to create triggers where they are only executed by the person triggering? Is this approach wrong?
Issue:
You want to have an onEdit trigger that has access to services that require authorization.
These services should have access private of the user who has caused the trigger to run by editing the spreadsheet.
Since the services require authorization, it cannot be a simple but an installed trigger (Restrictions).
Since installed triggers act on behalf of the user who installed them, they can only access data of the user who installed them.
Therefore, each user whose data should be accessed needs to install the trigger, so multiple triggers should be installed.
A trigger runs whenever any user edits the spreadsheet, it doesn't have to be the user who installed the trigger. Because of this, all of the installed onEdit triggers will run whenever any user edits the spreadsheet.
Solution:
Use Session.getActiveUser() and Session.getEffectiveUser() to check whether the user editing the spreadsheet (getActiveUser) is the same as the one who installed the spreadsheet (getEffectiveUser). If it's not, stop the function execution. This way, only one of the multiple onEdit triggers will make the corresponding actions.
Code sample:
function onEditTrigger(e) {
const active = Session.getActiveUser().getEmail();
const effective = Session.getEffectiveUser().getEmail();
if (active === effective) {
// TRIGGER ACTIONS
}
}
I have an onEdit triggered appscript that grabs data from a spreadsheet, formats it and then sends it to an email address. Typically these messages would be sent 'from' the user that is triggering the script to run. However, I am experiencing strange behavior where the current user is not used to send the message - or used inconsistently.
A couple of notes:
Occasionally the message is sent by the current user, other times it is not (in those cases it comes from my account, which created the script)
Script trigger is an 'onEdit' script which monitors the sheet for a checkbox status change
Spreadsheet is in a Shared Drive
We are using Google apps for education
The recipient address is a mailing list tool. When I list a different email address as the recipient (internal, external, other) the message consistently comes from the current user as expected. I've no idea why the recipient would affect how Google sends the message.
I realize i could use the GmailApp library to send instead, but want to avoid the re-authorizations that are mentioned.
So I have a Google Form-bound script that creates an installable trigger every time the Form is submitted. Now, I shared both the Form and the script to the actual users. At some point I have noticed that new triggers are not being created because quota limit is already reached. As I reviewed the list of installed triggers, I noticed that all of them are installed as "Me". How do I do it so that the other users who actually submitted the form (and created the installable trigger in the process) are identified as the "Owner" of the trigger and not me.
Assuming your code looks something like this:
function createOnFormSubmitTrigger() {
var form = FormApp.openById('[FORM-ID]');
ScriptApp.newTrigger('createTrigger')
.forForm(form)
.onFormSubmit()
.create();
}
function createTrigger() {
ScriptApp.newTrigger("myFunction2")
.timeBased()
.everyMinutes(10)
.create();
}
function myFunction2 () {
console.log('test')
}
And you're the one running the createOnFormSubmitTrigger function and granting the permissions, the trigger will be created for your account (installed as "me"). You would need to ask each user to run the createOnFormSubmitTrigger function by themselves in order to grant the permissions and get the trigger installed under their account. Which in this case wouldn't make much sense because each user trigger would be run each time a form submission is made no matter who submitted it.
As stated in the documentation for installable triggers:
Installable triggers always run under the account of the person who
created them. For example, if you create an installable open trigger,
it runs when your colleague opens the document (if your colleague has
edit access), but it runs as your account. This means that if you
create a trigger to send an email when a document is opened, the email
is always be sent from your account, not necessarily the account that
opened the document. However, you could create an installable trigger
for each account, which would result in one email sent from each
account.
EDIT
You could try a workaround for your use-case by using getActiveUser method which would return the trigger owner user and compare it to the user who submitted the form, which you can get with getRespondentEmail method, using an if statement to compare both user's emails and run the code you need depending on that. This way the triggers will be run every time but the necessary code would be run only when the trigger owner is the same as the form respondent.
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
I have a Google Apps Script that contains the following code:
function onOpen() {
var emailAddress = "jthfortyone#gmail.com";
var message = "Viewed"
var subject = "Someone Viewed Your Resume";
MailApp.sendEmail(emailAddress, subject, message);
}
I want to receive an email every time someone views my resume
But for some reason I only receive an email if I am the one open it and not when anyone else does.
What do I need to change to get the desired results?
Your container-bound script in a shared document will only run if:
Sharing has granted edit privileges. (Viewing and Commenting aren't enough.)
User is logged in with a Google account. (Only scripts run as webapps can be triggered anonymously, at which time they run as the owner. No such option, in this case.)
User agrees to authorize the script. (A script that sends emails will require authorization.)
Since this is your resume, I think you're going to need to find another solution.
The onOpen trigger should run in response to the active user opening the document.
The active user is defined as:
The user (Google account) that causes a script to execute. Depending on the execution method this may be different from the effective user. You can also think of this as the user at the keyboard
Have you tried accessing the document with a dummy account?