MailApp.sendEmail() not sending from current user - google-apps-script

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.

Related

MailApp.sendEmail -> mail coming from different accounts

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

onEdit event object active user is returning my email address instead of the user doing the edit

I have a Google sheet with an installed trigger / app script. The script uses the event object (I call it e) to do various things. One thing I am trying is to get the email address of the user who is doing the editing of the Google sheets. So, if the event object is e, the e.user should return the user id / email address of the person logged into the Google sheet and performing the action. But, what it does instead do is return MY email address. I'm guessing the e.user id is the id of the user the app script is running under. Can any Google engineers chime in? How can I get the user id of the person doing the editing?
Ok, wow, I finally got this working, and that was a weird one. So, if the trigger is installable as opposed to simple, and the users doing the editing belong to my same domain, then the e.user should work. It wasn't. What I eventually figured out is when one of the shared collaborators opens up the apps script editor from the container, for some reason, everything started working. So, I'm now able to get the user id's and emails from all the users in my domain when they perform an action. It seems like this is a bug. I dunno. But it works now.
You can obtain the User's Email with e.user.getEmail();
Here's the documentation comment:
getEmail()
Gets the user's email address, if available. If security policies do not allow access to the user's email address, this method 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 runs the script themselves or belongs to the same G Suite domain as the user.

Send email from a Google Script with another 'From' address

My Sheet-bound script is sending an email using MailApp.sendEmail.
The emails are always sent 'from' my own Gmail account. This project is for a customer, and I need his email to be the 'from' on these emails.
Reading similar questions I learn that the I only have flexibility in changing the name and replyTo address, using the advanced options of MailApp.sendEmail. However, the email address is still mine and Google doesn't offer any control over that.
I'm not familiar enough with all of the Google services and options to find the best way to do this. My customer does have a Google Apps for Business, but I don't.
Can I somehow create the email-sending function as a standalone script under his account, and somehow call it from the project under my account?
Any other ideas?
Thanks!
Emails are always sent from the account of the user that executes the script. In case the email is sent by a triggered function (installable triggers are the only ones that are able to send emails since it requires explicit authorization) then the email is sent from the account of the user that created the trigger (and authorized it).
In your case, it seems that the easier solution would be to ask your customer to execute the script himself and initiate all the triggers himself too.
If that should not be possible then you could indeed use a standalone script that would work as a kind of proxy, ie it would receive a request to send a message and actually send it from the customer account while returning an acknowledgement to your script.
But that's a bit tricky... the first solution is more elegant.
Edit :
I found the idea of sending emails through an independent script funny so I gave it a quick try and it seems to do the job pretty easily... test code below (this code should be deployed as a standalone app from your customer account) :
function doGet(e) {
Logger.log('e = e'+JSON.stringify(e));
if(e.parameter.recipient==null){return ContentService.createTextOutput("error, wrong request "+JSON.stringify(e)+"\n\n"+e.parameter.recipient+"\n\n"+e.parameter.subject+"\n\n"+e.parameter.body).setMimeType(ContentService.MimeType.TEXT)};
try{
MailApp.sendEmail(e.parameter.recipient, e.parameter.subject, e.parameter.body)
}catch(err){
return ContentService.createTextOutput('error : '+err).setMimeType(ContentService.MimeType.TEXT);
}
return ContentService.createTextOutput('mail successfully sent').setMimeType(ContentService.MimeType.TEXT);
}
note : the code below goes in your spreadsheet script, the doGet above is an standalone app running from your customer account.
function sendMail(recipient,subject,body){
var sent = UrlFetchApp.fetch("https://script.google.com/macros/s/---------------S381kO1Kqv61E/exec?recipient="+recipient+"&subject="+subject+"&body="+body);
Logger.log(sent);
}
function test(){
sendMail('recipient#gmail.com','test message','hello world')
}
I was able to send messages from my gmail account while being logged as a different user. (the url above is intentionally truncated, I don't want anyone to send email from my account ;-)

Email verification using google app script and google forms

I have a google form app which has, among others, an email id field.I want to verify that the email entered by user is the email which belongs to him. Pls note: I DO NOT WANT TO VERIFY THE DOMAIN/SYNTAX OF EMAIL. All emails would be gmail ids, so if that helps, is there a way to send a mail validation link to their gmail accounts and on clicking the link, the entry is made to spreadsheet. Else its cancelled.
Also the link must be valid for limited time only.
Yes this is possible. You can publish a Google script as a web app and add the email address of the recipient as a query parameter to this app. When the user clicks the link, the app is called, the email is verified and the app itself can log an entry into the spreadsheet.

GmailApp requires the script to run as user and SpreadsheetApp requires authorization of the owner?

I have written a google apps script that captures information from my employees, and writes this in a spreadsheet which only I can access.It also mails the employee, what information they have filled.The script is embedded in my google site.
The problem is,I have to run the script as the owner to be able to edit the spreadsheet and to send the email the script has to be run as the 'user running the script'.
Probable solution is the above problem is to set the script's trigger onChnage i.e. on Change of the spreadsheet on any record / any row the Email relevant that email address on that row mail will be send.
Hope this helps
Given your scenario, you want your script to run in both modes - 'User executing the app' and as yourself which is clearly not possible. However, there are some workarounds you can use.
Set the script to run as the user accessing the app and change the permission of your spreadsheet to provide access to 'Anyone with the link'. That way, no other employee can access or discover the spreadsheet other than if they somehow know the spreadsheet id.
The other option is to set the scrip to run as yourself, keep the spreadsheet private and exploit the replyTo and name options of advanced arguments ( https://developers.google.com/apps-script/class_mailapp#sendEmail ). To the recipient, the email will 'appear' to have come from someone else.
Note, using option 2, you'll run into Issue 2004