I have a Google Spreadsheet with 4 columns including Products, Salesperson, Category and Status. What I am trying to reach is whenever a user choose Yes option on Status column and if that product category is also G, then sending an email using the MailApp.
The e-mail should include the product value as well.
So far, I was able to sending an email. But I've really confused about the offset concept here and was not able to send the product in the email
The spreadsheet: https://docs.google.com/spreadsheets/d/1wVr0SGryNNvorVdDZEY1E6UDgh25_A5A2LhN1UNbIHE/edit?usp=sharing
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getName();
var r = sheet.getActiveCell();
var cell = sheet.getActiveCell().getA1Notation();
if(ss.getActiveCell().getColumn() !== 5) return;//
var row = sheet.getActiveRange().getRow();
var cellvalue = sheet.getActiveCell().getValue().toString();
var prod = sheet.getRange().offset(0, -2).getValues();
var cat = cellvalue.offset(0, -1).getValues();
var recipients = "email#email.com";
var message = '';
if(cellvalue === 'Yes' && cat === 'G') {
message = cell + ' in Sheet ' + sheetName + ' was changed to YES.';
var subject = 'Cell Changed to YES';
var body = message + ss.getUrl() + ' to view the changes' + prod;
MailApp.sendEmail(recipients, subject, body);
}
}
It's probably easier to use the object passed with the onEdit event instead of manipulating active cells and offsets.
This event object gives you the new value, so you can check if it is the one that you want ('Yes'). It also gives you the range that was edited, so you can use it to check if the change was in the correct column ('D') and to get the row that was modified. Once you have the row, you can use it to get the values of the other columns ('Products' and 'Cat') in that row.
Something like this should work:
function onEdit(event) {
const statusColumnNumber = 4; // Indices of rows and columns start from 1, so column D is 4.
if (event.range.getColumn() === statusColumnNumber && event.value === 'Yes') {
const sheet = event.range.getSheet();
const rowValues = sheet.getRange(event.range.getRow(), 1, 1, sheet.getLastColumn()).getValues().flat();
const categoryColumnIndex = 2; // Indices of JavaScript arrays start from 0, so column C is in position 2 of the array.
if (rowValues[categoryColumnIndex] === 'G') {
const prodColumnIndex = 0;
const prodValue = rowValues[prodColumnIndex];
const recipients = "email#email.com";
const subject = 'Cell Changed to YES';
const message = event.range.getA1Notation() + ' in Sheet ' + sheet.getName() + ' was changed to YES. '
const body = message + '\n' + sheet.getParent().getUrl() + ' to view the changes for ' + prodValue;
MailApp.sendEmail(recipients, subject, body);
}
}
}
As mentioned in the comments of your question, since you use a service that needs permissions (MailApp), you'll need to create an installable trigger that calls this function.
Related
I am new to coding scripts in google and come into a problem I can not work through and my script "mentor" is still not that experienced and can't figure it out either.
I am trying to update a different tab on my sheet from a pivot table when I use my script to send out bulked emails.
So the link below will bring you to the dummy sheet built off my real sheet. The 'PM' tab column L is what I am trying to update. It starts at 1 on all jobs. The emails are sent out by the Blue button on the next tab 'Follow up email' (this is just a pivot table so I can always adjust who is getting the emails easily). But I cant figure out how to have it update the 'PM' tab with the button at the same time as the emails go out.
Link to the open shared spreadsheet. Feel free to play around if you can help.
https://docs.google.com/spreadsheets/d/1_hipIj4suI2xMGUrZhMTBDvkQv9Y9O3JRNNQUpSeAP0/edit?usp=sharing
(only got the emails to send properly so far)
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var rows = sheet.getLastRow()
var dataRange = sheet.getRange(2, 1, rows-1, 7);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[1]; // Second column
var message = 'Hello, we have submitted this job ' + row[2] + ' days Ago. ' + row[4] + ' \n\n' + ' -' + row[5];
var subject = row[0]; // First column
MailApp.sendEmail(emailAddress, subject, message);
}
}
I need the button to send out emails on the 'Follow up email' tab and at the same time "email counter" (column L) would get 1 added to it on the 'PM' Tab. This way I can keep track of how many times that job was emailed from the sheet.
Try this code:
function sendEmails() {
var pmSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("PM");
var emailSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Follow up email");
var startRow = 2; // First row of data to process
var rows = emailSheet.getLastRow()
var dataRange = emailSheet.getRange(2, 1, rows-1, 7);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[1]; // Second column
var message = 'Hello, we have submitted this job ' + row[2] + ' days Ago. ' + row[4] + ' \n\n' + ' -' + row[5];
var subject = row[0]; // First column
MailApp.sendEmail(emailAddress, subject, message);
updatePM(pmSheet, emailAddress);
}
}
function updatePM(sheet, email){
var value;
var emails = sheet.getRange("G3:G" + sheet.getLastRow()).getValues();
for (var i = 0; i < emails.length; i++)
if (emails[i][0] == email){
value = sheet.getRange("K" + (i+3)).getValue() + 1
sheet.getRange("K" + (i+3)).setValue(value);
}
}
I changed the way you got the sheets just to be safe, then I just wrote a small function that gets called after the email is sent, which checks the list of emails in the PM sheet and then updates the value in the sent email column.
I have read a lot of onEdit and Triggers script but still I cannot achieve what I want to achieve, I code a lot in excel VBA and google sheet is very different. So the thing is based on my screenshot, what I want is to send an email once the cell contains "Approved", "denied", "In progress" and the email address must be based on the parallel of the edited cell. I'm dying to get this work done.
The code is based on the internet but I cannot tweak it based on my data/sheet.
You can add a custom function to a dropdown menu in the Spreadsheets UI with the following script. This will allow you to circumvent the onEdit() restriction that doesn't allow one to use the MailApp class, but it is at the cost of having users manually call the script instead of the script running automatically.
Here the user will select "Send E-Mail" from the dropdown menu, and it will prompt him/her for the Primary Key via an input prompt modal. The row of the corresponding key will be identified and an e-mail sent out after status is automatically changed to "approved". This script assumes that the spreadsheet contains at least four columns with header rows "Primary Key", "Description", "Email", and "Status" in any order.
Please note: this code was tested successfully. Please update lines 20 and 21 by replacing the square brackets and text contained therein that defines sheetURL and workSheetName variables.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('Send E-Mail', 'sendEmail')
.addToUi();
}
function sendEmail(){
// Display a dialog box with a title, message, input field, and "OK" and "Cancel" buttons. The
// user can also close the dialog by clicking the close button in its title bar.
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Pop-Up Prompt', 'Please enter primary key:', ui.ButtonSet.OK_CANCEL);
// Process the user's response.
if (response.getSelectedButton() == ui.Button.OK) {
Logger.log('The user entered the following primary key:', response.getResponseText());
// Map the header rows in order that column position is not hard-coded.
var sheetURL = '[ENTER YOUR SHEET URL HERE]';
var workSheetName = '[ENTER YOUR WORKSHEET NAME HERE]';
var sheet = SpreadsheetApp.openByUrl(sheetURL).getSheetByName(workSheetName);
var lastColumn = sheet.getLastColumn();
var headerRange = sheet.getRange(1, 1, 1, lastColumn);
var headers = headerRange.getValues();
for (var i=1; i<headers[0].length+1; i++) {
switch (headers[0][i-1]){
case "Primary Key":
var primaryKeyIndex = i;
break;
case "Description":
var descriptionIndex = i;
break;
case "Email":
var emailIndex = i;
break;
case "Status":
var statusIndex = i;
break;
}
}
// Header rows mapped.
// Search for row corresponding to primary key.
var primaryKey = response.getResponseText();
var keyRow = findInColumn(columnToLetter(primaryKeyIndex), primaryKey);
if (keyRow == -1){
ui.alert('Primary Key "'+ primaryKey + '" not found.');
} else {
ui.alert('Primary Key "'+ primaryKey + '" found at row: ' +keyRow+ '.');
sheet.getRange(keyRow, statusIndex).setValue("Approved");
//Prepare Email
var subject = "test";
var email = sheet.getRange(keyRow, emailIndex).getValue();
var body = "Hi, \n\n Your entry with primary key " + primaryKey + " is now approved.";
MailApp.sendEmail(email, subject, body);
}
} else if (response.getSelectedButton() == ui.Button.CANCEL) {
Logger.log('The user clicked cancel.');
} else {
Logger.log('The user clicked the close button in the dialog\'s title bar.');
}
}
// Helper function to find corresponding row to data in column.
function findInColumn(column, data) {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var column = sheet.getRange(column + ":" + column); // like A:A
var values = column.getValues();
var row = 0;
while ( String(values[row]) && String(values[row][0]) !== String(data) ) {
row++;
}
if (String(values[row][0]) === String(data))
return row+1;
else
return -1;
}
// Helper function to convert Column Number to Column Letter
function columnToLetter(column){
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
I'd suggest that you not use the onEdit trigger for sending email. I think it's over used by many users. If you are, you will have to go with the installable triggers. This is an example email solution that looks pretty clean that came in yesterday.
You can use most of this code below. Modify the email portions to suit your needs.
This code checks for sheet name to be 'Form Responses' and edited column header to be 'Status' as from pics given above.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var aSheet = ss.getActiveSheet();
// check sheet name
if (aSheet.getName() != 'Form Responses') return;
var range = ss.getActiveRange();
var row = range.getRow();
var col = range.getColumn();
// Logger.log(col);
var headers = aSheet.getRange(1,1,1,aSheet.getLastColumn()).getValues()[0];
// Logger.log(headers[col-1]);
// check column header
if (headers[col-1] != 'Status') return;
var value = range.getValue();
var values = ["approved", "denied", "in progress"]; // values to check for
// check values
if (values.indexOf(value.toString().toLowerCase()) == -1) return;
// Logger.log(row);
var rowValues = aSheet.getRange(row, 1, 1, aSheet.getLastColumn()).getValues()[0];
Logger.log(rowValues);
// change as necessary
var recipient = rowValues[1]; // email is in 2nd column
var body = 'Email body'; // create body
var subject = 'Test'; // set subject
// send email
MailApp.sendEmail(recipient, subject, body);
}
Just started my adventure with apps-script and im already stuck.
I'm trying to write script that triggers when any cell in my table is edited , check if that cell is in specific range ( entire column "O"), then gets cell row and sends mail to person bounded with that row.
As long as I got first and last part, I'm having trouble with checking if that range contains cell :
var cell = get.ActiveCell();
var range = ss.getRange("O:O");
However there are few similar columns with similar values, and i want to check this one only so far i got something like that
var ss = getActiveSpreadsheet();
var sheet = ss.getSheetByName("zamówienia");
var cell = get.ActiveCell();
var range =ss.getRange("O:O");
while (i != range.lenght){
if (cell != range[i]) {
i++;
}
else {
break;
return 1;
}
}
You should be using the onEdit() simple trigger, and then you can use the associated event object.
Example:
// This will show a pop up in your spreadsheet whenever you edit a cell in Column O of any sheet
function onEdit(e) {
var columnO = 15;
if (e.range.getColumn() === columnO) {
Browser.msgBox("Column O");
}
}
Got it like that if anybody's trying to sort out same problem. Added on edit simple trigger
function sprawdzenie(){
var ss = SpreadsheetApp.getActive();
var activeRow = ss.getActiveCell().getRow();
var activeCol = ss.getActiveCell().getColumn();
if (activeCol === 13){
var klient = SpreadsheetApp.getActiveSheet().getRange("c"+activeRow).getValue();
var data_wys = SpreadsheetApp.getActiveSheet().getRange("H"+activeRow).getValue();
var numer_oferty = SpreadsheetApp.getActiveSheet().getRange("E"+activeRow).getValue();
var kolor = SpreadsheetApp.getActiveSheet().getRange("B"+activeRow).getValue();
var prowadzacy = (SpreadsheetApp.getActiveSheet().getRange('AL'+activeRow).getValue() );
var zejscie = SpreadsheetApp.getActiveSheet().getRange("M"+activeRow).getValue();
var temat = ('Zejście z produkcji ' + numer_oferty + ' wysłanej dnia ' + data_wys);
var wiadomosc = (' Oferta o numerze :' + numer_oferty + ' ' + klient + ' w kolorze : ' + kolor + ' zeszła z dniem : ' + zejscie);
MailApp.sendEmail(prowadzacy, temat, wiadomosc);}
In an attempt to automate some of my work, I am beginning to learn basics of google scripts.
I have a spreadsheet in which I want to send an email notification when data is input into one column or another. There are also two tabs within this spreadsheet in which I would like this to occur.
The current result from the script is an email on the second 'sendnotification' function.
Question: How do I get the script to consider both functions?
I know this code can be condensed by likely using an IF fucntion in a better way but I am at a loss.
For some context: This is used in a manufacturing operation. The production is done by an offsite company and when they enter quantity into column 10 on either sheet, I want it to send a group of people an email that I work with. Similarly, when the product quality testing is done I want to be able to input into Column 12 and it send the offsite company an email.
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//Get Active cell
var mycell = ss.getActiveSelection();
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
//Define Notification Details
var recipients = "ryan.helms#company.com";
var subject = "Disc production was entered on the "+ss.getName();
var body = ss.getName() + " has been updated with an amount produced. Visit " + ss.getUrl() + " to view the quantities entered.";
//Check to see if column is A or B to trigger
if (cellcol == 10)
{
//Send the Email
MailApp.sendEmail(recipients, subject, body);
}
//End sendNotification
}
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//Get Active cell
var mycell = ss.getActiveSelection();
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
//Define Notification Details
var recipients = "ryan.helms#company.com";
var subject = "A lot of disc has been RELEASED by XYZ Company";
var body = ss.getName() + " has been updated with a lot of disc that were released by XYZ Company. Visit " + ss.getUrl() + " to view this updated information.";
//Check to see if column is A or B to trigger
if (cellcol == 12)
{
//Send the Email
MailApp.sendEmail(recipients, subject, body);
}
//End sendNotification
}
You'll need to set up an onEdit installable trigger (if you haven't already) and assign it to the following function:
function onEditEmailSender(e) {
var sheetName = e.range.getSheet().getName();
if (sheetName === "tab1" || sheetName === "tab2") {
var col = e.range.getColumn();
if (col === 10)
//send col 10 email
else if (col === 12)
//send col 12 email
}
}
The onEdit trigger passes a parameter with all sorts of information, the most useful in your case being e.range. This Range object corresponds to the cell that was edited to trigger the onEdit event. You can use it to get the name of the sheet (what you call tab) and the column that was edited.
Using that information you can send the appropriate email. Good luck!
I am trying to create a script that triggers a notification whenever a value is changed in a specific column of a Google Spreadsheet. Ideally, I would like to trigger notifications to other people, each based on changes to specific columns.
I have a test spreadsheet here:
https://docs.google.com/spreadsheets/d/1V4X1FNtYKbXhha84MzeU8kI57ck246WfvSluHlsP1eo/edit?usp=sharing
And have found a script for a custom notification elsewhere in the answers on SO. I took that and tweaked it until I got this:
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = ss.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var column = sheet.getActiveRange().getColumn();
var colLetter = columnToLetter(column);
var cellvalue = ss.getActiveCell().getValue().toString();
var recipients = "email#domain.org";
var message = '';
if(cell.indexOf('G')!=-1){
message = sheet.getRange('F'+ sheet.getActiveCell().getRowIndex()).getValue()
}
var subject = 'Update to Notification TEST Sheet';
var body = 'Sheet ' +sheet.getName() + ' has been updated. Visit ' + ss.getUrl() + ' View the changes in row ' + row + ', column ' +colLetter+ '.';
MailApp.sendEmail(recipients, subject, body);
};
function columnToLetter(column) {
var temp, letter = '';
while (column > 0)
{
temp = (column - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column = (column - temp - 1) / 26;
}
return letter;
}
function letterToColumn(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
};
Once you change the receipient email, the script runs, but sends a notification for any change in any cell, not for cells with a specific column.
Can anyone help me get it to do what I am looking for?
TIA!
Imagine your trigger event is, onEdit(e)
function onEdit(e)
{
var range = e.range;
var column = range.getColumn();
if(column == `your expected column number`)
{
// call your send notification function
sendNotification();
}
}
You can read about triggers more. Event Objects