I have a piece of code meant to send recurring emails every 8 weeks to a list of addresses in a google sheet.
It does not seem to be sending out the mails.
I have tried various examples that I found online, with no success
ScriptApp.newTrigger("sendEmails")
.timeBased()
.onWeekDay(ScriptApp.WeekDay.THURSDAY)
.atHour(11)
.nearMinute(00)
.everyWeeks(8)
.create();
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("EMAILS")
var startRow = 2;
var numRows = sheet.getRange(1,4).getValue();
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[0];
var message = row[1];
var subject = "mail subject here";
MailApp.sendEmail(emailAddress, subject, message);
}
}
when I run the script manually it seems to be working fine, so I guess the problem is in the new trigger part?
Problem:
Currently you have the code in place but it won't be used at all because it is not part of a function.
Requirement:
Trigger to run code every 8 weeks.
Solution:
Separate your trigger builder into a separate function.
Run the following script, it'll delete any triggers you may have accidentally set up and create a new one that should run as you're expecting.
function newTrigger() {
//clear all triggers
var tg = ScriptApp.getProjectTriggers();
if(tg.length>0){
for(i=0;i<tg.length;i++){
ScriptApp.deleteTrigger(tg[i]);
}
}
//build new trigger
ScriptApp.newTrigger("sendEmails")
.timeBased()
.onWeekDay(ScriptApp.WeekDay.THURSDAY)
.atHour(11)
.nearMinute(00)
.everyWeeks(8)
.create();
}
Notes:
You'll only need to run this function once to set up the trigger.
In your project's triggers, it'll show as "every week" but should actually only run every 8 weeks like we specified in the code using .everyWeeks(8).
References:
Installable Triggers
Class ClockTriggerBuilder
Related
I'm looking for help to send an email whenever a new row is added by a google form entry if said entry contains an email in the Email column. I'm new to Javascript, but I've pieced together some code which I plan to run off an onEdit trigger in GSheets.
My problem is that if there is no email address, the code will fail. I need to know how to wrap this in an "if/else" or maybe just a simple error handling bit would be fine, not sure.
If I go with an "if/else", I'll need to check if the email column contains a value. I don't need to check if it is a valid email; the google form already does this on submission.
Here is the code I have right now:
function MessageNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("Message Board"));
//
//extracts the values in last row and stores them into a two-dimensional
array called data
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(lastRow,3,1,8);
var data = dataRange.getValues();
//
//pull column elements into a one-dimensional array called rowData
for (i in data) {
var rowData = data[i];
var emailAddress = rowData[2];
var poster = rowData[7];
var subject = rowData[3];
var recipName = rowData[6];
var comment = rowData[4];
var replyLink = rowData[5];
//
//
var message = 'Dear ' + recipName + ',\n\n'+poster+' has posted the
following comment directed to you: '+'\n'+comment+'\n\n'+'To reply to this
comment click: '+replyLink;
var subject = subject;
MailApp.sendEmail(emailAddress, subject, message);
}
}
thanks in advance for any help you can give me.
Thank you tehhowch for the help. I'm new at this so I'll have to continue researching the link you referred to regarding iteration best practice. However I was able to get this working with a simple 'if' wrapper, which turned out to be simpler than I thought.
I did find out that form submission does not recognize an active sheet, so manually testing my code worked, while form submission did not trigger it.
After some looking, I replaced:
var ss = SpreadsheetApp.getActiveSpreadsheet();
with this:
var ssID = '//insert spreadsheet id here';
var ss = SpreadsheetApp.openById(ssID);
This still did not work, so I had to kickstart it by deleting the trigger and putting it back in (found this info: On form submit trigger not working)
This may not be the most efficient code, but here is what I have now, and it does work:
function MessageNotification() {
var ssID = '//insert spreadsheet id here';
var ss = SpreadsheetApp.openById(ssID);
ss.setActiveSheet(ss.getSheetByName("Message Board"));
//extracts the values in last row and stores them into a two-dimensional
array called data
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(lastRow,3,1,8);
var data = dataRange.getValues();
//
//pull column elements into a one-dimensional array called rowData
for (i in data) {
var rowData = data[i];
var emailAddress = rowData[2];
var poster = rowData[7];
var subject = rowData[3];
var recipName = rowData[6];
var comment = rowData[4];
var replyLink = rowData[5];
//
//
var message = 'Dear ' + recipName + ',\n\n'+poster+' has posted the
following comment directed to you: '+'\n'+comment+'\n\n'+'To reply to this
comment click: '+replyLink;
var subject = subject;
if(emailAddress)
{
MailApp.sendEmail(emailAddress, subject, message);}
}
}
As mentioned in the question comments, you want to use the event object available to the on form submit trigger. This can be accessed from a container-bound script on either the form or its responses spreadsheet, simply by adding a parameter to the function that receives the trigger.
This object is of the form:
e: {
authMode: <enum>,
namedValues: {
'q1title': [ <q1string> ],
'q2title': [ <q2string> ],
...
},
range: <Range>,
triggerUid: <string>,
values: [<q1string>, <q2string>, ...]
}
Using this object means that accessing of the Spreadsheet, for the purposes of emailing someone based on contents of the form, is unnecessary.
function MessageNotification(e) {
if(!e) return; // No form event object was provided.
var responses = e.namedValues;
var emailQTitle = /* the title of the question that asks for the email */;
// Check that 1) this question exists in the response object, and also
// 2) it has an answer with a value that 3) is "truthy".
// https://developer.mozilla.org/en-US/docs/Glossary/Truthy
if(responses[emailQTitle] // 1
&& responses[emailQTitle].length // 2
&& responses[emailQTitle][0]) // 3
{
var emailAddress = responses[emailQTitle][0];
/* access the responses variable in a similar manner
for the other variables needed to construct the email */
MailApp.sendEmail(emailAddress, ... );
} else {
/* There was no response to the email question. */
// You can use View->Stackdriver Logging to inspect the form response, for
// example, to make sure that it had the format or values you expected.
console.log({form_object: e, responses: responses, emailTitle: emailQTitle});
}
}
I currently trying to create for stock inventory of some products that are frequently used in my workplace using google spreadsheet. Moreover, I'm trying to come up with a script that would send me an email when a certain product reaches a value below 2 so that I would know that a certain product needs to be restock. I'm do not know the basics of coding, but here's what I got so far:
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var ProductA = sheet.getRange("B2").getValue();
var Product B = sheet.getRange("B3").getValue();
var min = 2
if (ProductA<min) MailApp.sendEmail('n********#googlegroups.com', 'LOW REAGENT STOCK', 'Attention! Your stock of ProductA is running low. Please proceed to restock.');
if (ProductB<min) MailApp.sendEmail('n********#googlegroups.com', 'LOW REAGENT STOCK', 'Attention! Your stock of ProductB is running low. Please proceed to restock.');
}
I put the trigger on onEdit to run the script and I intent to expand the list with more products. The thing is that if one product as already reached a value below 2 and if a change another one, the script will send email for both of them. With more products, this becomes a nuisance, because I would received a bunch of emails if other values remain below 2. Can someone help me out with this? I couldn't find any solution to this so far and I would truly appreciate some help.
Thank you!
When the "onEdit" trigger fires, it receives the event object as parameter containing some useful information about the context, in which the edit action occurred.
For example,
function onEdit(e) {
// range that was edited
var range = e.range;
//value prior to the edit action
var oldValue = e.oldValue;
//new value
var value = e.value;
//sheet the action came from
var sheet = range.getSheet();
//cell coordinates (if edited range is a single cell)
//or the upper left boundary of the edited range
var row = range.getRow();
var col = range.getColumn();
}
You can inspect the event object to get the cell that was edited and see if it's in column B.
var productsColIndex = 1; //column A index;
var inventoryColIndex = 2; //column B index
var range = e.range;
var value = e.value;
var sheet = range.getSheet();
var editedRow = range.getRow();
var editedCol = range.getColumn();
var productName = sheet.getRange(editedRow, productsColIndex).getValue();
//checking if
//1) column B was edited
//2) the product exists in column A
//3) new value is less than 2
if ((editedCol == inventoryColIndex) && productName && value < 2) {
//code for sending notification email.
}
Finally, because simple triggers like onEdit() can't call services that require authorization, it's better to create a function with a different name and then set up the installable trigger manually. In your Script Editor, go to "Edit" -> "Current project's triggers" -> "Add a new trigger" , select your function name from the dropdown list, and pick the following options: "From spreadsheet", "On edit".
I posted this question on Google Sheets forum and was directed here for help.
*Please note that I am not a coder, I've just started working with things like this.
I've created a workbook with 3 pages. It's connected to a form, so as people submit their reviews the answers are collected on the first sheet, calculated on the second sheet, and any submission with an overall score higher than 3.9 has the email address moved to the third sheet where it will be sent a follow-up email.
Here is a link to a copy of the sheet:
https://docs.google.com/spreadsheets/d/15p7_M4guRWCVHG-acRAheAROmh9t4wk3GWD_x0_rl90/edit?usp=sharing
It all works except the last page: I cannot figure out how to get the emails to send automatically as the sheet is updated. I've set the trigger to have it run when the sheet is updated, but to no avail - I have to manually go in and click the "Run" button to have the emails sent. (When I do, it pops up 'Failed to sent email: no recipient (line 21, file "Code")' but the emails are successfully delivered anyway.)
The formula I am using is this: (I have also tried swapping "sendEmails2" with "autoResponder" but that didn't change anything either.) Can anyone tell me what is wrong with it? Or is there a better way to automatically send the e-mails?
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 20000; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3)
// 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
if (emailSent != EMAIL_SENT) { // 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();
}
}
}
This should do it:
function sendEmails2(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Automatic Emails');
var rg=sh.getRange(2,1,sh.getLastRow(), 3);
var vA=rg.getValues();
for (var i=0;i<vA.length;i++){
var emailAddress = vA[i][0];
var message = vA[i][1];
var emailSent = vA[i][2];
var subject = "Sending emails from a Spreadsheet";
if(emailSent != 'EMAIL_SENT'){
MailApp.sendEmail(emailAddress, subject, message);
sh.getRange(2 + i,3).setValue('EMAIL_SENT');
}
}
}
Don't forget the onFormSubmit:
I'm sending a spreadsheet in the body of an email everyday. I completed the email portion, but now im trying to program the trigger to set off at 1:15pm everyday. I'm not sure how to implement the code to trigger with the email?
'function nearMinute(minute) {
var sendRead = ScriptApp.newTrigger("sendRead1pm")
.timeBased()
.atHour(13)
.everyDays(1) // Frequency is required if you are using atHour() or atMinute()
.create();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Totals");
var subjecttable = UrlFetchApp.fetch("https://docs.google.com/spreadsheet/pub?
key=XXXXXXXXXXXXXXXXXXXXXXXXXXX=true&gid=1&output=html");
var htmltable = subjecttable.getContentText();
var fromName = "DoNotReply - email";
var rowData = ss.getRange("B16").getValues()[0];
var emailAddress = "emailaddress#gmail.com"; // First column
var message = {htmlBody: htmltable, name: fromName}; // Second column
var subject = "TEST $" + rowData;
MailApp.sendEmail(emailAddress, subject, "", message);
}`
You don't have to code your trigger. Make your function to do the email part and set up the trigger manually. In your script, go to Resources --> Current Project's Triggers and then add a trigger. This is the easiest.
I found the following script to insert form submission values into a google spreadsheet.
function doPost(e) { // change to doPost(e) if you are recieving POST data
var ss = SpreadsheetApp.openById(ScriptProperties.getProperty('active'));
var sheet = ss.getSheetByName("DATA");
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]; //read headers
var headers2 = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0]; //read headers
var nextRow = sheet.getLastRow(); // get next row
var cell = sheet.getRange('a1');
var col = 0;
for (i in headers2){ // loop through the headers and if a parameter name matches the header name insert the value
if (headers2[i] == "Timestamp"){
val = new Date();
} else {
val = e.parameter[headers2[i]];
}
cell.offset(nextRow, col).setValue(val);
col++;
}
//http://www.google.com/support/forum/p/apps-script/thread?tid=04d9d3d4922b8bfb&hl=en
var app = UiApp.createApplication(); // included this part for debugging so you can see what data is coming in
var panel = app.createVerticalPanel();
for( p in e.parameters){
panel.add(app.createLabel(p +" "+e.parameters[p]));
}
app.add(panel);
return app;
}
//http://www.google.sc/support/forum/p/apps-script/thread?tid=345591f349a25cb4&hl=en
function setUp() {
ScriptProperties.setProperty('active', SpreadsheetApp.getActiveSpreadsheet().getId());
}
Now I want to send a formatted email to two of my coworkers every time a row gets inserted. I tried to use:
var emailAddress = "email#gmail.com"; // First column
var message = "message"; // Second column
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
but it's not sending anything.. can anyone advise please?
I had the same trouble.
With the most recent version of Google Apps I had to save the script, create a new revision, and re-publish the script making sure to select the new revision. After this the new code was in effect. I wasted several hours in the belief that the script would be updated if I just saved it.
Somehow the new method saves the script elsewhere. It's almost impossible to tell what code is actually running unless you go through the process of saving a revision, and re-publishing.