I have created an application where I am collecting form responses from various users. I am getting responses with email id in responses spreadsheet. As I don't want to store data in spreadsheet so I am reading data trough responses. I am facing some challenges please guide.
Query 1
while using onFormSubmit(e) I am not able to read submitted form, given code is returning null:
var form = FormApp.getActiveForm();
Logger.log('usename:' + form.getId());
error " Cannot call method "getId" of null." although if I hard coded value of formid var form = FormApp.openById('<<form_id_xyz>>'); then it is working fine and I can read responses as well.
How can I get form responses for multiple users?
Query 2
getRespondentEmail(); is not working in my case. Even I use form id <<form_id_xyz>> and trying to get email id from responses which I have captured at the time of form submission form.setCollectEmail(true); I tried following code in onFormSubmit(e) function but dint get a result:
var formResponse=form.response;
Logger.log('email id of user: ' + formResponses.getRespondentEmail());
and another way:
Logger.log('email id of user: ' + form.getRespondentEmail());
and
Logger.log('email id of user: ' + e.values[1]);
nothing works for me. Kindly guide.
Query 1: Hope it's clear in my comment.
Query 2:
Sorry to say, I don't understand your second query problem completely.
However as per your requirement I am suggesting this code.
If you have created a form you should know the form id (I assume) so try this code.
var form=FormApp.openById('your form id here');
//this returns your form which you created//
var responses=form.getResponses();
/// this will give you all responses of your form as an array////
///iterate the array to get respondent email id///
for(var i = 0; i < responses.length; i++){
Logger.log(responses[i].getRespondentEmail());
}
I think it's important to note that at the present time the answer to your question is: You can get what they enter, but you cannot get their true verified Email Address. This is explained better in this question and one of the answers details some workarounds such as publishing form as a web script.
The accepted answer displays what email address the user has typed into the form. There is no authentication to this beyond it having an # symbol thus a user could type foofoo#zoomZoom.com and it would be viewed in the forms results and scripts.
What's annoying is that google IS capturing the user's true email address because if settings are set to Allow One Response Per User, then the user is limited to one submission -- regardless of what they put as their email account. I'm not sure why Google won't provide a method to view the submitter's login email address since it has been disclosed to the user that this will be disclosed.
Microsoft Forms does capture this.
Related
I’m writing to you because I’m facing a problem with an automatic email script based on Google Form submission (or new GSheet entry when GForm is sent). Process in short:
I have a Google Form (here's similar one) that is linked to Data Studio and Power BI Dashboards. Based on data that goes into spreadsheets, the forms are automatically pre-filled using calculated fields in dashes (Date, ActionID, Code, ID, Location etc.) and data goes to Dash-linked spreadsheet [Example of what it might look like]. The thing is that in case of errors found during inspections, the copy of the form/email should be also sent to Employee (optionally, the person that is superior to them, so that both know the details, not only the auditor who fills-in the form – just option). I can’t use any available Add-ons for GForms due to sensitive nature of data. Auditors don’t have edit access to Forms/Dashes, and sending all information via email would take too long. I also created a test Google Form to demonstrate what it looks like.
All in all, What I’m looking for is a dynamic script that will also grab company email of the employee (supervisor is optional), and when auditor submits the form, the email/copy of the form also goes to those mentioned aboce. I couldn't find anything GForms related.
I used a similar script before, but don’t think it was based on new rows added to spreadsheets [Example]. If it’s not possible to achieve something like this, even spreadsheet entry form/email would be really greatly appreciated (email based on "EmployeeEmail" from form + selected columns included, as marked in sheet), although I’m afraid of things going wrong in a file with lots of rows. I tried to find something similar and discovered 2 scripts, but I don’t know how to make them dynamic: The first one below just sends messages to emails from a given range and it’s static (range).
thanks! It looks good, but I have 2 issues.
Edit:, it always needs that dummy email ('xxx#xxx.xxx'”, which means I’ll (or sb else) be getting hundreds of emails. Can we somehow get rid of this line or replace it with form sender email (I can replace existing column with one with form sender email (google form add emails automatically)/those that are already in columns 2/3?
2nd thing, how can I concatenate dummy message lines to variables:
var message = row.join('\n'); (currently adds values from row n)
e.g. can we somehow replace text join with e.g.
// Info from specific columns
var Date = lastRowValues[n][5]; //I don’t know how to grab last value from columns, it’s probably something like variable.getLastRow() + variable.getLastColumn() + Get values
var ID = lastRowValues[n][6];
var Code= lastRowValues[n][8];
var Action = lastRowValues[n][9];
var Location = lastRowValues[n][10];
var ErrorType = lastRowValues[n][11];
and then in message
// var = message = “You’ve made an error. Please find the details below.” +
“\n “ +
“\n Date of Action: “ + Date +
“\n ID: “ + ID +
“\n Action Code: “ Code +
“\n Type of Action: “ + Action +
“\n Location: “ + Location +
“\n Error Type: “ + ErrorType +
The rest, such as the title, may stay the same. I realised that numbers only are hard to read. Is it possible to achieve this output? This is what it looks like now.
You can add this code in your linked spreadsheet:
// this function will fires automatically
// it grabs all data from the last row and send it via email
function send_email() {
var row = SpreadsheetApp.getActive().getDataRange().getValues().pop();
var message = row.join('\n');
var subject = 'test subject';
var address = 'xxx#xxx.xxx';
GmailApp.sendEmail(address, subject, message);
// additional emails
var address2 = row[2];
GmailApp.sendEmail(address2, subject, message);
var address3 = row[3];
GmailApp.sendEmail(address3, subject, message);
}
// this function should be run just once to install the trigger
function install_onFormSubmitTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('send_email').forSpreadsheet(ss).onFormSubmit().create();
}
After you install the trigger every time your form was submitted all data from the form (= all cells from the last row on the sheet) will be sent to xxx#xxx.xxx. And to two additional addresses from cells 'C' and 'D'.
Feel free to change the code as you need.
I want my Google script to parse all emails within a label. But just once. The emails come from my bank. They store transaction details. Because I use thread conversation view I worry that the script will either - process one message more than once or miss a message in a case I mark the thread with a label let's say "done" once the email message was processed.
The transaction details are coming with the same subject, so all of them will be part of one thread.
I do not want to store message ID or something like outside Google Script.
Could you think of any solution?
I was thinking that I can add email ID to the thread but the I would end up with too many labels.
I might be able to use Gmail API as suggested here
GmailApp - Add label to specific message, not the thread and
Google Apps Script - Changing label of individual email in Gmail
but I do not know how to check if a particular message got specific label.
You can query for messages containing a certain label with Gmail.Users.Messages.list specifying the id of a label
Sample:
var starredMessages = Gmail.Users.Messages.list("me", {"labelIds":"Label_981438383934575828"}).messages;
var starredIds = [];
starredMessages.forEach(function(message){starredIds.push(message.id)});
Once you have this, you can retrieve all inbox messages, push their ids into an array and filter them to remove the already labelled messages from the array:
var AllIds = [];
var allMessages = GmailApp.getInboxThreads().forEach(function(thread){thread.getMessages().forEach(function(message){AllIds.push(message.getId())})});
var filteredIds= AllIds.filter(function (id) { return starredIds.indexOf(id) == -1;});
As a result, you obtain an array with message Ids that do not have the specified label (yet).
Now, do with those messages what you desire, e.g. in a loop and subsequently add the label to them with e.g.
filteredIds.forEach(function(id){Gmail.Users.Messages.modify({'addLabelIds': [LabelId]}, 'me', id)});
UPDATE
Another way to retrieve messages without the label is with the query parameter q.
Thereby, the query should be specified as -label:MY LABEL :
var NotStarredMessages = Gmail.Users.Messages.list("me", {"q":"-label:MY LABEL"}).messages;
HOWEVER, KEEP IN MIND THAT IF ONE MESSAGE OF A THREAD HAS THE LABEL, THIS SECOND METHOD WILL NOT EXCLUDE ALL MESSAGES OF THE CORRESPONDING THREAD FROM THE LIST.
So in your case the second method is not recommended.
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.
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.
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);
}