Use triggers to send emails based on time submitted by user - google-apps-script

I have users subscribing to a mail service using google forms and they indicate how often they would like to receive an email, the value is recorded on a cell(ex.: every 1h, 2h ...).
I would like to loop through each user email and send a message based on the time they chose. Is there a way to do it with triggers?
Here is what I got so far:
function sendMail(){
for (i=2;i<=lastEmailRow;i++){
var currEmail = recipients.getRange(i, 2).getValue();
var currentTrigger = recipients.getRange(i, 3).getValue(); //how often
currentTrigger = currentTrigger.split(" ")[1];
MailApp.sendEmail(currEmail, "myEmail#sample.com", "Your Daily Mail",
{ htmlBody: HTML});
}
}

If your script is working fine (I'm not sure as lastEmailRow isn't defined on the question code) you have to make some design decisions, like if you will be using only one function or you will be using multiple functions, one for each frequency.
Depending on the above decision, then you could
create one time-driven trigger that runs very often, let say every hour
create several time-driven triggers, each with it's own settings.
In any case, you should include some conditions to control to whom send the email.

Related

Can I update a Google Sheets spreadsheet using a Google Form?

I'm looking to store data about foster animals from a google form. Essentially, it will just input the information entered into the spreadsheet. This works well for the first submission, but is not useful for if I would like to change information recorded for a specific animal. I think name is my best bet for a unique identifier, so I figure that I would want to write a script that would search for the name through a given column if the same name was entered and then repopulate that row.
Is this even something I can do to begin with? In addition, am I thinking about it in a very backwards way? If more information is needed, I am happy to provide it.
The best approach in this situation is to make use of Apps Script triggers.
You could start by using an onFormSubmit which will run when a user ends up submitting the form needed.
This is an installable trigger which means that it will require a setup first.
If you plan on using the form for modifying the information, you can easily create an id field for instance in the form and setup a script something similar to this:
function onFormSubmit(e) {
let ss = SpreadsheetApp.openById('SS_ID').getSheetByName('SHEET_NAME');
let idCol = ss.getRange('ID_RANGE').getValues();
let submissions = e.namedValues();
for (let i = 0; i < idCol.length; i++) {
if (idCol[i][0] == submissions.Id)
//update the sheet accordingly
else {
//add the new values to the sheet
}
}
}
In order to gather the submissions from the form, the e.namedValues has been used. Assuming, you have a column in your spreadsheet in which you store the id of each animal which corresponds to an item in your form, you can simply check if the submitted form is addressed for an existing item - so you can update it with the new info or simply just add the new submissions to the sheet.
Please bear in mind that you will have to adapt this so it fits your current setup.
Reference
Apps Script Installable Triggers;
Apps Script Event Objects.

Form Notification for Teachers when Students Fill out Google Form

I'm making a website for school to connect students and teachers. Teachers fill out a Google Form asking for service (grading papers...) and it is connected to Google Spreadsheets. Then a student can see that Spreadsheet and sign up on a different Google Form to help the teacher, and that response is recorded in the same Google Spreadsheet. When the student submits his/her Google Form, I want the teacher to be notified by email that a student signed up to help them. How can I send that notification? And I don't want the notification to come from my own school address. Is that possible?
Here is the Google website: https://sites.google.com/fcpsschools.net/jmhsservicesignup/subjects/math
This is the code I have so far:
function sendEmails() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Tutors
Signed Up");
var startRow = sheet.getLastRow(); // First row of data to process
var dataRange = sheet.getRange(startRow, 1, 1, 5)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[3]; // Second column
var tutor = row[0];
MailApp.sendEmail(emailAddress,"Tutor Request Filled",""+tutor+" has accepted your request to be tutored! Please notify"+tutor+" if anything changes.");
}
}
The getLastRow doesn't seem to work, and the email sends from my own address, not a Google forms notification if that is even possible.
If this is impossible I might just make the students send the email to the teacher, but I really want to automate the process. If you can think of a workaround, that would also be awesome.
Adding to what Sandy Good and Guilherme mentioned.
Here are a few more tips:
Not clear what data you're trying to get in your function. Are you trying to grab the data from the form submission? In that case you need to set up a trigger from the scripts menu, and connect it to the function (function needs to have an 'event' argument, usually called e).
function processFromSubmission(e) {//get data from e}
Apologies if you're not trying to do that. What happens when you Log sheet.getLastRow()?
Ask the school if they can get you another email address to use for this form, something like notifications#yourschool.edu. Follow the steps here to set up your alias. Do it for the gmail account that "owns" the spreadsheet these forms are sending data to.
Make sure your alias is set up properly. You should be able to see it in the "from" dropdown menu when you compose an email. Also try running the code Logger.log(GmailApp.getAliases()) and check the log to see that it's available.
Use GmailApp.sendEmail to send email, not MailApp.sendEmail. They're almost the same, but it looks like the MailApp version doesn't let you send from an alias. You can specify the 'replyTo' email as well if you want to set it to something else, like the student filling out the form or whatever (still not clear exactly what you're trying to set up!).
Send email like:
GmailApp.sendEmail(emailAddress, subject, body,
{replyTo: replyToEmailAddress_can_be_any_email,
from: 'notifications#yourschool.edu'
});
Note: your link didn't open.

Sending email when cell reach certain value

I've created a spreadsheet that collects data from a Google Form.
When a certain cell's value reach above certain number, I'd like to the sheet to send an email to my account. However I can't seem to get my head around how to do this. I've realized that I can't use the conditional formatting option that I get by right clicking the cell. I can only alter the cell/text color by using that option. Do I have to use a script to be able to perform this task automatically?
(The sheet collects absence/attendance data in a class, and when the absence percentage reach a certain value (15%) I'd like the sheet to e-mail a notice about this.)
This might be a newbie question, but that's what I am; A newbie.
You can setup a onFormSubmit trigger on the Response Spreadsheet and after every submit, it can calculate the attendance percentage and send an email using the MailApp.sendMail() method.
function calculate(e)
{
var s = SpreadsheetApp.getActiveSheet();
var data = s.getDataRange.getValues();
for (var rows in data) {
// Calculate the attendance data
}
if (condition_met) {
MailApp.sendEmail(email, subject, message);
}
}

Dynamically edit multiple choice options in live Google Form using Apps Script

I'm a high school teacher in L.A. trying to create a course registration system using Apps Script. I need the Google Form I'm using for this registration to:
Question 1) Update the choices available in subsequent multiple choice questions on new pages based on a student's current response choices.
Question 2) Eliminate choices from the form when a multiple choice option has reached it's "cap".
Question 1 Example)
A student registers for “tie-tying” in workshop 1, and gets taken to a new page. The Script edits the available choices on that new page based on the student’s first choice, and removes “tie-tying” from the list of possible choices on that new page, so “etiquette” is their only remaining option.
Question 2 Example)
Students can either register for “tie-tying” or “etiquette”, both responses are initially available in the Google Form. 30 students take the survey, all 30 register for the “tie-tying” workshop. The Apps Script references the response spreadsheet, realizes the “tie-tying” workshop is full, then removes it from the Google Form's list of possible choices. Student 31 goes to register, and their only option is “etiquette”.
If my question has already been asked and answered (believe me, I did search!) I'd appreciate the redirection.
I believe we can achieve your second objective without too much difficulty and modify the form, based on the current state of response.
The approach is to
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
For instance
function updateForm(e) {
if (e.values[1] == 'Yes') {
Logger.log('Yes');
var existingForm = FormApp.openById('1jYHXD0TBYoKoRUI1mhY4j....yLWGE2vAm_Ux7Twk61c');
Logger.log(existingForm);
var item = existingForm.addMultipleChoiceItem();
item.setTitle('Do you prefer cats or dogs?')
.setChoices([
item.createChoice('Cats'),
item.createChoice('Dogs')
])
.showOtherOption(true);
}
}
When it comes to achieving the goal in your first question, its more delicate, as the form will not submit mid way. What is possible is to go to different pages based on different responses to a Multiple Choice question, your use case may fit this method, although its not very dynamic.
Further its possible to use html Service to create completely dynamic experience.
Let me know if you need further information.
You are not able to create this type of dynamic form using the Google Forms Service, because there is no interaction between the service and scripts during form entry, except upon Form Submission. In the case of a multi-page form, a script has no way to know that a student has completed one page and gone on to another.
You could achieve this using the HtmlService or UiService, though. In either case, you'd rely on the client-side form interacting through server-side scripts to get updated lists of course options, then modifying the next 'page'. It will be complex.
The other answer to this question will keep adding a multichoice select each time for the form is submitted. Using similar approach of:
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
I've used the following code to modify a list select which could be easiliy modified for a multiple choice.
function updateForm(){
var form = FormApp.openById('YOUR_FORM_ID'); // Base form
// need to read what dates are available and which are taken
var doc = SpreadsheetApp.getActiveSpreadsheet();
var dates = doc.getRange("dates!A1:A10").getValues(); //available options
var taken_dates = doc.getRange("responses!F2:F51").getValues(); //just getting first 50 responses
// joining the taken dates into one string instead of an array to compare easier
var taken_dates_string = taken_dates.join("|");
var choice = [];
// loop through our available dates
for (d in dates){
// test if date still available
if (dates[d][0] != "" && taken_dates_string.indexOf(dates[d][0]) === -1){
choice.push(dates[d][0]); // if so we add to temp array
}
}
var formItems = form.getItems(FormApp.ItemType.LIST); // our form list items
// assumption that first select list is the one you want to change
// and we just rewrite all the options to ones that are free
formItems[0].asListItem().setChoiceValues(choice);
}

Spreadsheet Email Trigger

I have Written Script on Google Spreadsheet to send Email when spreadsheet is modified or any Data is added. Email Trigger is working but whenever any data is entered in next Row it send Email to previous email address also.
Please suggest solution
The below is written script :
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1 , numRows,3) // Fetch the range of cells A2:B3
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[2]; // First column
var message = row[0] + "requested" + row [1]; // Second column
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}
Your question is unclear... nowhere in the script I see something that reads which cell is actually modified... your target range is hardcoded on row 2 so the only row that can be processed is row 2 (and the mail can only be sent once)...
So can you :
explain how it should work
explain how it works now , especially what do you mean by 'previous email'
remove typos in your code (row[2] is not First column)
explain how you trigger this function : the name onEdit(e) suggest an onEdit trigger but simple triggers cannot send mail so I suppose you have set some other trigger.
explain why (e) in your function parameter and not using it ?
EDIT : thanks for the complement of information.
The script you suggest is not sufficient to achieve what you want. The idea here is to check if something in the sheet has been modified either by adding (or inserting) a row of data or (if I understood well) by editing any row in the sheet with a new value.
This is not really as simple as it looks at the first glance ;-)
What I would do it to take a 'snapshot' of the sheet and -based on a timer or onEdit - compare that snapshot to the sheet's current state.
There is more than one way to get that result, you could have a second sheet in your spreadsheet that no one could modify and that is a copy of the main sheet that you update after each modification/mail send. So before updating the script should look for any difference between the sheets and send a report to the corresponding email when a difference is found.
Another way to do that is to store the sheet data converted to a string in the script properties, the principle is the same but it's more 'invisible' for normal users accessing the spreadsheet.
You could also use scriptDb or your userproperties but the script properties is probably better suited (simpler) for this use case.
Tell us what you think/prefer and I (or someone else) could probably give you some code to start with.
It appears that you're using a shared spreadsheet to collect the add-user-requests, and trusting the requesters to fill in the information. In the detail document you shared, it further appears that requests are ADDED, but not EDITED. (That's an important simplifying distinction.)
I suggest that what you really need is to use a form for receiving that input. Using a form will create a "data table" within your spreadsheet, a set of columns that you must not mess with. (You can edit the contents, add and delete rows, but must not add or remove columns.) However, you CAN add columns to the spreadsheet outside of this table, which gives you a handy place to store state information about the status of individual requests.
Further, you can trigger your processing to run on form submit, rather than a simple "onEdit" - this gets away from the problem that ScampMichael pointed out. Alternatively, you can use an installable edit trigger, as described in this answer.
Try this sheet, and this form. Save yourself a copy, go into the script and remove the comments that are stopping emails from being sent, and try it out. There's a menu item in the spreadsheet that can kick off processing; just clear the "Request State" column to re-run it. You can open the form (and find its URL), and add more entries to experiment.
It's the core of a similar system that I've written, and contains a discreet state machine for processing the requests. My system has large amounts of very complex data in multiple spreadsheets, so it often gets pre-empted, then needs to run again. (I use a timed trigger for that.) That's why requests are handled through states. If you find that too complex, pull out only the parts you need.