Google Apps Script - Automated Email Based on Cell Value - email

I'm a total noob when it comes to working with scripts and I'm looking for some help with one that I borrowed and modified to work with my spreadsheet.
I am looking for the value "Need to Order" in column H that will then cause an email to be sent out to a recipient. The only problem I'm having is that every time a value in that column is changed and my "Need to Order" text is present in one of the other cells in the column, an email gets sent out and my inbox gets flooded. Can someone help me tweak it so that it doesn't generate an email if any of the other cells in the column already have the "Need to Order" value present?
Thanks for any help you can afford.
Here's what I'm working with:
function sendEmail(email_address, email_subject, email_message) {
var status = ScriptProperties.getProperty('AlertStatus')+"";
var value = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vehicle Inventory").getRange( "H2:H100").getValues().toString();
if (value.match("Need to Order" )&&status.match("")) {
ScriptProperties.setProperty('AlertStatus', '')
MailApp.sendEmail('username#gmail.com', 'Need to Order', 'Order more equipment. Open the current version of your Google Document "test spreadsheet": ');
}
else {
if (!value.match("Need to Order" ))
ScriptProperties.setProperty('AlertStatus', '')
}
}​

How about changing:
var value = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vehicle Inventory").getRange( "H2:H100").getValues().toString();
to
var value = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vehicle Inventory").getActiveCell().getValue().toString();
This way you inspect the current cell where the cursor is on and not the entire column.

Related

How to send a conditional email based on the value of a cell from a form response?

I have a formula that calculates a number based on the response from a google form. Depending on what this number I want to send an email using details from the from as well as a pre typed email in another cell.
In Col1 is a time stamp, in col14 is an employee start date. My formula in Col33 works out how many days they have been employed at the time of submitting the form.
I want to send an email to the person if the number of days is less than 182.
I have an email pre typed out and can place this anywhere. At the moment I have it in all cells in col36. The email address will be in column32.
I have tried a number of different codes and none of them are sending the email no matter what the trigger I have set up is. I have very basic knowledge on apps script so my current code might be completely wrong, but it should show roughly what I'm getting at.
function sendEmail() {
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues()
for (i in values.length) {
var data = values[i][33];
var emailAddress = values[i][32];
var message = values[i][36];
if (data < 182); {
MailApp.sendEmail(emailAddress, "Flexible Working Request", message);
}
}
}
The current results have just been deleting the data in col33, Col34 & Col36 on the new form response row only.
Sorry if this question has been answered elsewhere, any other answer I found to similar issues I could not get to work.
I got someone who is much better at google apps script at work to give me a hand
It is to do with google forms pushing down formulas to the side
So we had to move the formula calculating the number of days to another sheet and then used this formula which worked
function sendEmailv2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form responses
1');
var scrip = Session.getScriptTimeZone();
var date = sheet.getRange(sheet.getLastRow(),14).getValue();
var sub = sheet.getRange(sheet.getLastRow(),1).getValue();
Logger.log(date);
var fortmat = Utilities.formatDate(new Date(date), scrip, "dd/MM/yyyy");
var Subfortmat = Utilities.formatDate(new Date(sub), scrip, "dd/MM/yyyy");
var emailAddress = sheet.getRange(sheet.getLastRow(),32).getValue();
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet4');
var message = sheet2.getRange(1,1).getValue();
var days = sheet2.getRange(sheet2.getLastRow(),2).getValue();
if (days<182){
MailApp.sendEmail(emailAddress, "Flexible Working Request", message,{noReply:true});
}
}
Thanks!
You don’t need to go over all the columns to get a single cell value, so there is no need for a for loop. You can do it directly with:
var sheet = SpreadsheetApp.getActiveSheet().getSheets[0];
var cell = ["A33"];
var days_value = sheet.getRange(cell).getValue();
Then you can just make an if condition to send the email:
if (days_value < 182){
MailApp.sendEmail(emailAddress, "Flexible Working Request", message);
}
Hope this helps

How to get email form submissions script to exclude blank response values from sheet?

I am editing an existing script that my team uses for a google form response sheet. The script automatically creates a message body using the headers and response cells for an order every time it is submitted, roughly like this:
Type of Order: Physical
Country: America
Digital Signature:
Favorite Color:
Favorite Food: Pasta
What I've been asked to do, is have the script read through the sheet and not include the header or response for questions that are not answered in any given submission. Like so, for the previous example:
Type of Order: Physical
Country: America
Favorite Food: Pasta
I should start by saying I have close to 0 experience in javascript or Google Apps. I have tried playing around with if clauses using both the len function and a negated isblank function to no avail. These all lead to undefined errors.
As you'll see, the original script was not created by me or the people who have been using it for the last few years.
Original script
function sendFormByEmail(e)
{
Logger.log('value of e is: ' + e);
var email = "xxx#xxx.com";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
var subject = "Type A Request: ";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
// Insert variables from the spreadsheet into the subject.
// In this case, I wanted the new hire's name and start date in the
// email subject. These are the 3rd and 16th columns in my form.
for(var i in headers)
message += headers[i] + ': '+ e.namedValues[headers[i]].toString() + "\n\n";
subject += e.namedValues[headers[10]].toString() + " - " +
e.namedValues[headers[12]].toString();
MailApp.sendEmail(email, subject, message, {noReply:true});
// Based off of a script originally posted by Amit Agarwal - www.labnol.org
}
You can include a check for blank values inside the for loop.
if (e.namedValues[headers[i]].toString() === "") continue;

Custom Email script

I am trying to form a simple order system, which responds to the user with a estimated delivery date once it is inserted into google sheet.
Basically someone completes a google form, which populates the sheet and then I require the sheet to send an email confirmation once a delivery date is manually inserted into the "delivery date" column on the sheet.
Currently the script is:
function CustomEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("B2:L1000");
var UserData = range.getValues();
for (i in UserData) {
var row = UserData[i];
var name = row[5];
var email = row[0];
var score = row[9];
MailApp.sendEmail (row[1], "ORDER CONFIRMATION", "Order Confirmation of: " + name + ". The estimated delivery date is " + score);
}
}
It seems to work but it emails all of the rows of data, so I receive multiple emails each time and it will duplicate. I need it to just send an email to the row which has had the date manually inserted in the sheet. The script is designed to email an email address which is captured through the form.
I would like it to email that line only, I have read that it would be best to use an "on edit" trigger. This works but it still sends an email to the whole sheet each time not just the particular line that is edited.
The email response arrives like this:
"Order Confirmation of: 300mm screws. The estimated delivery date is Thu Jan 17 2019 00:00:00 GMT-0000 (GMT)"
Apologies, this is my first attempt at any sort of script so very novice.
Cheers
Joe

How to trigger an email notification when cell value is modified by function

I would like to create a Google Sheets with event triggers. I'm using Google Apps Script.
I succeeded, thanks to Stack Overflow, to create a Google Sheets with an automatic mail notification when a cell is modified by a user.
Now I would like to know if this is possible when cell is modified by a function (not user's modification), such as :
if (today() >= B3 ; "late" ; "not late")
The function checks date, and give result "late" or "not late".
When deadlines are reached, the function would return "late" and a mail would be sent to warn me. The body mail would have the value of the cell in the B, D and E column and in the same row of the cell modified (I know how to do this using e.source, getRange and getRow)
So far, i've tried this, but it's not working
function sendNotification(e) {
if("F" == e.range.getA1Notation().charAt(0)) {
if(e.value == "Late") {
//Define Notification Details
var recipients = "user#example.com";
var subject = "Deadlines" ;
var body = "deadline reached";
//Send the Email
MailApp.sendEmail(recipients, subject, body);
}
}
}
How can I set up mail notifications when cells in F column have the "late" value (with "late" being the result of a function) ?
You can use a simple script that runs on a timer trigger and checks for any modification in a specific column in your sheet.
I use script like that for a lot of tasks, including calendar and sheets monitoring.
Below is a test code that works on column F, you have to run it once manually to create the scriptProperties value that I use to detect changes.
Then create a time trigger to run it every hour or any other timer value you find useful.
The only issue would be if you have a very long sheet, you could reach the length limit of the properties... (right now I don't remember the max length, will have to check ;-)
Code :
function checkColumnF() {
var sh = SpreadsheetApp.getActiveSheet();
var values = sh.getRange('F1:F').getValues().join('-');
if(PropertiesService.getScriptProperties().getKeys().length==0){ // first time you run the script
PropertiesService.getScriptProperties().setProperty('oldValues', values);
return;
}
var oldValues = PropertiesService.getScriptProperties().getProperty('oldValues').split('-');
var valuesArray = values.split('-');
while (valuesArray.length>oldValues.length){
oldValues.push('x'); // if you append some rows since last exec
}
Logger.log('oldValues = '+oldValues)
Logger.log('current values = '+valuesArray)
for(var n=0;n<valuesArray.length;n++){
if(oldValues[n] != valuesArray[n]){ // check for any difference
sendMail(n+1,valuesArray[n]);
}
}
PropertiesService.getScriptProperties().setProperty('oldValues', values);
}
function sendMail(row,val){
Logger.log('value changed on row '+row+' value = '+val+' , mail sent');
// uncomment below when you are sure everything runs fine to avoid sending dozens of emails while you test !
//MailApp.sendEmail(Session.getActiveUser().getEmail(),'value changed in your sheet','Row '+row+' is now '+val);
}

Getting a Google Form Script generated email to pipe data into Reponse Sheet

I am currently trying to setup an approval workflow. I'm fairly junior when it comes to some of this stuff. But so far have it working at respectable level to fit our needs with the assistance of an example.
I was using the template/example from Email Approval using Google Script and a Form.
The issue I am running into, with a lack of functionality is that at the time of Accept or Deny via the Email that is generated for approval I would like it to then record that data back into the Google Form row in the last column that the email was generated from.
I may end up adding 2nd timestamp, reply email etc later.
So then that row would show the initial form filled out and then either blank/accepted/deny as the status.
Thank you for any time or assistance.
The approval workflow that James Ferreira originally wrote was intentionally very basic. Enhancing it to provide correlation between approvals and the original requests is simple in concept, yet complicates the code because of details and limitations.
Things that need to considered:
Form responses include a timestamp, which we can use as a sort of "serial number" for responses, since it has a very high probability of being unique in an application like this.
We can pass this identifier along with the rest of the URL embedded in the approval email, which will give it back as a parameter to the webapp, in turn.
Passing an object like a timestamp between applications can be troublesome. To ensure that the URL embedded in the approval email works, we need to encode the string representation of the timestamp using encodeURIComponent(), then decode it when the webapp consumes it.
Searching for matches is simplified by use of ArrayLib.indexOf() from Romain Vaillard's 2D Array library. This function converts all array data to strings for comparisons, so it fits nicely with our timestamp.
Alternatively, we could put effort into creating some other identifier that would be "guaranteed" to be unique.
The approval-response web app (doGet()) does not understand what "activeSpreadsheet" means, even though it is a script contained within a spreadsheet. This means that we need a way to open the spreadsheet and record the approval result. To keep this example simple, I've assumed that we'll use a constant, and update the code for every deployment. (Ick!).
So here's the Better Expense Approval Workflow script.
// Utilizes 2D Array Library, https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library
// MOHgh9lncF2UxY-NXF58v3eVJ5jnXUK_T
function sendEmail(e) {
// Response columns: Timestamp Requester Email Item Cost
var email = e.namedValues["Requester Email"];
var item = e.namedValues["Item"];
var cost = e.namedValues["Cost"];
var timestamp = e.namedValues["Timestamp"];
var url = ScriptApp.getService().getUrl();
// Enhancement: include timestamp to coordinate response
var options = '?approval=%APPROVE%&timestamp=%TIMESTAMP%&reply=%EMAIL%'
.replace("%TIMESTAMP%",encodeURIComponent(e.namedValues["Timestamp"]))
.replace("%EMAIL%",e.namedValues["Requester Email"])
var approve = url+options.replace("%APPROVE%","Approved");
var reject = url+options.replace("%APPROVE%","Rejected");
var html = "<body>"+
"<h2>Please review</h2><br />"+
"Request from: " + email + "<br />"+
"For: "+item +", at a cost of: $" + cost + "<br /><br />"+
"Approve<br />"+
"Reject<br />"+
"</body>";
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),
"Approval Request",
"Requires html",
{htmlBody: html});
}
function doGet(e){
var answer = (e.parameter.approval === 'Approved') ? 'Buy it!' : 'Not this time, Keep saving';
var timestamp = e.parameter.timestamp;
MailApp.sendEmail(e.parameter.reply, "Purchase Request",
"Your manager said: "+ answer);
// Enhancement: store approval with request
var sheet = SpreadsheetApp.openById(###Sheet-Id###).getSheetByName("Form Responses");
var data = sheet.getDataRange().getValues();
var headers = data[0];
var approvalCol = headers.indexOf("Approval") + 1;
if (0 === approvalCol) throw new Error ("Must add Approval column.");
// Record approval or rejection in spreadsheet
var row = ArrayLib.indexOf(data, 0, timestamp);
if (row < 0) throw new Error ("Request not available."); // Throw error if request was not found
sheet.getRange(row+1, approvalCol).setValue(e.parameter.approval);
// Display response to approver
var app = UiApp.createApplication();
app.add(app.createHTML('<h2>An email was sent to '+ e.parameter.reply + ' saying: '+ answer + '</h2>'))
return app
}
So, I tried this, but there an issue with the formatting for date when it's in the data array. In order to get this to work, you have to reformat the time stamp in the doGet using formatDate.
I used the following to get it to match the formatting that appears in the array.
var newDate = Utilities.formatDate(new Date(timestamp) , "PST", "EEE MMM d yyyy HH:mm:ss 'GMT'Z '(PST)'");
Lastly, of course update the indexof parameter that is passed to newDate.