Can anyone help.
I have a simple google spreadsheet that enables me to book delegates onto a variety of courses at different venues and at different times and dates.
I used the same spreadsheet last year, kindly set up by Bob Rashkin! It worked perfectly and sent emails when delegates booked onto the course and also sent email reminders automatically when the course was 9 days or so from starting.
I have duplicated the spreadsheet for this term but the sheet refuses to send the reminder emails, I really could do with a little help on this?
A secondary matter is that when the script sends a booking confirmation email, it sometimes sends two of them which creates a lot of phone calls asking if they've booked on twice.
Help someone please
This is the reminder script that I'm using
function Reminder() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var s=ss.getActiveSheet();
var r1=s.getDataRange().getRow()+1;//Start past the header row!!! Doh!
var r2=s.getDataRange().getLastRow();
var mn,m,days,d=new Date(),coursedate=new Date(),dlen=8.64e7,i,course,r,year;//8.64e7
var subject="Just a gentle reminder that you or colleague(s) from your setting have a Paediatric First Aid course coming up in the next week or so. ";
var recipient, body, tail="Please be aware that Entrust (formerly Staffs Early Years) will make a charge for non attendance so";
tail+=" please make sure that you familiarise yourself with the times and dates of the course. ";
tail+="If you need help finding the venue then please follow the link below to find the venue and print off a map if required.";
tail+="\n\nhttp://www.blithfieldsafety.co.uk/venues/";
for (r=r1;r<=r2;r++) {
recipient=s.getRange(r,9).getValue();
course=s.getRange(r, 2).getValue();
body=subject+"\nCourse Details\n"+course+"\n\nDelegate Name: "+s.getRange(r,4).getValue()+"\n\n"+tail; //changed (r,2) to (r,4)
mn=course.match(/Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/)[0];
m=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"].indexOf(mn);
days=course.match(/(\d{1,2})(st|nd|rd|th)/g);
year=d.getFullYear();
for (i in days) {
coursedate.setMonth(m);
coursedate.setDate(days[i].slice(0,-2));
if ((coursedate-d)/dlen<14 && s.getRange(r,16).getValue()!="mail sent") {
GmailApp.sendEmail(recipient, subject, body);
s.getRange(r,16).setValue("mail sent");//arbitrarily picked col 15
}
}
}
};
It looks like the time remaining until the course begins is checked with this line:
if ((coursedate-d)/dlen<14 && s.getRange(r,16).getValue()!="mail sent") {
That line is making a date calculation, and checking if the value of a cell had the text "mail sent" in it. If the cell didn't have mail sent AND the date calculation is true, then an email gets sent. Notice that the divisor dlen is a value that was hard coded.
var mn,m,days,d=new Date(),coursedate=new Date(),dlen=8.64e7,i,course,r,year;//8.64e7
The value of the variable dlen is set to a constant value of 8.64e7. But I'm guessing that the math no longer works right for some reason.
The value of dlen is 86400000.
There are 24 hours in a day, 60 minutes in an hour, and 60 seconds in a minute.
24 * 60 * 60 = 86,400 seconds in a day. So, obviously, the 86,400,000 number is a multiple of the number of seconds in a day.
I'm guessing that there is a new course every month?
You can add a Logger.log() statement to your code, and run it so see what the variable values are:
Logger.log('coursedate: ' + coursedate);
If you put that line in your code:
for (i in days) {
coursedate.setMonth(m);
Logger.log('coursedate: ' + coursedate);
coursedate.setDate(days[i].slice(0,-2));
Logger.log('coursedate: ' + coursedate);
Logger.log('d: ' + d);
if ((coursedate-d)/dlen<14 && s.getRange(r,16).getValue()!="mail sent") {
That would tell you what the values of the variables coursedate and d are right when the calculation is being made.
Then you could hopefully figure out why the math is the way it is. To view the Logger.log() output, click on the View menu, and choose the Logs menu item. A list of logged values will be in the window.
Related
This is the code I am currently trying to use to implement an email based on the cell value of C2 (see screenshot of Google sheets below).
function amberwarning() {
// Fetch the combined flow value
var combflowrange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("FloodEWS").getRange("C2");
var combflow = combflowrange.getValue();
// Check combined flow value
if (270 < combflow < 310){
// Fetch the email address
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Email").getRange("A2");
var emailAddress = emailRange.getValues();
// Send Alert Email.
var subject = 'Amber warning';
var message = 'It is possible that the Egger site will experience flooding in the coming hours. The advice is to be prepared to take action as combined river flows can increase very quickly during storms. Please keep up to date with the latest river levels for Hexham at <https://flood-warning-information.service.gov.uk/station/9006>. The latest flood warnings from the Environment Agency for Hexham are here <https://flood-warning-information.service.gov.uk/warnings?location=+hexham>. The latest MetOffice weather forecast can be found here <https://www.metoffice.gov.uk/weather/forecast/gcy2xzrne#?>. Please use all available information to inform your decision making. You will keep receiving an email as per each refresh of the latest data. The current combined flow from the North and South Tyne is' + combflow;
MailApp.sendEmail(emailAddress,subject,message);
}
}
The current error message I am receiving is "The parameters (number[],String,String) don't match the method signature for MailApp.sendEmail. (line 15, file"
The idea is that:
When cell C2 is between 270 and 310, to send an email 'Amber warning'
When cell C2 is above 310 send an email 'Red warning'
When cell C2 is less than 270, no email
This will hopefully be attached to a trigger to schedule every 15 mins
Any help on how to combine the two emails (or have single codes for each email) would be greatly appreciated.
enter image description here
It seems your "emailAddress" parameter is a number array (number[]) since the error you are receiving says so.
Try using getValue() if it is a single address, or get the first value of getValues() which is a 2D array by doing getValues()[0].
Whichever you choose, assign it to your emailAddress variable before calling MailApp.sendEmail().
Try to follow the steps in the documentation
as it explains everything clearly and how to send email through app-script
I have my family cell phone bills set to autopay and sometimes forget to send each individual their portion of the bill. I wanted to setup an automated system with google apps to send me a form where I can input each person's owed amount. Then after I submit the form, the app will send the people on my plan an email with their amount due. I then want the same prefilled form sent back to me a week or two later that allows me to update my googlesheet column with people's payment status.
I have figured out how to process the form data and then send out the bill emails. However, I cannot find a way to resend a form via a google-scirpt so I can update if an individual has paid me and I have cashed their checks. I figure I will need to capture the responce.id to update the same sheet entry, but I have not been able to find a way to resend the form.
I have googled a bit and tried to some method like sendForm("email",formID) but have not been able to find anything. Everything I have seen online shows me how to send the form from my google drive. However, I was wondering if anyone knows if such a method exists.
Here is a sample of my code so far (I am in no way a professional programmer so feel free to make suggestions to improve the existing code):
/*Define key variables up here like URL for sheets */
var sheetId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var sheetName = "Form Responses";
var sheetData =SpreadsheetApp.openById(sheetId).getSheetByName(sheetName).getDataRange();
var lastRow = sheetData.getNumRows();
var monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
var base = [ 1, 2];
function test(){
for (i = 0; i< base.length; i++){Logger.log(i);}
};
function lastBillComplete() {
lastRow = sheetData.getNumRows();
isSuesCheckCashed = sheetData.getValues()[lastRow-1][7];
isNancysCheckCashed = sheetData.getValues()[lastRow-1][8];
if (isSuesCheckCashed == "Yes" && isNancysCheckCashed == "Yes") {
return true;}
else{
return false;}
};
function sendBill(){
// Array of names that emails are being sent to
var emails = ["xxxxxxx#gmail.com","xxxxxxx#gmail.com"]; //the real emails will go here.
var names = ["Sue", "Mom"];
//subject line of email
var subject = "Verizon bill for " + monthNames[new Date(sheetData.getValues()[lastRow -1][2]).getMonth()];
//body of email that changes for each person
for (i = 0; i < names.length; i++){
var amount = sheetData.getValues()[lastRow-1][i+3];
var body = new String("Hi " + names[i] +",\n\nYour portion of this month's bill is $"+amount +". I have attached the .pdf of the bill to the email if you would like to look it over. Please let me know if you have any questions.\n\nTalk to you soon, \nJeremy");
MailApp.sendEmail(emails[i].toLowerCase(), subject, body);
}
};
I realize that probably the best way to set this up is to have the people on my plan just autopay to my bank account. However, the people on my account like to send actual checks, and are resistant to the idea. So I figured I would use the opportunity to improve my scripting abilities.
Thanks in advance,
Jeremy
This might be a slightly different approach than what you're doing, but if the forms that you have people fill out are connected to a spreadsheet, I think it will be easier if you use that spreadsheet as verification as to whether or not if they've filled the form. Timestamp the responses or have a field for Billing Month, just anything to identify a time period. Within that time period, check to see if your plan members have a response. You can then create a time-based trigger to have it check at regular periods and use the same email sending code you have to send the people that have not paid the form again, or just send yourself an email to take whatever appropriate action.
This question already has an answer here:
For loop and if statement for multiple conditions
(1 answer)
Closed 6 years ago.
I've got a Google Form set up to record user-reported errors about a database we maintain. The responses go into a Google Sheet and the users email is recorded. Essentially, I'd like to have a status field in that Google Sheet -- and when it's set to something like "Complete" (which would be in the same row as the response) I would like an email to be automatically sent to the user that submitted the response, letting them know the status of their response is complete. So sort of like a ticket system that many companies use (but we don't have a lot of bandwidth to set this up, so we're looking for something simple/free).
You cannot send an email inside the onEdit trigger. So you'll have to save the edits somewhere, maybe inside UserProperties, and have a time-based trigger that sends this value to your email every minute.
See: Email Notifications in Google Spreadsheets.
Google Spreadsheet support email notifications for row edits (tools - notification rules) but the last time I tried it, it never worked.
Create an onEdit() function, capture the cells value when it's edited, and run the code.
function onEdit(e){
// Capture the cells value after it is edited
var valCell = e.value;
Logger.log('The cell value is: ' + valCell);
if (valCell === "Complete") {
//Get the range of the cell
var theRange = e.range;
//Get the row of the range
var theRowOfEdit = theRange.getRow();
// Returns the cell with email
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("B" + theRowOfEdit.toString());
//Get the user email
var userEmail = cell.getValue();
//Send the email
}
}
This is not the complete code that you need. But, set this code up; test it, debug it, and if you have a specific question, post another question with the error message and line of code that isn't working.
Use debug in the code editor, and/or Logger.log() statements to debug the code.
I have a spreadsheet that logs incoming answered and missed calls in Google Drive.
It is currently set to send an email every hour between 10am and 7pm.
Ideally I would like it to not send the email during the weekend.
Setting up each hour Monday to Friday uses too many triggers.
Is there a way to construct a trigger that will send an email every hour (10am to 7pm) only Monday to Friday?
I've read the documentation at Google and a few (unrelated as it turns out) examples on here and I am stumped!
I tried putting a load of trigger conditions together:
function autoSendHourly() {
ScriptApp.newTrigger("hourlyUpdate()")
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.onWeekDay(ScriptApp.WeekDay.TUESDAY)
.onWeekDay(ScriptApp.WeekDay.WEDNESDAY)
.onWeekDay(ScriptApp.WeekDay.THURSDAY)
.onWeekDay(ScriptApp.WeekDay.FRIDAY)
.atHour(10)
.atHour(11)
.atHour(12)
.atHour(13)
.atHour(14)
.atHour(15)
.atHour(16)
.atHour(17)
.atHour(18)
.atHour(19)
.create();
}
I wasn't entirely surprised that it didn't work, but I was mildly surprised that it threw up no errors.
Any help (including "you're mad it can't be done") would be greatly appreciated.
The simplest thing to do is use the create trigger like you did but for every hour every day and then in you handler function add a small piece of code that will return if day and time don't meet specific conditions like explained in this (old) post.
the code may look like something like this :
function officeHours(){
var nowH=new Date().getHours();
var nowD=new Date().getDay();
Logger.log('day : '+nowD+' Hours : '+nowH)
if(nowH>17||nowH<8||nowD==6||nowD==0){return}
Browser.msgBox('time to work !');//normally your real function should begin here...
}
I haven't messed around with java in awhile but this article might help.
Android: how to get the current day of the week (Monday, etc...) in the user's language?
If it was me, I would get the day of the week and check it in a switch. Then if it matches a week day call a function to check the time between 10am and 7pm.
Best of luck.
In asp.net mvc2, how do I show the status of a user as "online"?
So if the user is actively working on the site, the status would be "online".
if the user stepped away from the site for about 5 minutes then it would be "5 minutes".
if the user stepped away from the site for about 10 minutes then it would be "10 minutes".
So on and so forth.
What is the best way to accomplish this? Any code sample would be very helpful to me.
The responses so far suggest that I used Ajax. If so, then how would I be able to query online users vs offline users. All my queries go against Database. Is it possible to query and display results joining Ajax results with Database queries?
I would think the most straight forward way of doing it would be with a session variable. You could add a line to your controllers (either in the action method, or the constructor, or even possibly with an action filter) which stashes the current Date/Time in the session. You could then use an ajax call to update the value on the screen at a specific interval. You would probably want to make the interval in minutes rather than seconds otherwise you would be displaying a counter (i.e. "1 second", "2 seconds", etc).
Some quick code samples:
// Somewhere in controller
Session["LastSeen"] = DateTime.Now;
// Now, an action that would return the amount of time since the user was last seen
public ViewResult GetLastSeenTime()
{
return Json(new { TimeAway = Date.Time.Now.Subtract((DateTime)Session["LastSeen"]).TotalMinutes});
}
// Then on your page, something like this
$.post("/Controller/GetLastSeenTime",null,function(result) {
if(result.LastSeen < 5)
$("#Status").Text("Online");
else if (result.LastSeen % 10 == 0)
$("#Status").Text(result.LastSeen + " minutes");
},"json");
Totally not tested, but should be close.
ckramer is right. I suggest expending his solution to make it js degradable.
/ Now, an action that would return the amount of time since the user was last seen
public ActionResult GetLastSeenTime()
{
if (Request.IsAjax) {
return Json(new { TimeAway = Date.Time.Now.Subtract((DateTime)Session["LastSeen"]).TotalMinutes});
}
ViewData.Add("LastSeen", Date.Time.Now.Subtract((DateTime)Session["LastSeen"]).TotalMinutes}));
return View("MyView")
}