send email from currently logged in user when checkbox is TRUE - email

My question is an extension of this fantastic solution but am hoping to take it one step further. Whenever a user other than me marks the checkbox as TRUE, the sender of the email is always me, since:
Installable triggers always run under the account of the person who created them
Is it possible to capture the user currently logged in and make them the sender, and if so, what am I missing in my code to make that happen?
What I've tried
I believed I had found my answer, but no such luck. This still posts the timestamp to the sheet successfully, but the email sender still shows as me. Any help would be greatly appreciated.
Edit(s):
I noticed in the above solution if (activeUser === effectiveUser) { only "worked" if typed as if (activeUser !== effectiveUser) {. In my attempts at making it work, I made that edit and forgot to revert it.
function sendEmail(e){
var sheet = e.source.getActiveSheet();
var cell = e.range;
var activeUser = Session.getActiveUser().getEmail();
var effectiveUser = Session.getEffectiveUser().getEmail();
if (activeUser !== effectiveUser) {
Logger.log(cell.getColumn());
Logger.log(cell.isChecked());
//Check if the checkbox in column G(index 7) was checked
if(sheet.getName() == "actionItems" && cell.getColumn() == 7 && cell.isChecked()){
//get current row values from column A to column F
var values = sheet.getRange(cell.getRow(),1,1,6).getDisplayValues().flat();
Logger.log(values);
var transmittalNumber = values[0];
var email = values[5];
var query = values[1];
//create and update the email's hmtl body
var templ = HtmlService.createTemplateFromFile('html_template');
templ.query = query;
var message = templ.evaluate().getContent();
//Send email
MailApp.sendEmail({
to: email,
subject: "Oatsies Action Item: "+transmittalNumber,
htmlBody: message
});
//Add timestamp at column H(index 8)
var timeZone = "GMT-7";
var date = Utilities.formatDate(new Date(),timeZone, "yyyy-MM-dd HH:mm");
sheet.getRange(cell.getRow(),8).setValue(date);
}
}
}

From the question
Is it possible to capture the user currently logged in and make them the sender?
If you are using a free Google account (usually gmail.com account) it might be possible if you use the Gmail API and set a way for active users to authorize the access to their Gmail account to send emails. Also it might be possible if you and the user are using a Google Workspace accounts and if you are able to take advantage of company-wide delegation of authority (also might be possible if you are able to configure the user's email addresses as emails aliases of your account).
Regarding the use of Session.getActiveUser().getEmail() it will return the active user email based on a complex rules i.e. your account and active user belongs to the same Google Workspace domains.
Related
Session.getActiveUser().getEmail() results are inconsistent
Domain-wide delegation
getActiveUser() doesn't return the user?

Related

Send an email using email addresses from a column in Google sheets

I'm trying to create code that will send an email using addresses from a specific column in google sheets. I want the code to send an email after the sheet is edited by other users. For example, someone enters a request on a row in the sheet - then an email is sent to the manager of the request. Here's what I have so far...
function SendEmail(){
// Fetch the email address
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("HLP REQUESTS").getRange("K:K");
var emailAddress = emailRange.getValues()[0][0];
// Send Alert Email.
var message = 'A request has been submitted for professional learning related to an HLP you champion. Please check the Design Team Notes document in case follow-up is required.'; // Second column
var subject = 'HLP Request for Professional Learning';
MailApp.sendEmail(emailAddress, subject, message);
}
When I run the code above I get an error - Exception: Failed to send email: no recipient. There is a valid email address in column K, so I'm a little confused.
If you want get email address from the last cell of the column K it can be done this way:
function SendEmail(){
var emailRange = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("HLP REQUESTS").getRange("K:K");
var emailAddress = emailRange.getValues()
.flat() // convert a 2d array into a flat array
.filter(String) // remove empty elements from the array
.pop(); // get the last element from the array
var message = 'A request has been submitted for professional learning related to an HLP you champion. Please check the Design Team Notes document in case follow-up is required.';
var subject = 'HLP Request for Professional Learning';
MailApp.sendEmail(emailAddress, subject, message);
}
Update
Here is the full implementation with installable trigger onEdit that sends email as soon as the checkbox (in column L) was checked in:
// global variables
var SS = SpreadsheetApp.getActiveSpreadsheet(); // get the srpreadsheet
var checkbox_col = 12; // column with checkboxes (L in this case)
// the main function
function sendEmail(e) {
try {
var {rowStart, columnStart} = e.range; // get row and column of the cell that was edited
if (columnStart != checkbox_col) return; // do nothing if it was not column with checkboxes
if (e.value != 'TRUE') return; // do nothing if the checkboxs was unchecked
e.range.setValue(false); // else uncheck the chekbox
var sheet = SS.getSheetByName('HLP REQUESTS'); // get the sheet
var emailAddress = sheet.getRange('K' + rowStart).getValue(); // get email addres from current row, column K
var message = 'A request has been submitted for professional learning related to an HLP you champion. Please check the Design Team Notes document in case follow-up is required.';
var subject = 'HLP Request for Professional Learning';
MailApp.sendEmail(emailAddress, subject, message); // send the message
SS.toast('Email to ' + emailAddress + ' has been sent');
}
catch(e) { SpreadsheetApp.getUi().alert(e) }
}
// additional functions -------------------------------------------------------------------------
// insatll the trigger
function install_onEidt_trigger() {
ScriptApp.newTrigger('sendEmail').forSpreadsheet(SS).onEdit().create();
SS.toast('Trigger was installed');
}
// remove all triggers
function remove_all_triggers() {
ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t));
SS.toast('All triggers were remoded');
}
// custom menu to install and remove triggers
function onOpen() {
SpreadsheetApp.getUi().createMenu('⚙️ Scripts')
.addItem('Install trigger', 'install_onEidt_trigger')
.addItem('Remove all triggers', 'remove_all_triggers')
.addToUi();
}
To make it work you have:
to reload the spreadsheet (or to run the function onEdit() manually) to get the custom menu Scripts
in the custom menu run the item Install trigger
after that it will try to send the message to the address from column K of current row whenever user clicks on checkbox in column L
My test sheet looks like this:
Sending Emails
function SendEmail() {
const ss = SpreadsheetApp.getActive();
const rsh = ss.getSheetByName("HLP REQUESTS");
const emails = rsh.getRange("K1:K" + rsh.getLastRow()).getDisplayValues().flat();
var message = 'A request has been submitted for professional learning related to an HLP you champion. Please check the Design Team Notes document in case follow-up is required.';
var subject = 'HLP Request for Professional Learning';
emails.forEach(e => {
MailApp.sendEmail(e, subject, message);
});
}
If you wish to attach this to an onEdit you will have to rethink the process because the onEdit trigger fires on every edit to any sheet and most likely you will be require to use an installable onEdit so that you can perform operations that require permission. I'd recommend you play around with the onEdit simple trigger for a while. Look at the event object and see what's available at low overhead cost.

Add Email Signature to Email Notification Script

I am writing a code on Google Apps Script to send an email every time there is a new announcement made in my site. Here is the code for reference:
var url_of_announcements_page = "https://sites.google.com/announcements";
var who_to_email = "emailaccount";
function emailAnnouncements(){
var page = SitesApp.getPageByUrl(url_of_announcements_page);
if(page.getPageType() == SitesApp.PageType.ANNOUNCEMENTS_PAGE){
var announcements = page.getAnnouncements({ start: 0,
max: 10,
includeDrafts: false,
includeDeleted: false});
announcements.reverse();
for(var i in announcements) {
var ann = announcements[i];
var updated = ann.getLastUpdated().getTime();
if (updated > PropertiesService.getScriptProperties().getProperty("last-update")){
var options = {};
options.htmlBody = Utilities.formatString("<h1><a href='%s'>%s</a></h1>%s", ann.getUrl(), ann.getTitle(), ann.getHtmlContent());
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
PropertiesService.getScriptProperties().setProperty('last-update',updated);
}
}
}
}
function setup(){
PropertiesService.getScriptProperties().setProperty('last-update',new Date().getTime());
}
I would like to know if it is possible to add my gmail signature to the code. As when I send it with the script my signature is removed. Do I have to make my signature in the code or am i able to get my signature from gmail and automatically insert it at the end? Here is the line for the formatting of the email:
MailApp.sendEmail(who_to_email, "Announcement - '"+ann.getTitle()+"'", ann.getTextContent()+"\n\n"+ann.getUrl(), options);
Apps Script cannot access user's signature: there is no method for that in MailApp, or GmailApp, or even in Gmail API accessible via Advanced Google Services.
In principle, you could use GmailApp to get a recent outgoing message and search its text for the signature contained after the last -- found in message body. But this requires giving the script a lot more access (GmailApp can access, forward and delete existing email, unlike MailApp) and is error-prone (when text parsing fails, you might end up with an embarrassing fragment of text in your message).
Just append it directly:
var signature = "\n\n--\nFirstName LastName";
// ...
MailApp.sendEmail(... +signature, options);
(By the way, Gmail web interface and Gmail mobile app have different user signatures in general, so having another one for script-generated messages doesn't seem unusual.)

Google Apps - Share Contacts within Org

Within our Google Apps Org, I would like to setup a shared contact list that anyone inside our company can access and add/edit the contacts so we have all the same information. What is the best way to go about this?
I would create an application in App Engine that uses the Google APIs to edit the Shared Contacts list. That way you can restrict access to your domain users and also audit the activity that is occurring. There are third party tools out there that can edit the shared contact list but this is typically locked down to avoid situations where users delete contacts they should not be able to. Don't forget that the Shared Contacts list that appears in Gmail's type-ahead has a 24 hour delay.
Hey for anyone out there we used a Google Sheet, now anyone can update the sheet and you can either set an automated trigger to upload them on a schedule or manually push them into the Google Directory.
gsheet:
First we pull all the contacts from the directory then you can add/update/delete existing or new contacts.
Then push them to the Directory using the menu.
We made setup super simple so it auto grabs the user info and domain etc without the user having to do anything
var SHEET_NAME = 'google';
var ERROR_RECIPIENT_MAIL= Session.getActiveUser().getEmail();
var DOMAIN = ERROR_RECIPIENT_MAIL.replace(/.*#/, "");
Then we call the Domain Shared Contacts API to get all the data and put it into an array:
function getAllContacts(){
var contacts = ContactsApp.getContacts();
var lastRow = SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).getLastRow();
if (lastRow >2) SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).deleteRows(3, lastRow*1-2);
var contacts = ContactsApp.getContacts();
var params = {
method : "get",
contentType : "application/atom+xml",
headers : {"Authorization": "Bearer " +
ScriptApp.getOAuthToken(),"GData-Version": "3.0"},
muteHttpExceptions : true
};
var startIndex=1;
var data,respCode,resp;
resp = UrlFetchApp.fetch("//www.google.com/m8/feeds/contacts/"
+DOMAIN+"/full?alt=json&start-index="+startIndex, params);
respCode=resp.getResponseCode();
//SpreadsheetApp.getActiveSpreadsheet().
// getSheetByName(SHEET_NAME).getRange("A10").setValue(resp);
data = JSON.parse(resp.getContentText());
From there it's then put in the correct fields on the sheet for the user to update. Then the user selects the action from the drop down which calls the appropriate function when the script is run to update.
Example of delete function:
function deleteContact(contactID,rowNumber){
var params = {
method : "delete",
contentType : "application/json",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken(),"GData-Version": "3.0","If-Match":"*"}
};
var resp = UrlFetchApp.fetch(contactID, params);
var respCode=resp.getResponseCode();
if (respCode=='201' || respCode=='200') {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).deleteRow(rowNumber*1);
}
else{
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getRange(rowNumber*1, 15, 1, 1).setValue('ERROR');
ERROR_COUNT=ERROR_COUNT.toString()+rowNumber;
}
}
It's pretty cool, and now we are working on bulk data entry as it seems to stall or stop after about 700 contacts in a single run. Also some of the contacts don't get synced and have an error which we'll work on shortly to get the user more info and even store the missed contact to be fixed and updated after. Anyway hope that helps and gives you some ideas.
Ours is located here for anyone interested.

How to fix this authorization Google Apps Script suggest box library issue?

I'm trying to add an autocomplete feature (a Ui in a popup window in a spreadsheet) in my Google Spreadsheet using this Google Apps Script suggest box library from Romain Vialard and James Ferreira's book (modified):
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "my_sheet" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 1) {
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
var dataCell0 = r.offset(0, 1);
if( dataCell0.getValue() == '' )
otherTestTunction();
}
}
}
But when I start editing column 1 of "my_sheet" and the Ui box appears, this autorization error happens (In my language it says: "you must have permission to perform this action"):
The documentation says that onEdit() trigger "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."
Since I'm not using ContactsApp, I suppose that the suggest box library require authorization.
How could I set up an installable on Edit trigger that will ask for authorization? (Could you give me some code sample?)
Here is my test spreadsheet: https://docs.google.com/spreadsheet/ccc?key=0AtHEC6UUJ_rsdFBWMkhfWUQ0MEs2ck5OY1BsYjRSLXc&usp=drive_web#gid=0
Out of curiosity about what you suggested on authorizations needed by the library I made a test on a new sheet, the exact code below asks for spreadsheet access, nothing more.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
}
To handle that you just have to ask your user to run one function in your script (no matter what function) and they will get the following popup :
After this initial step your function will work as expected, ie the Ui will show up.
Beside that, I'm not sure I understand what you want to achieve is feasible, the onEdit trigger fires when the edit is done, meaning after you hit ENTER, then the value in the suggestBox is not taken into account... moreover you have to handler in the UI to do anything so I'm still wondering what do you really expect to do with this code ? (what would be ideal is an onClick event in spreadsheetApp but unfortunately it doesn't exist so far...)
But maybe I missed something obvious.
About installable onEdit that you mention also in your post, you should note that it doesn't need to be authorized by the end user since it would run as YOU, the person that creates the trigger and not the user accessing the SS , therefor accessing your own data and not the user's ones... That might be a non negligible restriction (as Zig mentioned in a comment earlier...)

setting up script to include google docs form data in email notification

I've setup a form using googledocs. I just want to have the actual data entered into the form emailed to me, as opposed to the generic response advising that the form has been completed.
I have no skill or experience with code etc, but was sure i could get this sorted. I've spent hours+hours and haven't had any luck.
My form is really basic.it has 5 fields. 4 of which are just text responses, and one multiple choice.
I found this tute online (http://www.labnol.org/internet/google-docs-email-form/20884/) which i think sums up what i'm trying to do, but have not been able to get it to work.
from this site i entered the following code:
function sendFormByEmail(e)
{
var email = "reports.mckeir#gmail.com";
var subject = "Google Docs Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
To this, i get the following response: ->
Your script, Contact Us Form Mailer, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.
The script is used by the document 100% Club.
Details:
Start Function Error Message Trigger End
12/3/12 11:06 PM sendFormByEmail TypeError: Cannot call method "toString" of undefined. (line 12) formSubmit 12/3/12 11:06 PM
Is anyone able to help shed some light on this for me? I'm guessing i'm not including some data neeeded, but i honestly have no clue.
Workaround http://www.labnol.org/internet/google-docs-email-form/20884/
You have to setup app script to forward the data as email.
I'll point to the comment above that solved it for me: https://stackoverflow.com/a/14576983/134335
I took that post a step further:
I removed the normal notification. The app script makes that generic text redundant and useless now
I modified the script to actually parse the results and build the response accordingly.
function sendFormByEmail(e)
{
var toEmail = "changeme";
var name = "";
var email = "";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Google Docs Form Submitted";
var message = "";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers) {
if (headers[i] = "Name") {
name = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Email") {
email = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Subject") {
subject = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Message") {
message = e.namedValues[headers[i]].toString();
}
}
// See https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
var mailOptions = {
name: name,
replyTo: email,
};
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(toEmail, subject, message, mailOptions);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
The script utilized in the example is extremely generic but very resilient to change because the message is built as a key/value pair of the form fields submitted.
If you use my script you'll have to tweak the for loop if statements to match your fields verbatim. You'll also want to edit the toEmail variable.
Thanks again for the question and answers. I was about to ditch Google Forms as the generic response was never enough for what I was trying to do.
Lastly, in response to the actual problem above "toString of undefined" specifically means one of the form fields was submitted as blank. If I had to guess, I would say the author only used this for forms where all the fields were required or a quick undefined check would've been put in place.
Something like the following would work:
for(var i in headers) {
var formValue = e.namedValues[headers[i]];
var formValueText = "";
if (typeof(formValue) != "undefined") {
formValueText = formValue.toString();
}
message += headers[i] + ' = '+ formvalueText + "\n\n";
}
I haven't tested this precisely but it's a pretty standard way of making sure the object is defined before trying methods like toString() that clearly won't work.
This would also explain Jon Fila's answer. The script blindly assumes all of the header rows in the response are sent by the form. If any of the fields aren't required or the spreadsheet has fields that are no longer in the form, you'll get a lot of undefined objects.
The script could've been coded better but I won't fault the author as it was clearly meant to be a proof of concept only. The fact that they mention the replyTo correction but don't give any examples on implementing it made it perfectly clear.
If this is a Google Form, do you have any extra columns in your spreadsheet that are not on the form? If you delete those extra columns then it started working for me.
You don't need to use a script. Simply go to Tools >> Notification Rules on your Google Spreadsheet. There you can change the settings to receive an email with your desired information every time the document is changed.