Receiving duplicate emails with sendEmail() - google-apps-script

I tried both MailApp.sendEmail() and GmailApp.sendEmail() to send an email confirmation from onFormSubmit and ending up with multiple duplicate emails (as many as 6). The code looks like this:
function sendEmailConf_(ss, email, session) {
Logger.log("sendEmailConf_ email: %s for session: %s", email, session);
var formUrl = ss.getFormUrl(); // Use form attached to sheet
var form = FormApp.openByUrl(formUrl);
var formResponses = form.getResponses();
Logger.log("Count of form responses: %s", formResponses.length);
for (var i = 0; i < formResponses.length; i++) {
if (formResponses[i].getRespondentEmail() == email) {
Logger.log("Sending email to: %s for session: %s", email, session[0]);
GmailApp.sendEmail(
email,
'Confirmation for registration of: ' + session[0] + ', ' + getSessionSchedStr(session),
('Thanks for registering!\n\n' + getResponseAsText(formResponses[i]) + '\n\n' +
'You may change your response using this URL: ' + formResponses[i].getEditResponseUrl())
);
}
}
}
Using script transcript and log statements, I confirmed that sendEmail() is getting called only once and that the email is a string with single email address in it. The emails I receive have exactly the same body and are received at the same time and they all have the same from and to addresses (both mine, since I am testing it). Anybody has a clue on what is going wrong here?
Edit: Just observed that the duplicate count is increasing by one every time it is run. I just tried it again and got 7 fresh emails, all exact duplicates (and different from prior 6). I am clueless on what could be causing such a behavior.

Open the script editor and choose Resources -> Current Project Triggers. Make sure you only have a single trigger associated with the script.
If you have shared the script with multiple users, you'll have to repeat this from the account of every user who may have authorized the script.

Related

onSubmit Trigger Executed Without Form Submission

I created a Google Form, linked to a Sheet to capture responses, and added an Apps Script that runs each time the Form is submitted. Ran through a bunch of tests and everything was working fine - form responses fed through, onSubmit function working great. Last night, though, we received a few executions of the script even though the Form was not submitted.
Looking at the Responses page on the Form itself, there were no submissions when I got the notification. Also, this is not a public Form in my organization, and only one other person has the link besides myself. He confirmed he didn't submit the form at the time of the executions.
There are two sheets in the Google Sheet: 1> Form Responses and 2> Data. The data sheet uses a few QUERY functions to pull data from the responses sheet, formatting it differently (e.g. putting hyphens in phone numbers, rendering some fields in upper case, etc.). Also, the data sheet headers are labeled differently than the Form questions (e.g. 'homeAdd1' instead of 'Home Address Line 1'). This is because the script creates a PDF, using the Form responses to replace placeholders ('%homeAdd1%') on a template Google Doc. The script then takes the generated PDF and emails it to the submitter.
Again, everything was working great until yesterday's testing. I didn't realize it at the time, but when my colleague was inputting random values to test the Form, for the Home Address Line 2 he only input a 5-digit ZIP code. It generated a PDF fine, and also emailed it to him, but this caused the QUERY function to render a #VALUE error. The functions look like this:
=QUERY(Responses!L2:S,"SELECT UPPER(L) UPPER(M)...
So when Sheets saw a cell with just 5 digits, it automatically rendered it as a number, and UPPER doesn't work on number values. I (stupidly) didn't think to pre-format all of both sheets as plain text, so this occurred.
Would a #VALUE error on a Google Sheet linked to a Form and an Apps Script cause a misfire of the onSubmit function? This is the only thing I can see that could have possibly caused it, but it doesn't make sense. I've fixed the formatting issue, but I don't know if an erroneous execution could mean some other issue.
With the extra submissions, the script just sent the most recent PDF again and again. Within 20 seconds, it fired 5 times, sending the last PDF that was generated via email each time. Looking at the Stackdriver logs, there's nothing different from when we were testing it earlier yesterday. The console.log and console.info commands work fine, and they all come through listed as having been triggered by the onSubmit function.
Here's the script:
Submit function:
function onSubmit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var list = ss.getRange("A1:A").getValues();
var row = list.filter(String).length;
var email = ss.getRange(row,2).getValue();
var newResponse = ss.getRange(row,3).getValue();
if (newResponse == 'Generate New') {
newOne(ss,row,email);
} else if (newResponse == 'Upload Completed') {
completed(ss,row,email);
} else {
}
}
Function that was executed:
function newOne(ss,row,email) {
var name = ss.getRange(row,4).getValue();
console.log('Function Start - ' + name);
var newType = ss.getRange(row,6).getValue();
var copyFile = DriveApp.getFileById('[file id]').makeCopy();
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getActiveSection();
// Replacing variables with values on spreadsheet
console.log('Create file start - ' + name);
var newInfo = ss.getRange(row, 1, 1, 29).getDisplayValues();
var header = ss.getRange(1, 1, 1, 29).getDisplayValues();
for (var i = 1; i <= 5; i++) {
copyBody.replaceText('%' + header[0][i] + '%', newInfo[0][i].toString());
}
var x;
if (newType == 'Office 1') {
x = 6;
} else if (newType == 'Office 2') {
x = 15;
} else {
}
for (var i = x; i <= (x + 8); i++) {
copyBody.replaceText('%' + header[0][i] + '%', newInfo[0][i].toString());
}
copyBody.replaceText('%' + header[0][26] + '%', newInfo[0][26].toString());
// Create the PDF file, rename it, and delete the doc copy
copyDoc.saveAndClose();
var newFile = DriveApp.createFile(copyFile.getAs('application/pdf'));
newFile.setName('New - ' + name + '.pdf');
copyFile.setTrashed(true);
console.log('Create file finished - ' + name);
//Mails PDF to submitter
console.info('Pre-email log for ' + name);
MailApp.sendEmail(email,'Email Subject','', {
noReply: true,
htmlBody: "<body>Hello, and thank you.</body>",
attachments: [newFile]
});
console.info('Email sent for ' + name);
appFile.setTrashed(true);
}
Any insight / help would be appreciated; thanks!
Josh
Spurious unwanted Event Triggers
I've had problems with spurious triggers coming from onFormSubmit event triggers. In my case they were always immediately after a real trigger occurred from a Form Submission. I found that I could identify them because none of my required questions were answered. I discuss it here.
It might be worth your time to capture the e.values array and see if you can find a consistent way to keep them from causing a misfire of your processing function.
As far as I know, onSubmit(e) doesn't work the way you're expecting it to.
I think what you're looking for is an onFormSubmit trigger, try using the following from Class SpreadsheetTriggerBuilder documentation to create a script trigger that executes every time someone submits a response to your linked form:
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("function name")
.forSpreadsheet(sheet)
.onFormSubmit()
.create();
I have an installation of a spreadsheet and corresponding form where I get frequent duplicate on form submit events, inexplicably. It does not occur in other installations. If this is your situation you can't just check if the event is null because to test it for null you have to have something to test. If it's undefined you will get an error. So first test if it's undefined. Try this code:
`function formSubmitted(e) {
// Deal with the unusual case that this is a bogus event
if ((typeof e === "undefined") || (e == null) || (e.length == 0)) {
Logger.log("formSubmitted() received a bogus or empty event");
return;
}
...`

Google sheet script linked sending duplicate emails when form is submitted

I'm having an issue where a script I wrote is sending duplicate emails when a form is submitted. The script is also executing on occasion when I simply open the spreadsheet. I only have one trigger set up to run the script when the form is submitted, and I'm the only one with edit access to the sheet. I tried deleting the script project altogether and creating a new one, which didn't resolve the issue. I'm not sure if there's anything wonky with my script, but here it is:
function sendEmails() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Raw Data'); // Gets Raw Data Sheet
var lastRow = sheet.getLastRow(); // Gets last row of sheet everytime the form is submitted
var lastColumn = sheet.getLastColumn(); // Gets last column of sheet everytime the form is submitted
var value = sheet.getRange(lastRow,1,lastRow,lastColumn).getValues().toString();
var comments = sheet.getRange(lastRow, 41).getValue().toString(); // Gets additional comments from inspection form submitted
if (value.indexOf("NOT OK") > -1) {
MailApp.sendEmail({
to: "test#test.com",
subject: 'Machine Issue',
htmlBody: "An inspection of the xyz machine has returned issues: " + "<br/><br/>"
+ "<b>" + comments + "</b>" + "<br/><br/>" +
" Click " + ' <b>HERE</b>'
+ " to see the last inspection report.",
});
} // Produces email based on defined parameters.
}
I've also tried deleting the trigger and setting up a new one, which hasn't worked either.
Check your executions log. If you have multiple executions but only one Form Responses line, this is a known bug with the form submit trigger. The only way to get around it is to use a script lock.
Like this:
SpreadsheetApp.flush();
var lock = LockService.getScriptLock();
try {
lock.waitLock(15000); // wait 15 seconds for others' use of the code section and lock to stop and then proceed
} catch (e) {
Logger.log('Could not obtain lock after 30 seconds.');
return HtmlService.createHtmlOutput("<b> Server Busy please try after some time <p>")
// In case this a server side code called asynchronously you return a error code and display the appropriate message on the client side
return "Error: Server busy try again later... Sorry :("
}
START NORMAL CODE HERE
I've only got one script where this is really a problem but it was a really awful problem, up to six executions per form submission and the scriptlock is the tidiest way to lock it down. If your code itself takes less than 15 seconds reduct your waitlock time so the extra copies give up faster. If you use this method you'll still see the extra copies in the executions log, but they'll only be 15 seconds long. It's very satisfying to watch them caught and killed in this way.
I had an issue with multiple emails on form submission too. I noticed that my code was sending an email for every send email function i had. Like, it was based on score email, so what i did is, i closed function for every alternative, so, it would check points, if it didnt met the requirements, then it just wouldnt send email, and go for the next function, until it found a the function that met requirementes.
I think that in your code, its reading send emails twice, so he reads on the send emails, look for requirements, and sends. Then, it reads the next send emails, looks again for requirements and send email again.
Its like your giving an order to send emails twice.
This line has a problem:
var value = sheet.getRange(lastRow,1,lastRow,lastColumn).getValues().toString();
Let's say lastRow is 20. Then this code with get the last row plus the next 19 rows of values which presumably are all blank. The third parameter is the number of rows and the fourth is the number of columns.
It's better to pass the event object into the function and use e.values rather than having to go get the last line. If you get multiple form submissions one after another you may in fact be getting the wrong data.
This line also has a problem:
htmlBody: "An inspection of the xyz machine has returned issues: " + "<br/><br/>"
+ "<b>" + comments + "</b>" + "<br/><br/>" +
" Click " + ' <b>HERE</b>'
+ " to see the last inspection report.",
});
The comma at the end of the htmlBody parameter should be removed.
Try this code:
function sendEmails(e) {
var value=e.values.toString();
var comments=e.values[40];
if (value.indexOf("NOT OK") > -1) {
var html="An inspection of the xyz machine has returned issues: ";
html+="<br/><br/>" + "<b>" + comments + "</b>" + "<br/><br/>" + " Click "
html+=' <b>HERE</b>' + " to see the last inspection report.";
MailApp.sendEmail({to: "test#test.com",subject: 'Machine Issue',htmlBody: html});
//Logger.log(html);
}
}
Form Submit Event Object
I played around with this a little more and according to #J. G. there is a problem with onFormSubmit triggers returning multiple triggers. I solved the situation for my testing by using the following code which I was using to log onFormSubmit triggers.
function testFormSubmission(ev) {
var lock=LockService.getUserLock();
try{
if(ev.values && !ev.values[1]){throw('Spurious Returns Error');}
if(lock.tryLock(10000)) {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('LogSheet');
var tA=[Utilities.formatDate(new Date(), Session.getScriptTimeZone(),"d/M/yyyy HH:mm:ss")];
tA=tA.concat(ev.values);
tA.splice(tA.length-1,1,ev.triggerUid,ev.range.rowStart,ev.range.columnEnd,JSON.stringify(ev.values));
sh.appendRow(tA);
lock.releaseLock();
}
}
catch(error){
console.error(error);
return;
}
}

Getting thread id of a mail sent through google scripts

Is it possible to get the thread id of a mail sent through MailApp.sendEmail().I want to tag the sent mail with a label just after it is sent.
MailApp.sendEmail("samplemail#gmail.com","Sellers Required for pilot",msg_to_bd);
//get thread id for this mail, say thread 1
thread1.addLabel(labll);
First, since you want to add labels to the thread you just sent, you must be using GmailApp. MailApp only allows you to send mail, not interact with the user's inbox.
As you've seen, GmailApp.sendEmail() does not return a message or thread ID. In this case, you can search for the thread you just sent, but you must account for when you've sent several messages to this person.
As long as you are not sending duplicate mails very quickly, you can rely on the fact that a call to GmailApp.search() will return threads in the same order as the web UI. So a search for 'from:me to:customer123#domain.net' might return many threads, but the first result will be the thread for the most recently sent message.
A toy example where we send a mail to a bunch of addresses listed in a tab called Recipients:
var recipients = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Recipients')
.getDataRange()
.getValues();
recipients.shift(); // Only if the Recipients sheet contained a header you need to remove
var d = new Date();
var dateText = d.toLocaleString(); // Pretty-printed timestamp
var newLabel = GmailApp.createLabel(dateText); // Label corresponding to when we ran this
for (var i = 0; i < recipients.length; i++) {
GmailApp.sendEmail(recipients[i], 'This is a test', 'Of the emergency broadcast system');
var sentThreads = GmailApp.search('from:me to:' + recipients[i]);
var mostRecentThread = sentThreads[0];
mostRecentThread.addLabel(newLabel);
}
Apps Script won't return the thread ID but what you can do is search for the subject in your mailbox after sending the email and apply the label to the first thread in the result.
var to="email#example.com", subject="email subject";
GmailApp.sendEmail(to,subject,msg_to_bd);
var threads = GmailApp.search("to:" + to + " in:sent subject:" + subject, 0, 1);
threads[0].addLabel(label);
Since all of the GmailApp.send* methods (at the time of writing) do not return a message or thread identifier, and since the GmailMessage object has no send* method, the safest thing to do seems like embedding a unique identifier into the message when it is sent. Then search for an email containing the unique identifier.
This code worked for me as an experiment. Note that I had to sleep() for a couple seconds in order for the search to succeed.
function tryit() {
var searchTerm = Utilities.getUuid();
GmailApp.sendEmail('address#somewhere.com', 'oh please',
'custom id: ' + searchTerm);
Utilities.sleep(2000);
var threadIds = GmailApp.search(searchTerm);
Logger.log(threadIds);
if (threadIds.length != 1) {
Browser.msgBox('Found too many threads with unique id '
+ searchTerm);
return;
}
return threadIds[0];
}
I suspect the reason we have to jump through hoops is that the API authors don't want to make sending email synchronous (maybe it can take too long), and hence they have no way to return an error or message id upon failure or success.
If you want to go completely crazy, you could send a message to yourself with the uuid, then spin in a while-sleep-search loop until you found the uuid and hence get a thread id, then reply to the thread with the full list of recipients. This guarantees that only your inbox suffers if things go wrong.
Im using this, it adds uuid hidden code into message, and I can find/label particular email with 100% precision:
var uid = Utilities.getUuid();
var uidText = '<span style="color:transparent; display:none !important; height:0; opacity:0; visibility:hidden; width:0">' + uid + '</span>';
GmailApp.sendEmail(parameters.email, subject, "", {"htmlBody":htmlEmail + uidText});
Utilities.sleep(1000);
GmailApp.search(uid)[0].addLabel(label)

Getting active spreadsheet row after form submission

I am relatively new to Google Apps Script and have been using a very simple script that I created about a year ago that is triggered when a user submits inputs via a Google Form. The script has been working perfectly until approximately this past May and I've been scrambling trying to figure out what happened when I haven't made any changes to my code. I have searched many different places and cannot seem to find what is wrong.
Basically, I have a form that users complete and then submit. Upon submission, the script takes the inputs from the most recent row and stores them in variables that would then be assembled into an email message confirmation that acknowledges each user's submitted input.
Here is my code:
function acknowledgement() {
var ActiveSheet = SpreadsheetApp.getActiveSheet();
var ActiveRow = ActiveSheet.getActiveRange().getRow();
var emailAddy = ActiveSheet.getRange("E"+ActiveRow).getValue();
var locvar = ActiveSheet.getRange("C"+ActiveRow).getValue();
var employeevar = ActiveSheet.getRange("B"+ActiveRow).getValue();
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Variables");
var contactvar = sh.getRange("A2").getValue();
var subject = sh.getRange("B2").getValue();
var contactvar2 = sh.getRange("C2").getValue();
var linebrk = "<br />";
var msg = "Dear " + employeevar + ","
+ linebrk + linebrk
+ "This confirms that you have completed your review of the latest security presentation."
+ linebrk + linebrk
+ "Your location number is " + locvar + "."
+ "Thank you very much for your participation."
+ linebrk + linebrk
+ contactvar;
var msghtml = '<p>'+msg+'</p>';
var advancedargs = {cc:contactvar2, htmlBody:msghtml};
MailApp.sendEmail(emailAddy, subject, msg, advancedargs);
}
What is currently happening is that my code is no longer grabbing the current row number (i.e. the active row that was just submitted by a user). Instead, it is simply grabbing the top row of the sheet (i.e. my row headings like 'Employee Name', 'Email Address', etc.) and assigning those row headings to the variables thus producing an error when trying to send the email confirmation. For instance my variable emailAddy would contain "Email Address" causing sendEmail to fail.
Any feedback would be appreciated!
Using getActiveRow in the context of a form submission is somewhat strange as one cannot consider that a user is actually active on the sheet... I don't know why you did choose that approach and I'm actually wondering how it happened to work for so long...
There are other possibilities to handle form submissions but the one that will need the fewest changes in your code is to simply use getLastRow() instead of getActiveRange().getRow()
There are a few risks to use that simple "strategy" as there might be concurrency issues when 2 or more people send a form simultaneously.
The other solution is to get all the field values directly from the event properties that comes on form submission as in that case each event is unique, no matter how it comes into the spreadsheet but your script will have to be rewritten more deeply.
I believe that Google Forms has well covered the case you mention, the trigger "onFormSubmit" the spreadsheet, receives an object as a parameter with all the information you need.
I agree with Serge that the script be rewritten deeply, but definitely, it will save many problems.
Go to the documentation, specifically in "Spreadsheet Form Submit Events" https://developers.google.com/apps-script/understanding_events.
You are looking for the code e.range.getRow().
So we have:
function onFormSubmit(e) {
const row = e.range.getRow()
}
You'll also need to setup a trigger to the onFormSubmit function.
Edit > Current project's triggers
Now (finally) some fun: everytime a form is submitted, you'll know the row it corresponds to. Have fun!
Note that the onFormSubmit function could have any name - the trigger will map to any named function and pass to it an "e" argument that contains range.getRow() among other information.

How to add "Edit Response" link to Google Forms emails?

I have a simple Google Form that collects data, and, using AppScript, sends confirmation emails to users who fill it out. After user submits the form, on confirmation, s/he will see a link to edit his/her response.
I'd like to include that link as a part of the confirmation email (Right now, it only shows up on the page.) How can I obtain the URL to edit a submitted response?
I am able to get the link to the Form through SpreadsheetApp.getActiveSpreadsheet().getFormUrl(). It gives me the following format: https://docs.google.com/a/domain.com/spreadsheet/viewform?formkey=<formKey>
The link however doesn't include the edit key, which is required for users to edit his/her response. The expected URL should look like this: https://docs.google.com/a/domain.com/spreadsheet/viewform?formkey=<formKey>&edit=<editKey>
Thanks for the help in advance!
-K
Edited:
Added a feature request on this: http://code.google.com/p/google-apps-script-issues/issues/detail?id=1345&thanks=1345&ts=1337773007
The answer that this wasn't possible by #Henrique Abreu was true until very recently. Google seems to have added getEditResponseUrl() to the FormResponse class and with that it becomes possible to use code like this to get the edit URL for a bunch of existing forms:
function responseURL() {
// Open a form by ID and log the responses to each question.
var form = FormApp.openById('1gJw1MbMKmOYE40Og1ek0cRgtdofguIrAB8KhmB0BYXY'); //this is the ID in the url of your live form
var formResponses = form.getResponses();
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
Logger.log(formResponse.getEditResponseUrl());
}
}
To make it automatically email the user as they respond one could add a trigger on form submit. As The situation I'm working with doesn't require people to log in with an apps account I don't have access to an email address automatically so I have a text question that captures the user's email address.
It does ask the question about whether or not editing the forms is what you want. I've been grappling with the relative advantages of editing an existing response or sending a prefilled form using toPrefilledUrl() so that I can see how things have changed over time. I guess this comes down to the value that tracking this will provide you.
If you are using Google Apps your responders can edit there form responses.
See: How to Edit Form Responses
--edit this is now possible. See other answers.
After user submits the form, on confirmation, s/he will see a link to
edit his/her response. I'd like to include that link as a part of the confirmation email
That is not possible, period.
That link is not accessible anywhere and one can't guess/construct it. But, there's some workarounds that might suit you (some suggested here that I'll re-phrase), e.g.
Send a per-populated form link and have the user re-send it. You'd need to have some kind of control field (e.g. the username), so you can know and delete/ignore his older submits. Possibly automatically via a script.
You could also develop and publish an apps-script GUI and send a link to this apps script plus a parameter that you generate where you can determine which entry you should edit. The down-side of this approach is that it's somewhat cumbersome and overkill to re-design the whole form on Apps Script. But again, it works.
At last, you could open an "Enhancement Request" on Apps Script issue tracker and wait until they and Google Spreadsheet/Forms team get together to develop a solution.
Here is a clear blog post that shows you how to do it step by step and explains what's going on under the hood for AppsScripts newbies:
http://securitasdato.blogspot.com/2014/11/sending-confirmation-emails-from-google.html
While collectively you can get there from the all the excellent answers provided here, the script from that post worked best for me.
Does this help - I haven't tried it but I was looking for the same thing a while ago and noticed this.
From this page
https://developers.google.com/apps-script/reference/forms/
code from there contains this:
Logger.log('Published URL: ' + form.getPublishedUrl());
Logger.log('Editor URL: ' + form.getEditUrl());
Jon
Great, script works! Thanks.
For newbies, like me: Just paste the andre's code for function SendConfirmationMail(e) into your spreadsheet's code editor and set 'on form submit' trigger to run it. That's in spreadsheet script editor, not form script editor.
You need to hack in some values. Read the code. For me the confusing one was the need to replace the ********COLUMN SEQUENCE EX 14****** with the sheet column number where you want the edit urls to end up. I used 39 which is one column more than my form was using up.
However, I got runtime probs in this part:
for (var i in headers) {
value = e.namedValues[headers[i]].toString();
// Do not send the timestamp and blank fields
if ((i !== "0") && (value !== "")) {
message += headers[i] + ' :: ' + value + "<br>";
}
}
Dunno why, but I replaced it with this:
for (var keys in columns) {
var key = columns[keys];
if ( e.namedValues[key]) {
message += key + ' :: '+ e.namedValues[key] + "<br>";
}
}
Works for me.
Try This: (Credits is not for me, because i merge two solutions of the third part)
Source: Send Confirmation Email with Google Forms
/* Send Confirmation Email with Google Forms */
function Initialize() {
var triggers = ScriptApp.getScriptTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("SendConfirmationMail")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function SendConfirmationMail(e) {
var form = FormApp.openById('***YOUR FORM CODE***');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('***SHEET NAME***');
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = ***************COLUMN SEQUENCE EX 14******; // column number where URL's should be populated; A = 1, B = 2 etc
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [], url;
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
url = resultUrls[i-1]
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
try {
var ss, cc, sendername, subject, headers;
var message, value, textbody, sender;
// This is your email address and you will be in the CC
cc = Session.getActiveUser().getEmail();
// This will show up as the sender's name
sendername = "****YOUR NAME******";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
subject = "Registro de Oportunidade submetido com sucesso";
// This is the body of the auto-reply
message = "Nós recebemos seu registro de oportunidade.<br>Muito Obrigado!<br><br>";
ss = SpreadsheetApp.getActiveSheet();
headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
// This is the submitter's email address
sender = e.namedValues["********COLUMN NAME OF DESTINATION E-MAIL************"].toString();
for (var i in headers) {
value = e.namedValues[headers[i]].toString();
// Do not send the timestamp and blank fields
if ((i !== "0") && (value !== "")) {
message += headers[i] + ' :: ' + value + "<br>";
}
}
message += "<br>Link to edit" + ' :: ' + url + "<br>";
textbody = message.replace("<br>", "\n");
GmailApp.sendEmail(sender, subject, textbody,
{cc: cc, name: sendername, htmlBody: message});
} catch (e) {
Logger.log(e.toString());
}
}
you can try to populate a form with the values given from that email address than delete previous answers ...
it's not a beautiful way but it can works ...
I don't think we have access to what that value is through the Spreadsheet API (which means Apps Script doesn't have it either). The closest I can think of would be the "key" value in this feed. You'd have to test to find out though. There's no other alternative that I know of other than accessing the Spreadsheet API directly. So first, you'd have to get the last row through the api use ?reverse=true&max-results=1