I'm using the Form Notifications add-on in a Google Form. I've edited the Code.gs and CreatorNotification.html files and all works fine - when a Google Form is submitted I get an email. Now I'm trying to get some of the fields from that Form submission into the email. But with the edits I've added below, the email notification stops working.
In the Code.gs script I have:
function sendCreatorNotification() {
var form = FormApp.getActiveForm();
var settings = PropertiesService.getDocumentProperties();
var responseStep = settings.getProperty('responseStep');
responseStep = responseStep ? parseInt(responseStep) : 10;
function onFormSubmit(e) {
//Get information from form and set as variables
var First_Name = e.value[2];
// If the total number of form responses is an even multiple of the
// response step setting, send a notification email(s) to the form
// creator(s). For example, if the response step is 10, notifications
// will be sent when there are 10, 20, 30, etc. total form responses
// received.
if (form.getResponses().length % responseStep == 0) {
var addresses = settings.getProperty('creatorEmail').split(',');
if (MailApp.getRemainingDailyQuota() > addresses.length) {
var template = HtmlService.createTemplateFromFile('CreatorNotification');
template.summary = form.getSummaryUrl();
template.responses = form.getResponses().length;
template.title = form.getTitle();
template.responseStep = responseStep;
template.formUrl = form.getEditUrl();
template.notice = NOTICE;
template.firstname = First_Name;
var message = template.evaluate();
MailApp.sendEmail(settings.getProperty('creatorEmail'),
form.getTitle() + ': Case submission',
message.getContent(), {
name: ADDON_TITLE,
htmlBody: message.getContent()
});
}
}
}
}
In the CreatorNotification.html I have:
<p><i>Form Notifications</i> (a Google Forms add-on) has detected that the form
titled <b><?= title ?></b> has received
<?= responses ?> responses so far.</p>
<p>Summary of form responses</p>
<p>First Name:</p> <?= firstname ?>
Any direction would be appreciated.
You are trying to run two triggers. That "Add-on" code creates a trigger. The Add-on creates an "Installable" trigger. You already have one trigger set up for the form being submitted. The onFormSubmit(e) function is a "Simple" trigger. So, you have two triggers set up to run when a form is submitted. So, you created a conflict. If you look in the RESOURCES menu, under CURRENT PROJECT's TRIGGERS, you should see a trigger defined for the sendCreatorNotification() function.
Here's what you can try. You don't need a seperate onFormSubmit(e) simple trigger. The sendCreatorNotification() function, has the event object available to it. Just add e to the sendCreatorNotification() function:
sendCreatorNotification(e)
The write your code to get the value out of e.
Related
I'm new to the Google apps script. I wrote a script to send emails when there is a new submission from google forms using data and template from a spreadsheet. However, it sends an email to not just the new submission but also to all of the previous submissions. The whole script is quite long, so I only copy a short part of it. Is there any way to fix it?
Here is the link to the spreadsheet https://docs.google.com/spreadsheets/d/1fhuwEndIS3khg3W19jpQnBAaCp_MMrD_bfATrdf2-4I/edit?usp=sharing
Thank you.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calculation");
var lr = ss.getLastRow();
for (var i = 3; i<=lr;i++){
var currentEmail = ss.getRange(i, 1).getValue();
var currentName = ss.getRange(i, 3).getValue();
var currentScore1 = ss.getRange(i, 4).getValue();
MailApp.sendEmail(
currentEmail,
subjectline,
"HTML",
{ htmlBody: messageBody }
);
}
}
Instead of reading the values from the spreadsheet take advantage of the form submit event object. This event object has two properties including the form submission values, one is an Array of form submission values in the same order than the sheet columns, the other is an object having a property for each question each of them having an Array of values. Ref. https://developers.google.com/apps-script/guides/triggers/events
This shows the changes that need to done to your script:
function sendEmail(e) {
var currentEmail = e.values[0];
var currentName = e.values[2];
var currentScore1 = e.values[3];
MailApp.sendEmail(
currentEmail,
subjectline,
"HTML",
{ htmlBody: messageBody }
);
}
Note: In order to make the event object work, the function should be called by a Google Sheets form submit trigger.
Related
Event values and offset in Google spreadsheet
How to send an email only to the last Google form submission?
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.
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?
I have a working script in one of my google sheets projects, but now I want it to be triggered when I hit the submit button on a Google Form I have. Basically, the data from my Google Form gets exported to my Sheets form, but then I have a script to analyze the data entered. For some reason, it seems like it's doing nothing when the onSubmitForm() function is triggered. It's clear there's a problem because my logger test line displays for the onSubmitForm function but not for the EvaluateResults function.
The code in my Google Form is simple:
function onSubmitForm(){
Logger.log("onSubmitForm Running");
a.EvaluateResults();
}
The code in the Google Sheets is simple as well:
function EvaluateResults(){
Logger.log("evaluation running");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet_results = ss.getSheetByName("Sheet2");
var sheet_userForm = ss.getSheetByName("Form Responses 1");
sheet_results.getRange("C24").setValue((sheet_userForm.getRange("A2").getValue());
}
You should write the entire function in Google form script itself. You can collect the response from Google form as soon as the submit is hit.
function onSubmitForm(e){
Logger.log("onSubmitForm Running");
var itemResponses = e.response.getItemResponses();
var emailAddress = itemResponses[1].getResponse(); // Response of second question
Logger.log(emailAddress)
var ss = SpreadsheetApp.openById("SS ID"); // Replace with your Spreadsheet Id
var sheet_results = ss.getSheetByName("Sheet2");
sheet_results.getRange("C24").setValue(emailAddress);
}
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.