I have a spreadsheet with a Yes/No column (column AP) and I need to send an email notification whenever any value within that column is changed. I have worked out how to send one when a specific cell is changed:
function sendNotification(e) {
if("AP4" == e.range.getA1Notation()) {
if(e.value == "YES") {
//Define Notification Details
var recipients = "***********#gmail.com";
var subject = "Update"+e.range.getSheet().getName();
var body = "This cell has changed";
//Send the Email
MailApp.sendEmail(recipients, subject, body);
}
}
}
However, I need this to work for any cell within column AP.
I also then need to store other values with the changed row as variables to use within the email body. So for example, the product name is in column B, and I need to be able to access this name so that my message reads something like "Column AP has been changed to 'Yes' for " + productName. Any help would be received very gratefully.
Try this:
function sendNotification(e){
if(e.range.getColumn()==42 && e.value=='YES'){
var recipients = "***********#gmail.com";
var subject = "Update"+e.range.getSheet().getName();
var body = "This cell has changed";
var valColB=e.range.getSheet().getRange(e.range.getRow(),2).getValue();
MailApp.sendEmail(recipients, subject, body)
}
}
Related
I would like to create a list of emails, which are listed in the column of a sheets.
how can I do this?
example:
column A
email 1
email 2
email 3
mailling = column A
MailApp.sendEmail({
to: mailling,
subject: "test",
body: "Test message",
if your emails are in column A starting from row 2:
function getEmails() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const emails = sh.getRange(2,1,sh.getLastRow() - 1, 1).getValues().flat();
return emails.join(',');
}
function sendEmails() {
MailApp.sendEmail({to: getEmails(),subject: "test",body: "Test message"});
}
I think you should check the documentation of the class like suggested in the comments, it has really good features that can improve the way you email. Anyway, here is an example that can help you.
function sendMail() {
//Each numer means the column of the sheets thats going to grab the value
var first = 0;
var second = 1;
var third = 2;
//In the Column D must have the emails
var fourth =3;
//Specifies the HTML document that going to give the structure of the email
var emailTemp = HtmlService.createTemplateFromFile("email");
//Tells wich is the sheet to take information
//in this case the sheets name is "Data Base"
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data Base");
//Gives the range of the columns that the information is going to be
var data = ws.getRange("A1:E" + ws.getLastRow()).getValues();
//This is an optional filter in the Column F so you can filter wich rows to run
data = data.filter(function(r){ return r[5] == true });
//To use the variables in between the HTML file your going to use the value after "emailTemp." as <?= fr ?>
data.forEach(function(row){
emailTemp.fr = row[first];
emailTemp.se = row[second];
emailTemp.th = row[third];
var htmlMessage = emailTemp.evaluate().getContent();
GmailApp.sendEmail(row[fourth], "HEEERE GOES THE SUBJECT OF THE EMAIL", "Your email doesn't support HTML.", {name: "Email", htmlBody: htmlMessage})
});
Here I used a html template to send emails with variables extracted from other columns. You can check out this github
I am using Google sheets and the Google script editor to create a script to automatically send myself an e-mail every time a product quantity goes below the minimum inventory level. Since I have multiple products with different minimum inventory levels I expect to get a series of e-mails, one for each row.
I use one sheet for the actual Inventory data and another sheet that contains information for the script to refer to, such as my email and what message to include in the e-mail.
I succeeded having an e-mail sent collecting data from the first row of the Inventory sheet but I am not being able to apply that for all the following rows.
I tried changing the .getRange("F2") to .getRange("F2:F"), then whenever one of the products goes under the minimum inventory level I get one single e-mail containing the information about all products, regardless of whether their quantity is under the minimum level or not.
The ideal solution would be ONE single e-mail containing all the information about all products that are under the minimum quantity .
Here is a link to my spreadsheet: https://docs.google.com/spreadsheets/d/1ZHmBvi8ZeaDRYq6Qigaw08NUiOwZumPrLnvnka_mgmA/edit?usp=sharing
Current script:
function CheckInventory() {
// Fetch inventory quantity
var InventoryRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inventory").getRange("F2");
var Inventory = InventoryRange.getValue();
// Fetch minimum quantity
var MinimumQuantityRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Inventory").getRange("D2");
var MinimumQuantity = MinimumQuantityRange.getValue();
// Check Inventory
if (Inventory < MinimumQuantity){
// Fetch email address
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Notification Rules").getRange("E2");
var emailAddress = emailRange.getValues();
// Fetch email message details.
var detailsRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Notification Rules").getRange("G2");
var details = detailsRange.getValues();
var subjectdetailsRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Notification Rules").getRange("H2");
var subjectdetails = subjectdetailsRange.getValues();
// Send Alert Email.
var message = details;
var subject = subjectdetails;
MailApp.sendEmail(emailAddress, subject, message);
}
}
Update:
As you said in a comment, you want the email to be sent when you edit an inventory cell, and only if this edited inventory quantity is below the corresponding minimum. So here I update my answer accordingly.
First, I guess you have done this already, but because the function uses sendEmail, you will have to grant authorization for it to work. I created a trigger for that. Run this once:
function createEditTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("CheckInventory")
.forSpreadsheet(ss)
.onEdit()
.create();
}
Then, this is the function that will run every time the spreadsheet is edited. To avoid the email to be sent every time the file is edited, we need a condition that checks whether the edited cell is an inventory and that this inventory is below the minimum:
function CheckInventory(e) {
var ss = e.source;
var inventorySheet = ss.getSheetByName("Inventory");
var rowIndex = e.range.getRow();
var columnIndex = e.range.getColumn();
var numCols = 6;
var row = inventorySheet.getRange(rowIndex, 1, 1, numCols).getValues()[0];
var editedInventory = row[5];
var editedMinimum = row[3];
var sheetName = ss.getActiveSheet().getName();
// Checking that: (1) edited cell is an inventory quantity, and (2) Inventory is below minimum
if(editedInventory <= editedMinimum && sheetName == "Inventory" && columnIndex == 6 && rowIndex > 1) {
var inventoryValues = inventorySheet.getDataRange().getValues();
var emailBody = "";
for(var i = 1; i < inventoryValues.length; i++) {
var inventory = inventoryValues[i][5];
var minimum = inventoryValues[i][3];
if(inventory <= minimum) {
var productName = inventoryValues[i][0] + " " + inventoryValues[i][1];
var productUnits = minimum + " " + inventoryValues[i][4];
var messagePart1 = "Inventory for " + productName + " has gone under " + productUnits + ". ";
var messagePart2 = "Organise purchase order. Inventory as of today is: " + inventory + " " + inventoryValues[i][4];
var message = messagePart1.concat(messagePart2);
var newItem = "<p>".concat(message, "</p>");
emailBody += newItem;
}
}
var emailSubject = "Low inventory alert";
var emailAddress = "your-email#your-domain.com";
// Send Alert Email
if(emailBody != "") {
MailApp.sendEmail({
to: emailAddress,
subject: emailSubject,
htmlBody: emailBody
});
}
}
}
As I said in a comment, if you just want to send an email, it doesn't make sense to have many email subjects, so I hardcoded the subject.
Regarding the emails, I assumed you just want an email address to receive the email, so I hardcoded it too. If you want all the different email addresses found in Notifications tab to receive emails regarding all products, a small fix would be needed to this code. Tell me if that's needed for you.
Also, I didn't use your notifications tab at all, I created the message directly using the script. I'm not sure it is that useful to have the sheet "Notification Rules". Much of its info is the same as the one in inventory, and the rest of data (email address, basically) could be easily included there. But whatever suits you.
I hope this is of any help.
I have been trying to retrofit an old code I have used to send emails before to send an email when the formula solution in a cell equals today's date in another cell.
Here is my code:
function sendtest(e) {
var ss = e.source;
var s = ss.getSheetByName("Test");
var r = e.range;
// Below is the line that selects what column to use for the send date
var actionCol = 2;
var colIndex = r.getColumnIndex();
// Testing if statement
if (e.value == s.getRange(2, 3).getValue () && colIndex == actionCol) {
// All rows below are used to send the email
var row = r.getRowIndex();
// This takes the email addresses in column D
var userEmail = s.getRange(row, 4).getValue ();
//The subject line of the email
var subject = "Test test " + s.getRange(row, 1).getValue ();
//The structure of the body of the email
var body = "It has been two weeks since test test, " + s.getRange(row, 1).getValue ();
body +="\n\ntest test?";
body +="\n\ntest test,";
body +="\n\ntest test";
// This line sends the email
MailApp.sendEmail(userEmail,subject,body);
}
}
EDIT: Sorry I forgot to state what is going wrong. Every time I attempt to trigger this script (time based), I get an error telling me that line 3 (get sheet by name) is undefined.
Google Sheets Script
I need to generate an auto email reply when Column "A" is marked "Completed". The email address to send this to is in Column "I" and subject of the email needs to be data in Column "H" while the body of the email will be generic for all emails sent. This is all specific to each Row.
I have multiple scripts running, for hiding rows etc, but nothing this complex.
All data is sent in to spreadsheet from Google Forms, and will need to encompass all rows
Any help would be much appreciated.
I created a script for something similar to this, except it runs off of check boxes. You could easily edit this code to have the email recipient variable to point to a value in a column by adding a .getdisplayvalue
How I used it is basically just as a script trigger, so I wouldn't have it replace the "progress" column you have, but to add a column for them to check when they're done editing the row.
Side Note: This script purposefully sets the check box back to default after clicking "yes I want to send the email" on the alert, otherwise the script would continuously run.
Without seeing your Google Sheet or current code/this code inserted, I wouldn't be able to help you implement at all. Let me know if this helps.
/*
A function to:
* After clicking a checkbox, auto prompt a yes/no box
* Upon "yes", copies that row from the source sheet to a destination sheet
* send an e-mail based on that new row's data
I reccomend protecting the response sheet and hiding it, as well as protecting the check box column to give edit access to only those you want to be able to send e-mails.
NOTES:
*It is important that the headers on your source sheet match your destination sheet.
* You have to run the script from the editor first to accept permissions for the emailapp and driveapp
* you need to set up a project trigger (edit/current project triggers) for the source sheet, on spreadsheet, on edit.
*The email will come from the owner of the google sheet and owner of the script project. (the person who reviews and accepts permissions)
MAKE SURE you are the owner of the sheet, that you are putting the code into the editor, and that you're okay with the e-mail coming from and replying to your email address.
*/
function EmailNotification(e) {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Assets'); //source sheet
var columnb = sheet.getRange('B:B'); //Column with check boxes
var columnbvalue = columnb.getValues();
var notifysheet = ss.getSheetByName('Responses'); //destination sheet
var data = [];
var rownum =[];
//Condition check in B:B (or check box column); If true copy the same row to data array
for (i=0; i<columnbvalue.length;i++) {
if (columnbvalue[i] == 'true') {
var columnb2 = sheet.getRange('B2:B');
columnb2.setValue('false');
// What you want to say in the pop up alert
var response = ui.alert('Hold Up!\n Are you sure you want to send an email to finance for this asset change?', ui.ButtonSet.YES_NO);
if (response == ui.Button.YES) {
data.push.apply(data,sheet.getRange(i+1,1,1,20).getValues());
//Copy matched ROW numbers to rownum
rownum.push(i);
//Copy data array to destination sheet
notifysheet.getRange(notifysheet.getLastRow()+1,1,data.length,data[0].length).setValues(data);
var activeRow = notifysheet.getLastRow();
var assetname = notifysheet.getRange(activeRow, 1).getDisplayValue(); // The number is the column number in the destination "responses" sheet that you want to include in the email
var owner = notifysheet.getRange(activeRow, 3).getDisplayValue();
var serial = notifysheet.getRange(activeRow, 9).getDisplayValue();
var podate = notifysheet.getRange(activeRow, 6).getDisplayValue();
var email = 'theiremail#gmail.com' //The email address in which you want to send the email notification to
var subject = 'Asset has changed department ownership!'
//Body of the email message, using HTML and the variables from above
var message =
'<br><br><div style="margin-left:40px;">Heads Up!</div>'
+'<br><br><div style="margin-left:40px;">An asset has changed department ownership.</div>'
+'<br><br><div style="margin-left:40px;"><h3 style="text-decoration: underline;">Asset Name:'+ assetname +'</h3></div>'
+'<div style="margin-left:40px;">New Departmet Owner: '+ owner +'</div><br>'
+'<div style="margin-left:40px;">Serial: '+ serial +'</div>'
+'<div style="margin-left:40px;">Purchase Date: '+ podate +'</div>'
+ '<br><br><div style="margin-left:40px;">ヽ(⌐■_■)ノ♪♬</div>';
MailApp.sendEmail(
email,
subject,
"",
{
htmlBody: message,
name: 'Sadie Stevens', //The name you want to email coming from. This will be in bold, while your e-mail address will be small in italics
});
}
}
}
}
Try it this:
function EmailNotification(e) {
var ui=SpreadsheetApp.getUi();
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet=ss.getSheetByName('Assets');
var columnb=sheet.getRange(1,2,sheet.getLastRow());
var columnbvalue=columnb.getValues();
var notifysheet=ss.getSheetByName('Responses');
var data=[];
var rownum=[];
for (var i=0;i<columnbvalue.length;i++) {
if (columnbvalue[i] == 'true') {
var columnb2=sheet.getRange(2,2,sheet.getLastRow()-1);
columnb2.setValue('false');
var response=ui.alert('Hold Up!\n Are you sure you want to send an email to finance for this asset change?', ui.ButtonSet.YES_NO);
if (response==ui.Button.YES) {
data.push(sheet.getRange(i+1,1,1,20).getValues());
rownum.push(i);
notifysheet.getRange(notifysheet.getLastRow()+1,1,data.length,data[0].length).setValues(data);
var activeRow=notifysheet.getLastRow();
var assetname=notifysheet.getRange(activeRow, 1).getDisplayValue(); // The number is the column number in the destination "responses" sheet that you want to include in the email
var owner=notifysheet.getRange(activeRow, 3).getDisplayValue();
var serial=notifysheet.getRange(activeRow, 9).getDisplayValue();
var podate=notifysheet.getRange(activeRow, 6).getDisplayValue();
var email='theiremail#gmail.com' //The email address in which you want to send the email notification to
var subject='Asset has changed department ownership!'
var message =
'<br><br><div style="margin-left:40px;">Heads Up!</div>'
+'<br><br><div style="margin-left:40px;">An asset has changed department ownership.</div>'
+'<br><br><div style="margin-left:40px;"><h3 style="text-decoration: underline;">Asset Name:'+ assetname +'</h3></div>'
+'<div style="margin-left:40px;">New Departmet Owner: '+ owner +'</div><br>'
+'<div style="margin-left:40px;">Serial: '+ serial +'</div>'
+'<div style="margin-left:40px;">Purchase Date: '+ podate +'</div>'
+ '<br><br><div style="margin-left:40px;">ヽ(⌐■_■)ノ♪♬</div>';
MailApp.sendEmail(email,subject,"",{htmlBody: message,name: 'Sadie Stevens'});
}
}
}
}
I am relatively new to programming, and have recently been working on a script to send emails from a google spreadsheet when a cell in a certain column is changed. The recipient is assigned based off of an email address in another column in the same row as the change. I am having difficulty getting my code to stop running after the first email. As it is, the script runs indefinitely (at least until I run out of emails for the day).
Here is the code:
function sendNotification() {
var sheet = SpreadsheetApp.getActiveSheet();
//Get Active cell
var mycell = sheet.getActiveSelection();
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
var address = sheet.getRange("C" + cellrow).getValue();
var streetAddress = sheet.getRange("F" + cellrow).getValue();
var startRow = 2;
var numRows = 2000;
// Fetch the range of cells A2:O2000
var dataRange = sheet.getRange(startRow, 1, numRows, 15)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = address; // First column
var message = streetAddress +" Has been Submitted for permitting!"; // Second column
var subject = "The above Address has been Submitted For Permitting! We will Follow up with you when it has been approved.";
//Check to see if column is H to trigger
if (cellcol == 8 && sheet.getName() == "Sheet1" && mycell !== "")
{
//Send the Email
MailApp.sendEmail(emailAddress, message, subject);
}
//End sendNotification
}
}
What can I do to resolve this? Would a loop be the best option? How would I implement this?
How about this approach?
var EMAIL_SENT = "EMAIL_SENT";
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var mycell = e.range;
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
var emailAddress = sheet.getRange("C" + cellrow).getValue();
var streetAddress = sheet.getRange("F" + cellrow).getValue();
var subject = "The above Address has been Submitted For Permitting! We will follow up with you when it has been approved."
// Fetch values for each row in the Range
var message = streetAddress +" Has been Submitted for permitting!";
var emailSent = sheet.getRange("O" + cellrow).getValue();
if ( cellcol == 8 && sheet.getName() == "Sheet1" && emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(cellrow, 15).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
If you use the onEdit() the function will be triggered every time you edit the cell. Is this what you want?
What I assume you're looking for is a script that:
Reads every row of the active sheet
If the 8th column is not empty, sends an e-mail to the address in the first column
The whole script is trigger upon the user requests (not when the user edits a cell)
In this case the first approach is better, the sendNotification(). Also a loop is necessary to read all the rows. And the IF statement should be something like if (row[8] != "") then send the e-mail.
In this case row which was defined as row = data[i] in your first script will have the values of all the cells in the row being read in the loop. So row[8] will have the value of the 8th (column H), which you want to check for emptiness, thus if(row[8] != "").
Also, if I understand correctly the e-mail adress should be emailAddress = row[1] inside the loop, because the email address is different every row.
Your second approach var EMAIL_SENT = "EMAIL_SENT"; is almost similar to the simple extension of the code that sets the cells in a column to 'EMAIL_SENT' for each row after sendEmail is called given in Section 2: Improvements. Within tutorial, each cell was marked in each row every time an email is sent. With that, you should mark edited cells as unsent then you will be able to re-run the script later on, avoid sending email duplicates and will only send the edited cells.
To make your code more efficient and help you improve the performance of your scripts, there are also list of best practices given.