Send email based on cell value (date) - date

I've looked around and have bits and pieces but can't put the puzzle together.
I need to send an email 90 days before a date contained in a list of cells in the same column.
This is what my data looks like:
For example, the script should send an email on 01/08/19 with the following text:
Reminder birthday Jon Doe 01/11/2019

Try this:
function send(){
var ss = SpreadsheetApp.getActiveSheet();
var firstDate = new Date(); // today
var data = ss.getRange("A6:C" + ss.getLastRow()).getValues(); // gets the name and the bday
for(var i = 0; i < data.length; i++){
if (time(firstDate, data[i][2]))
Logger.log("SEND"); // Here you would send the email.
else
Logger.log("NOT SENT");
}
}
function time(firstDate, secondDate){
var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
if (diffDays <= 90)
return true;
else
return false;
}
Here is where I found how to calculate the time difference. And my code is build assuming you have the list starting on A6.

I'm use this script for alert bank certificates expiration, yo can easy adapt for your problem, sorry but I Dont have not time to translate.
function Vencimiento() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lastRow = sheet.getLastRow();
lastRow = lastRow-4;
var rango = sheet.getRange(5, 2, lastRow, 4);
var valores = rango.getValues();
var inicio = Date.now();
for(var i = 0; i < lastRow; i++){
var vence = Date.parse(valores[i][2]);
var dif = Math.round((vence-inicio)/86400000) ;
switch (dif){
case 0:{enviaCorreo(valores[i][0],valores[i][1],valores[i][3],dif);break};
case 7:{enviaCorreo(valores[i][0],valores[i][1],valores[i][3],dif);break};
case 15:{enviaCorreo(valores[i][0],valores[i][1],valores[i][3],dif);break};
case 45:{enviaCorreo(valores[i][0],valores[i][1],valores[i][3],dif);break};
}
}
}
function enviaCorreo(empresa,cert,banco,dias){
var array = ["mail#gmail.com", "mail#gmail.com"];
if(dias == 0){
var str = ("El día de hoy se vencio el certificado nro: "+cert+" del banco "+banco);
Mail(array,str);
}else{
var str = ("Restan "+ dias+" para que se venza el certificado nro: "+cert+ " del banco "+banco);
Mail(array,str);}
}
function Mail(destinatarios,mensaje){
var recipient = destinatarios;
var enviar = mensaje;
GmailApp.sendEmail(destinatarios, 'Alerta Certificado bancario', enviar);
}

Related

BCC doesn't seem to function as an option of sendEmail - name and replyTo work though

function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Welcome");
var targetSheet = ss.getSheetByName("Done");
var startRow = 2;
var lr = sheet.getLastRow();
var dataRange = sheet.getRange(startRow, 1, lr-1, 6);
var data = dataRange.getValues();
var colNumber = sheet.getLastColumn()-1;
var delRows = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
var id = row[0];
var emailAddress = row[1];
var date = row[2];
var city = row[3];
var bccmail = row[6];
var Sender = 'XXXXXX';
var reply = 'xxxxxx#xxxxxxx.com';
if (emailAddress.match('#') === null){
continue;
};
var subject = row[4];
var message = "Hey " + id + ", welcome in the team " + row[5];
MailApp.sendEmail(emailAddress, subject, message, {bcc: bccmail,name: Sender,replyTo: reply});
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
var sourceRange = sheet.getRange(i+startRow, 1, 1, colNumber);
sourceRange.copyTo(targetRange);
delRows.push(i+startRow);
}
delRows.reverse().forEach(ri=>{sheet.deleteRow(ri)});
Almost all the script works fine. When it comes to sendEmail, I have tried to follow these guidelines and use sendEmail(recipient, subject, body, options). 2 out of 3 options work fine but BCC doesn't work at the moment. Do you know what I am doing wrong? Can BCC be a variable?
The problem is in this line:
var bccmail = row[6];
dataRange is defined as a range with only 6 columns. data is a 2D array with the values of dataRange. row is a 1D array with a single row of data. JavaScript array indexes only start at 0, so the values are in row[0] to row[5].
Please check your sheet in which column does the bcc string is defined and count the index from 0.
Reference:
Arrays in JavaScript

Send email when any value is input into first column Google Script

I'm looking to send an email to the recipient (clientEmail) when data is added to the first column of that specific row. The data in the first column would be a mix of numbers and letters. I've tried different methods using the following code but can never get it to send only when the value in the first column contains a value.
var EMAIL_DRAFTED = "EMAIL DRAFTED";
function draftMyEmails() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active
sheet
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 0; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var clientName = row[1]; // Col B: Client name
var clientEmail = row[2]; // Col C: Client email
var message1 = row[3]; // Col D: First part of message
var message2 = row[4]; // Col E: Second part of message
var emailStatus = row[lastColumn - 1]; // Col F: Email Status
// Prevent from drafing duplicates and from drafting emails without a recipient
if (emailStatus !== EMAIL_DRAFTED && clientEmail) {
// Build the email message
var emailBody = '<p>Hi ' + clientName + ',<p>';
emailBody += '<p>' + message1 + ', your requested data, ' + message2 + ', is ready.<p>';
//Send the emaiil
MailApp.sendEmail(
clientEmail, // Recipient
'Here is your data', // Subject
'', // Body (plain text)
{
htmlBody: emailBody // Options: Body (HTML)
}
);
sheet.getRange(startRow + i, lastColumn).setValue(EMAIL_DRAFTED); // Update the last column with "EMAIL_DRAFTED"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
}
}
}
Start off by changing your for loop, know the difference between ++i and i++, in this case you'd want to use the latter. See: difference between ++i and i++.
for (var i = 0; i < data.length; i++) {
All you need to do after that is add a check in your if statement for the column in question. Note: you could define this separately like you've done for the other variables. I'll provide 2 examples and you can pick which you'd prefer to use, both will function the same.
//option 1
if (emailStatus !== EMAIL_DRAFTED && clientEmail && row[0]) {
//option 2
var checkData = row[0];
if (emailStatus !== EMAIL_DRAFTED && clientEmail && checkData) {
In the end your code should look something like this:
var EMAIL_DRAFTED = "EMAIL DRAFTED";
function draftMyEmails() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn); // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 0; i < data.length; i++) {
var row = data[i];
// Assign each row a variable
var clientName = row[1]; // Col B: Client name
var clientEmail = row[2]; // Col C: Client email
var message1 = row[3]; // Col D: First part of message
var message2 = row[4]; // Col E: Second part of message
var emailStatus = row[lastColumn - 1]; // Col F: Email Status
// Prevent from drafing duplicates and from drafting emails without a recipient
if (emailStatus !== EMAIL_DRAFTED && clientEmail && row[0]) {
// Build the email message
var emailBody = '<p>Hi ' + clientName + ',<p>';
emailBody += '<p>' + message1 + ', your requested data, ' + message2 + ', is ready.<p>';
//Send the emaiil
MailApp.sendEmail(
clientEmail, // Recipient
'Here is your data', // Subject
'', // Body (plain text)
{
htmlBody: emailBody // Options: Body (HTML)
}
);
sheet.getRange(startRow + i, lastColumn).setValue(EMAIL_DRAFTED); // Update the last column with "EMAIL_DRAFTED"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
}
}
}

Deleting a row based on date - Date values

My query relates to this Google Form responses spreadsheet. I'm trying to adapt the script I got from here.
function cleanup() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form responses 1');
var values = sheet.getDataRange().getValues();
var InAYear = (Date.now()/86400000 + 25569) + 365;
for (var i = values.length - 1; i >= 0; i--) {
if ( values[i][5] >= InAYear) {
sheet.deleteRow(i+1);
}
}
}
I'm trying to get this to compare the date in the Start Date column of the sheet with the date in a year from now and delete the row if the column entry is greater than this (ie. if the date on the sheet is more than a year in advance). However, I obviously don't understand how to get the two different dates in the same format because examining variable values when debugging shows wildly different values.
Try the following script code:
function cleanup() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Form responses 1');
var values = sheet.getDataRange().getValues();
var today = Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), 'MM/dd/yyyy')
for (var i = values.length - 1; i >= 0; i--) {
if ( values[i][4] != '' && dateDiffInDays(values[i][4],today) > 365 ) {
sheet.deleteRow(i+1);
}
}
};
function dateDiffInDays(d1,d2) {
var date1 = new Date(d1);
var date2 = new Date(d2);
var timeDiff = date1.getTime() - date2.getTime();
return Math.ceil(timeDiff / (1000 * 3600 * 24));
};
It looks like I have it working, and sending me an email.
function cleanup(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Form responses 1');
var values = sheet.getDataRange().getValues();
var today = new Date();
var InAYear = new Date();
InAYear.setFullYear( today.getFullYear()+1 );
var emailaddress = "****";
var subject = "Annual Leave Request";
var message = "Annual Leave has been requested as follows:" + "\n\n";
for (var i = values.length - 1; i >= 0; i--) {
if ( values[i][4] > InAYear ) {
sheet.deleteRow(i+1);
subject = "Annual Leave Request - Rejected";
message = "The following annual leave request was rejected due to being more than one year in advance:" + "\n\n";
}
}
for(var field in e.namedValues) {
message += field + ':'
+ "\n" + e.namedValues[field].toString() + "\n\n";
}
MailApp.sendEmail(emailaddress, subject, message);
}
Thank you to Kishan, without who's help I would not have been able to get to this stage.

Calling a function from onEdit() trigger doesn't work

I want to run a function that updates some values when I edit one cell of a column. This line of the trigger works well: dataCell0.setValue(today_date(new Date())[2]);. But this other line updatePercent(); doesn't. But if I call this updatePercent() function from a time based trigger (in Resources), it works well. What is going wrong with this updatePercent() call?
function onEdit(){
var s = SpreadsheetApp.getActiveSheet();
if( ( s.getName() == "mySheet1" ) || (s.getName() == "mySheet2") ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( s.getRange(1, r.getColumn()).getValue() == "PORCENT_TIME") { // If you type a porcent, it adds its date.
var dataCell0 = r.offset(0, 1);
dataCell0.setValue(today_date(new Date())[2]);
updatePercent();
}
}
}
Here the updatePercent function code:
/**
* A function to update percent values accoding to input date.
**/
function updatePercent() {
var sheet = SpreadsheetApp.getActiveSheet();
var column = getColumnNrByName(sheet, "PORCENT_TIME");
var input = sheet.getRange(2, column+1, sheet.getLastRow(), 4).getValues();
var output = [];
for (var i = 0; i < input.length; i++) {
var fulfilledPercent = input[i][0];
Logger.log("fulfilledPercent = " + fulfilledPercent);
var finalDate = input[i][3];
Logger.log("finalDate = " + input[i][3]);
if ( (typeof fulfilledPercent == "number") && (finalDate instanceof Date) ) {
var inputDate = input[i][1]; // Date when input was added.
var restPorcentPen = 100 - fulfilledPercent;
var restantDays = dataDiff(inputDate, finalDate);
var percentDay = restPorcentPen/restantDays;
Logger.log("percentDay = " + percentDay);
var passedTime = dataDiff(inputDate, new Date());
Logger.log("passedTime = " + passedTime);
var passedPorcent = passedTime * percentDay; // How much percent this passed time is?
Logger.log("passedPorcent = " + passedPorcent);
var newPorcent = (fulfilledPercent + passedPorcent);
newPorcent = Math.round(newPorcent * 100) / 100;
Logger.log("newPorcent = " + newPorcent);
var newInputDate = hoje_data(new Date())[2]; // Now update the new input date
// newPorcent = newPorcent.toFixed(2);
output.push([newPorcent, newInputDate]);
sheet.getRange(2, column+1, output.length, 2).setValues(output);
Logger.log(" ");
var column25Dec = getColumnNrByName(sheet, "PORCENT_25DEZ");
var passedTimeSince25Dec = dataDiff(new Date(2013,11,25), new Date()); // Months: January is 0;
var decPercent = (newPorcent - (passedTimeSince25Dec * percentDay)); // .toFixed(2).replace(".", ",");
decPercent = Math.round(decPercent * 100) / 100;
// if (sheet.getRange(output.length+1, column25Dec+1).getValues() == ''){
sheet.getRange(output.length+1, column25Dec+1).setValue(decPercent );
// }
var remainingYears = dataDiffYears(new Date(), finalDate);
sheet.getRange(output.length+1, column).setValue(remainingYears);
}
else {
newPorcent = "Put a final date"
output.push([newPorcent, inputDate]);
sheet.getRange(2, column+1, output.length, 2).setValues(output);
}
if (finalDate instanceof Date){
var remainingYears = dataDiffYears(new Date(), finalDate);
// Logger.log("remainingYears = " + remainingYears);
}
else {
remainingYears = "insert a valid date";
}
sheet.getRange(output.length+1, column).setValue(remainingYears);
}
}
I will guess you're using the new gSheets. Check if it will work in the old-style sheets. The new sheets' onEdit trigger has problems, particularly with getActive.
My problem was in the updatePercent() funciton. Thank you, guys!

Google Apps Script : "if" loops with radio buttons & writing it in an existing spreadsheet

Using google apps script & google site, I'm trying to write down a form and get the answers in a spreadsheet.
Here is my work for now on :
function doGet(){
var app = UiApp.createApplication().setTitle('Radio Button Demo');
var radio1 = app.createVerticalPanel();
var radio11 = app.createRadioButton('group1','Oui').setName('oui1').setId('oui1');
var radio12 = app.createRadioButton('group1','Non').setName('non1').setId('non1');
radio1.add(radio11).add(radio12);
app.add(radio1);
var radio2 = app.createVerticalPanel().setId('question2').setVisible(false);
var radio21 = app.createRadioButton('group2','Oui').setName('oui2').setId('oui2');
var radio22 = app.createRadioButton('group2','Non').setName('non2').setId('non2');
radio2.add(radio21).add(radio22);
app.add(radio2);
var radio3 = app.createVerticalPanel().setId('question3').setVisible(false);
var radio31 = app.createRadioButton('group3','Oui').setName('oui3').setId('oui3');
var radio32 = app.createRadioButton('group3','Non').setName('non3').setId('non3');
radio3.add(radio31).add(radio32);
app.add(radio3);
var radio4 = app.createVerticalPanel().setId('question4').setVisible(false);
var radio41 = app.createRadioButton('group4','Cool').setName('oui4').setId('oui4');
var radio42 = app.createRadioButton('group4','Or not').setName('non4').setId('non4');
radio4.add(radio41).add(radio42);
app.add(radio4);
// handler to make value of question 1 change
var handler11 = app.createServerValueChangeHandler('showstatus1_1');
handler11.addCallbackElement(radio1);
radio11.addValueChangeHandler(handler11);
var handler12 = app.createServerValueChangeHandler('showstatus1_2');
handler12.addCallbackElement(radio1);
radio12.addValueChangeHandler(handler12);
// handler to make value of question 2 change
var handler21 = app.createServerValueChangeHandler('showstatus2_1');
handler21.addCallbackElement(radio2);
radio21.addValueChangeHandler(handler21);
var handler22 = app.createServerValueChangeHandler('showstatus2_2');
handler22.addCallbackElement(radio2);
radio22.addValueChangeHandler(handler22);
// handler to make value of question 3 change
var handler31 = app.createServerValueChangeHandler('showstatus3_1');
handler31.addCallbackElement(radio3);
radio31.addValueChangeHandler(handler31);
var handler32 = app.createServerValueChangeHandler('showstatus3_2');
handler32.addCallbackElement(radio3);
radio32.addValueChangeHandler(handler32);
// handler to make value of question 4 change
var handler41 = app.createServerValueChangeHandler('showstatus4_1');
handler41.addCallbackElement(radio4);
radio41.addValueChangeHandler(handler41);
var handler42 = app.createServerValueChangeHandler('showstatus4_2');
handler42.addCallbackElement(radio4);
radio42.addValueChangeHandler(handler42);
// functions to change values of question 1
function showstatus1_1(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.oui1
app.getElementById('non1').setValue(false);
app.getElementById('question2').setVisible(true);
return app;
}
function showstatus1_2(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.non1;
app.getElementById('oui1').setValue(false);
app.getElementById('question2').setVisible(true);
return app;
}
// functions to change values of question 2
function showstatus2_1(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.oui2
app.getElementById('non2').setValue(false);
return app;
}
function showstatus2_2(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.non2;
app.getElementById('oui2').setValue(false);
return app;
}
// functions to change values of question 3
function showstatus3_1(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.oui3
app.getElementById('non3').setValue(false);
return app;
}
function showstatus3_2(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.non3;
app.getElementById('oui3').setValue(false);
return app;
}
// functions to change values of question 4
function showstatus4_1(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.oui4
app.getElementById('non4').setValue(false);
return app;
}
function showstatus4_2(e){
var app = UiApp.getActiveApplication();
var radioValue = e.parameter.non4;
app.getElementById('oui4').setValue(false);
return app;
}
My first question is How to make question 3 and 4 visible based on the answers of question 1 and 2. I have found how to do it based on the answer of 1 question but I'm stuck with multiple questions.
For example : Make question 3 visible if the answer is "Oui" and "Oui", else make question 4 visible !
My second question is : How to get the value of the different questions ?
I would like to write in an existing spreadsheet the answers oof the different users, and also the choice. But i'm stuck when I try to find a way of getting the answers of users.
Thanks for helping me if you have time,
Vincent
radioButtons are a bit tricky in GAS... to work as they should, they need to have the same name but if they have the same name they return a result in the handler function that can't be read, ie e.parameter.radioButtonName is not useable since they are not differentiated.
There are simple workarounds though. Here is an example to show how you could handle that using clientHandlers and a (visible or invisible) textBox. there is also a function that handles the "reverse process", ie set the radioButtons vale from data coming from another widget. That should help you so answer both of your questions.
function radiotest() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
var radioValue = app.createTextBox().setId('radioValue');
radioValue.setId("radioValue").setName("radioValue");
var listhandler = app.createServerHandler('listhandler').addCallbackElement(panel);
var list = app.createListBox().addChangeHandler(listhandler).setName('list');
for(var i = 1; i < 10; i++){
var name = 'choice '+i;
list.addItem('Activate '+name,name);
var handler = app.createClientHandler().forTargets(radioValue).setText(name);
panel.add(app.createRadioButton('radioButtonGroup',name).addValueChangeHandler(handler).setId(name));
}
panel.add(radioValue);
var getit=app.createButton("Valide").setId("val");
panel.add(getit).add(list);
var handler = app.createServerHandler("valide");
handler.addCallbackElement(panel);
getit.addClickHandler(handler);
app.add(panel);
SpreadsheetApp.getActiveSpreadsheet().show(app);// show app
}
//
function valide(e){ ;// This function is called when key "validate" is pressed
var sh = SpreadsheetApp.getActiveSheet();
var RadioButton = e.parameter.radioValue;
sh.getRange('A1').setValue(RadioButton);
var app = UiApp.getActiveApplication();
return app;
}​
function listhandler(e){ ;// This function is called when listBox is changed
var sh = SpreadsheetApp.getActiveSheet();
var app = UiApp.getActiveApplication();
var listvalue = e.parameter.list;
var radioValue = app.getElementById('radioValue').setValue(listvalue);
sh.getRange('A2').setValue(listvalue);
var radiobutton = app.getElementById(listvalue);
radiobutton.setValue(true);
return app;
}​
Run this test from a spreadsheet and you'll get something like this :
EDIT :
following your comment, here is an efficient way to build such a multiple choices questionary, here is the test app
function doGet() {
var app = UiApp.createApplication().setTitle('test Questionnaire');
var panel = app.createVerticalPanel();
var sHdlr = app.createServerHandler('react').addCallbackElement(panel);
var questions = ['<b>Question Numéro 1 :</b><br>Faites votre choix parmis les 4 possibilités suivantes','<b>Question 2</b><br>Encore un fois, faites votre choix','<b>Question 3</b><br>encore un effort...','<b>Question 4</b><br>vous y êtes presque...'];
var Qitems = [['choix1 de Q1','choix2 de Q1','choix3 de Q1','choix4 de Q1'],['choix1 de Q2','choix2 de Q2','choix3 de Q2','choix4 de Q2'],
['choix1 de Q3','choix2 de Q3','choix3 de Q3','choix4 de Q3'],['choix1 de Q4','choix2 de Q4','choix3 de Q4','choix4 de Q4']];
var Qpanel = [];
for (var n=0 ; n<questions.length ; ++n){
var Qval = app.createTextBox().setId('Qvalue'+n).setName('Qvalue'+n).setVisible(false);
Qpanel[n] = app.createVerticalPanel().setId('QP'+n).setVisible(false).add(app.createHTML(questions[n])).add(Qval).setStyleAttribute('padding','10px');
panel.add(Qpanel[n]);
for(var q=0;q<Qitems[n].length;++q){
var name = Qitems[n][q]
var handler = app.createClientHandler().forTargets(Qval).setText(name);
Qpanel[n].add(app.createRadioButton('radioButtonQ'+n,name).addClickHandler(handler).setId(name).addClickHandler(sHdlr));
}
}
app.add(panel);
Qpanel[0].setVisible(true);
return app;
}
function react(e){
var app = UiApp.getActiveApplication();
var source = e.parameter.source;
var answer = [];
for(var n = 0; n < 4 ; ++n){
answer[n] = e.parameter['Qvalue'+n];
Logger.log('answer '+ (n+1) + ' = '+answer[n]+' source = '+source)
}
if(answer[0]=='choix1 de Q1'){app.getElementById('QP'+1).setVisible(true)}
if(answer[1]=='choix1 de Q2'||answer[1]=='choix3 de Q2'){app.getElementById('QP'+2).setVisible(true)}
if(answer[2]=='choix1 de Q3'||answer[2]=='choix3 de Q3'){app.getElementById('QP'+3).setVisible(true)}
if(answer[3]=='choix1 de Q4'){
app.add(app.createHTML('YESSSSSSSSS ... !!<br>Vous avez réussi !<br> vos réponses sont les suivantes : '+answer.join(' + ')).setStyleAttribute('padding','20px'))
}
return app;
}