I am trying to get a script working that hooks into a google sheet, pulls information that is taken of the phone, and sends it via email once marked. So far I have this, from sources on the internet and a bit of customising.
function sendApprovalEmail() {
var sheetNameToWatch = "SHEETNAMEGOESHEREUSUALLY";
var columnNumberToWatch = 12; // column A = 1, B = 2, etc.
var valueToWatch = "SENT";
var date = 5;
var name = 9;
var number = 10;
var message = 11;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var emailAddress = "MYEMAILGOESHEREUSUALLY";
var subject = "Missed Call Notifcation";
var email = "Hello! "+date+" "+name+" "+number+" "+message+"";
MailApp.sendEmail(emailAddress, subject, email);
}
}
The above works, triggers, and sends properly. The only thing it doesn't do is suck in the Date, Name, Number and Message.
These need to be unique for each email, based on the line that was just marked as SENT. Usually, there are only a couple a day, never at the same time.
So if Row 23 is marked as SENT, it needs A23, B23, and C23.
If row 66 is marked as SENT, it needs A66, B66, and C66.
How do I get the script to look up values in column 5, 9, 10 and 11 OF THE ROW that it has detected 'SENT' in?
The code is using var range = sheet.getActiveCell() the get the active cell. Then you could use range.getRow() to get the row number, then you could use something like sheet.getRange(range.getRow(), columnNumber) to get the desired cells where columnNumber could be 5, 9, 10 and/or 11. In other words, instead of
var date = 5;
use
var date = sheet.getRange(range.getRow(), 5).getValue();
but put the above line after
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
Do the same for the name, number and message variables.
Note: There are other more efficient ways like using sheet.getDataRange().getValues() which will return an array of arrays having all the sheet values, the use
var date = data[range.getRow()][5];
and so on.
This is probably close to what your looking for:
First you have to settle on a format for your spreadsheet so that all operators will record the information in a standard format. I used the following format for each of my sheets.
All of the sheets used for recording information start with the prefix of 'ph:'. I get the entire array of sheets and I loop through them looking for the sheets that begin in 'ph:' name.slice(0,3). Once found I get the range of A1:B6 and collect all of the data into one array and then loop through the array putting all of the information into an associative array using the following algorithm dObj[value in column1]=value in column2. So in my example you can get the name with dObj.Name and the message is obtained by using dObj.Message and so on. So this associates the key in column one with the value in column2.
Now here is the code:
function sendApprovalEmails(){
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
for(var i=0;i<shts.length;i++){
var sh=shts[i];
var name=sh.getName();
if(name.slice(0,3)=='ph:'){//finds the operator log sheets
var dObj={};
var rg=sh.getRange('A1:B6');//Use a fixed range so you can use the rest of the sheet for whatever
var vA=rg.getValues();
for(var j=0;j<vA.length;j++){
dObj[vA[j][0]]=vA[j][1];//Builds the associative array
}
if(dObj.Approval=='Yes'){
Logger.log('Send Email:\nDate: %s\nNumber: %s\nName: %s\nMessage: %s,To: %s',Utilities.formatDate(new Date(dObj.Date),Session.getScriptTimeZone(),"E MMM dd, yyyy"),dObj.Number,dObj.Name,dObj.Message,dObj.Email);
var recipient=dObj.email;
var subject="Missed Call Notification";
var body = Utilities.formatString('Hello! %s %s %s %s',Utilities.formatDate(new Date(dObj.Date),Session.getScriptTimeZone(),"E MMM dd, yyyy"),dObj.Name,dObj.Number,dObj.Message);
//MailApp.sendEmail(recipient, subject, body);
}
}
}
}
In my example B1 has a data validation of either Yes or No.
Of course this is probably just a starting point. You can create the code to copy a master sheet and open it up with each phone call. I don't know if there is a limit to the number of sheets but there is a a limit to the number of cells in one Spreadsheet.
Documentation Reference:
By the way this version of your code works.
function sendApprovalEmail() {
var sheetNameToWatch = "test";
var columnNumberToWatch = 1;
var valueToWatch = "SENT";
var date = 5;
var name = 9;
var number = 10;
var message = 11;
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName()==sheetNameToWatch && range.getColumn()==columnNumberToWatch && range.getValue() == valueToWatch) {
var emailAddress = "foundit#found.com";
var subject = "Missed Call Notifcation";
var email = Utilities.formatString('Hello! %s %s %s %s',date,name,number,message);
//MailApp.sendEmail(emailAddress, subject, email);
Logger.log('\nemailAddress: %s\nsubject: %s\nemail: %s',emailAddress,subject,email);
}
}
I don't like to send out a lot of useless emails while debugging so I just use the Logger to record the email information.
Related
I am using a spreadsheet to manage certification expiration dates. I want to send an email to an employee when their certification is expiring within 90 days. I only want to send one email. I am struggling getting the date from the cell and comparing it to today's date.
I want to send an email if Todays Date + 90 days in MS is > certification expiration date in MS.
I started using a template to prevent sending duplicate emails. I got it working with if && with words in two cells. I am struggling getting the dates to work. I have tried using getTime() to get the dates in MS but getValues().getTime returns an error.
var EMAIL_SENT = 'EMAIL_SENT';
var NintyDayInMs = 90*24*60*60*100;
var Today = new Date().getTime();
var expired = Today+NintyDayInMs;
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 4);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var emailSent = row[2]; // Third column
var exp = row[3]; // Fourth column
var expDate = exp.getTime();
if (emailSent != EMAIL_SENT && expDate < expired) { // Prevents
sending duplicates
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is
interrupted
SpreadsheetApp.flush();
}
}
}
My current code results in
TypeError: Cannot find function getTime in object (Date in cell).
(line 26, file "Code")
Read Adding Days to a Date - Google Script for a better understanding of date arithmetic in scripts.
The flaw is in trying to chain the expiry date. Instead of:
var exp = row[3]; // Fourth column
var expDate = exp.getTime();
use just:
var expDate = new Date(row[3]); // make the sheet value a date object
Then the rest goes naturally...
var expDate = new Date(row[3]); // make the sheet value a date object
Logger.log("expiry = "+expDate);
var today = new Date();
Logger.log("today = "+today);
var today90 = new Date(today.getTime()+90*3600000*24);// 90 days from today
Logger.log("today90 = "+today90);
if ((today90 > expDate) && (emailSent!=EMAIL_SENT)){
Logger.log("send the email");
}
else
{
Logger.log("don't send the email");
}
I have tried over and over to get this 'simple' script to work. I would like to scan over a column of dates and if a pre set 'days due' is today, it will then pull the email from the same row with a reminder message stating the task is due. For whatever reason, when I do this I cannot get multiple emails to fire to different owners and my loop keeps stacking the tasks due on the same day. I can SHARE SHEET HERE. any help is appreciated!!
function checkReminder() {
// get the spreadsheet object
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// set the first sheet as active
SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);
// fetch this sheet
var sheet = spreadsheet.getActiveSheet();
// figure out what the last row is
var lastRow = sheet.getLastRow();
// the rows are indexed starting at 1, and the first row
// is the headers, so start with row 2
var startRow = 2;
// grab column 5 (the 'days left' column)
var range = sheet.getRange(2,5,lastRow-startRow+1,1 );
var numRows = range.getNumRows();
var days_left_values = range.getValues();
// Now, grab the reminder name column
range = sheet.getRange(2, 1, lastRow-startRow+1, 1);
var reminder_info_values = range.getValues();
//Range A2:End of rows and columns
data = sheet.getRange(2, 6, lastRow-startRow+1,1);
//Now, grab the emails
var email_values = data.getValues();
//Logger.log(email_values)
//Logger.log(reminder_info_values)
//=======================Above this line works
fine====================================
for (k in email_values){
var row = email_values[k];}
//var emailAddress =row[5]
var warning_count = 0;
var msg = "";
// Loop over the days left values
for (var i = 0; i <= numRows - 1; i++) {
var days_left = days_left_values[i][0];
if(days_left == 7) {
// if it's exactly 7, do something with the data.
var reminder_name = reminder_info_values[i][0];
var emailAddress = row[6]
msg = msg + "Reminder: "+reminder_name+" is due in "+days_left+"
days.\n";
}
}
warning_count++;
if(warning_count) {
//MailApp.sendEmail(emailAddress,
//"Reminder Spreadsheet Message", msg);
Logger.log(emailAddress);
Logger.log(msg);
}
}
I have multiple projects that output daily data to their own Google spreadsheets. I would like to make one master sheet in which this data is captured. This is fairly easy to do using importrange, but the spreadsheet becomes very, very slow when a large quantity of data is imported like this, so I'm hoping to use a script to just copy and paste the data over.
I know how to do set up the script manually using the following code from another post:
var sourceSpreadsheetID = "ID HERE";
var sourceWorksheetName = "SHEET NAME HERE";
var destinationSpreadsheetID = "ID HERE";
var destinationWorksheetName = "SHEET NAME HERE";
function importData() {
var thisSpreadsheet = SpreadsheetApp.openById(sourceSpreadsheetID);
var thisWorksheet = thisSpreadsheet.getSheetByName(sourceWorksheetName);
var thisData = thisWorksheet.getDataRange();
var toSpreadsheet = SpreadsheetApp.openById(destinationSpreadsheetID);
var toWorksheet = toSpreadsheet.getSheetByName(destinationWorksheetName);
var toRange = toWorksheet.getRange(1, 1, thisData.getNumRows(), thisData.getNumColumns())
toRange.setValues(thisData.getValues());
}
But ideally, I would like to make the list easy to expand using an array. I've set up an "import" table (see the figure below), so I would guess a for loop running through it would allow me to do this, but I'm not sure how.
Image of table
I'd really appreciate any help you guys can offer. Thanks!
To answer my own question, I've managed to cobble the following together and it seems to work:
function importData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var keysSheet = ss.getSheetByName("Keys")
var targetSheet = ss.getSheetByName("Test")
var keys = keysSheet.getRange("B2:B50").getValues();
var sheets = keysSheet.getRange("C2:C50").getValues();
var ranges = keysSheet.getRange("D2:D50").getValues();
var row, startcolumn = 1;
for (row = 1; row < 50; row++) {
if (keys[row-1] != '' && sheets[row-1] != '' && ranges[row-1] != '') {
var sourceSpreadsheetID = keys[row-1];
var sourceWorksheetName = sheets[row-1];
var sourceDataRange = ranges[row-1];
var thisSpreadsheet = SpreadsheetApp.openById(sourceSpreadsheetID);
var thisWorksheet = thisSpreadsheet.getSheetByName(sourceWorksheetName);
var thisData = thisWorksheet.getRange(sourceDataRange);
var toRange = targetSheet.getRange(1, startcolumn, thisData.getNumRows(), thisData.getNumColumns());
toRange.setValues(thisData.getValues());
startcolumn = startcolumn + thisData.getNumColumns();
}
}
}
I am sure that this can be done more efficiently using arrays, a while loop (rather than a for loop), and a keys table range that updates automatically based on its size, but I couldn't figure out how to do that with my high school coding skills.
Hopefully what I've figured out so far will help someone else!
I'm using the following script to send email reminders from a Google Sheet, but would like to modify it so that it send the email out on a date specified in cell F of each row.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 999; // Number of rows to process
// Fetch the range of cells A2:B999
var dataRange = sheet.getRange(startRow, 1, numRows, 999)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var subject = row[1]; // Second column
var message = row[2]; // Third column
var emailSent = row[3];
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 4).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
That's what I have and any attempts to add a date in there have failed pretty badly.
I came across this earlier question: Google Apps Script - Send Email based on date in cell but was unable to combine it with my script.
The solution Serge provided in that previous answer sets the stage for you to have a very flexible script, able to use any portion of the date / time as a criteria for sending.
Here's a simpler and less flexible approach. Assumptions:
The date is in the spreadsheet as a date, not a string.
We only care that the date matches; hours, minutes and seconds are inconsequential.
The script and the reminder dates in the spreadsheet are based on the same timezone.
The magic here is all about comparing dates. A JavaScript Date object is a numeric representation of time elapsed from the start of 1970, Universal time. Comparing equality of dates then, is difficult. However, thanks to the assumption above, we only care about the date, which is helpful. To get around timezone concerns and eliminate the effect of hours, minutes, etc., we just use the same Date method to generate date strings from the date objects we want to compare. The toLocaleDateString() method adjusts for time zones for us.
Resulting script:
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails3() {
var today = new Date().toLocaleDateString(); // Today's date, without time
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 999; // Number of rows to process
// Fetch the range of cells A2:B999
var dataRange = sheet.getRange(startRow, 1, numRows, 999)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var subject = row[1]; // Second column
var message = row[2]; // Third column
var emailSent = row[3];
var reminderDate = row[5].toLocaleDateString(); // date specified in cell F
if (reminderDate != today) // Skip this reminder if not for today
continue;
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 4).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
I've been searching online all morning, and haven't been able to find what I want to do. I found a similar post on here, but couldn't figure out how to adapt it to my needs.
I'm a teacher, and I was thinking about how I could use Google Sheets to automatically email parents when their child's grade falls below a C in my class. I was able to quickly find the script to have Sheets send an email, and was wondering if it's possible to edit that script to have the email sent ONLY if the value in a specific cell is below 70.
Here's the script I found. I edited the subject line to read "Math Grade" (that was easy to figure out), but I'd like to edit it so that the email only gets sent if the value in cell D2 (or D3, D4, D5, etc) is below 70. (Column A has email, Column B has the message, Column C would have the student's name, and Column D would have their numerical grade.) I feel like it should be obvious, but my scripting knowledge is non-existent. Can anybody help?
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
var subject = "Math Grade";
MailApp.sendEmail(emailAddress, subject, message);
}
}
The code was only getting 2 columns of data, and it needs to get 4.
getRange(row, column, numRows, numColumns)
I added a line of code that gets how many columns are in the sheet. Then the for loop got an extra line of code to get the grade, and finally, an if conditional check was added.
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var numOfColumns = sheet.getLastColumn();
// Fetch the range of cells
var dataRange = sheet.getRange(startRow, 1, numRows, numOfColumns);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
var grade = "";
var i = 0;
for (i=0;i<data.length;i++) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = row[1]; // Second column
grade = row[3];
if (grade < 70) {
var subject = "Math Grade";
MailApp.sendEmail(emailAddress, subject, message);
};
};
};