Email Sender sends in a random order - javascript

After filling out a form the script sends an email but in a random order that does not make sense at all. When I try to manipulate the code I get errors and the script stops working.
function onFormSubmit(e) {
var values = e.namedValues;
var htmlBody = '<ol>';
for (Key in values) {
var label = Key;
var data = values[Key];
htmlBody += '<li>' + label + ": " + data + '</li>';
};
htmlBody += '</ol>';
MailApp.sendEmail('email#email.com','WORK REQUEST: ATTENTION NEEDED', '', {htmlBody:htmlBody})
}

Instead of e.namedValues use e.values together with reading the form response sheet columns headers
function onFormSubmit(e) {
var sheet = e.range.getSheet();
var headersRange = sheet.getRange(1,1,1,e.values.length);
var headers = headersRange.getValues()[0];
var htmlBody = '<ol>';
for (var i = 0; i < e.values.length; i++) {
htmlBody += '<li>' + headers[i] + ": " + e.values[i] + '</li>';
};
htmlBody += '</ol>';
MailApp.sendEmail('email#email.com','WORK REQUEST: ATTENTION NEEDED', '', {htmlBody:htmlBody})
}
Why?
e.namedValues returns and object. Object properties are unordered.
By default, the columns order is the same as the questions order

Related

How to save radio buttons to local storage

i have a quiz with radio buttons ,sow i have to save the answears on my local storge ,but im stuck i don t know what else to do,im learnig sow dont hate me pls,tnx
This is my code sow far
<form id="quiz"> </form>
<script>
let object;
let httpRequest = new XMLHttpRequest();
httpRequest.open("GET", "quiz.json", true);
httpRequest.send();
httpRequest.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
object = JSON.parse(this.response);
console.log(object)
}
let json = object
let quiz = document.getElementById("quiz");
let keyList = Object.keys(json.quiz);
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let questionItem = json.quiz[key];
let html = "<div>";
html += "<div><h2>Question " + (i + 1) + ": " + questionItem.question + "</h2></div>";
html += "<div>";
for (let i = 0; i < questionItem.options.length; i++) {
html += "<div >";
html += "<input type=\"radio\" id=\"q\" checked=\"checked\" name=\"qzz" + key + "_option\" value=\"" + questionItem.options[i] + "\">" + questionItem.options[i] ;
html += "</div>";
}
quiz.innerHTML += html;
}
quiz.innerHTML += "<input type=\"submit\" value=\"submit\">";
function save() {
var g1 = document.querySelector('input[type="radio]');
g1 = (g1) ? g1.value : '';
localStorage.setItem("g1", g1);
}
});
You can simplify your AJAX dialog by using fetch() instead of new XMLHttpRequest();. I straightened out a few things in your code (also see the initial remarks in #brianagulo's answer) and prepared a little set of sample data to demonstrate the whole functionality of the quiz. The jsonplaceholder.typicode.com url only serves as a working json-server endpoint. The received data is actually ignored here.
In your "production version" you will need to un-comment the line:
localStorage.setItem("quiz",JSON.stringify(ans))
The checked answers where collected in an object doing
[...document.querySelectorAll('input[type=radio]:checked')].reduce((a,{name,value}) =>(a[name]=value,a), {});
This
collects all checked radio button inputs with (document.querySelectorAll('input[type=radio]:checked')),
converts the collection of DOM elements into a proper array (with [... ])and eventually
reduce()-s its elements into an object where the element names are the property names and the (input-)element values are the property values.
And also please note that you can only store strings in local storage. Therefore I converted the ans object into a JSON string before using it in the .setItem() method.
const Q = {
quiz: [{
question: "Where was the Boston tea party?",
options: ["New York", "Detroit", "Boston", "Reno"]
}, {
question: "Where would you find Venice Beach?",
options: ["Detroit", "Venice", "Paris", "Los Angeles"]
}, {
question: "Where would you find Queens?",
options: ["London", "Paris", "Stockholm", "New York"]
}, {
question: "Where is Greenwich Village?",
options: ["London", "Paris", "Stockholm", "New York"]
}, {
question: "Where would you find the Gateway Arch?",
options: ["St. Quentin", "St. Louis", "St. Anton", "San Francisco"]
}]
}, quiz = document.getElementById("quiz");
var url = "quiz.json";
// in your productive version: comment out the following line
url = "https://jsonplaceholder.typicode.com/users/7"; // functioning test URL for fetch
function save(ev) {
ev.preventDefault();
const ans=[...document.querySelectorAll('input[type=radio]:checked')].reduce((a,{name,value}) =>(a[name]=value,a), {});
// in Stackoverflow snippets you cannot use local storage, so here is console.log instead:
console.log(ans);
// in your productive version: un-comment the following line
// localStorage.setItem("quiz",JSON.stringify(ans))
}
fetch(url).then(r => r.json()).then(object => {
// remove the following line:
object = Q; // use the static quiz from defined in Q instead ...
let json = object
let keyList = Object.keys(json.quiz);
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let questionItem = json.quiz[key];
let html = "<div>";
html += "<div><h2>Question " + (i + 1) + ": " + questionItem.question + "</h2></div>";
html += "<div>";
for (let i = 0; i < questionItem.options.length; i++) {
html += "<label>";
html += "<input type=\"radio\" id=\"q\" name=\"qzz" + key + "_option\" value=\"" + questionItem.options[i] + "\"> " + questionItem.options[i];
html += "</label><br>";
}
quiz.innerHTML += html;
}
quiz.innerHTML += "<input type=\"submit\" value=\"submit\">";
quiz.onsubmit=save;
});
<form id="quiz"> </form>
There is a typo on your save function. You are missing a quote after radio:
var g1 = document.querySelector('input[type="radio"]');
Also, your question is confusing but if what you are trying to do is get whether the radio is checked or not you must access the checked property and save that to localStorage. And if you want to save the state for all of the buttons then you should use querySelectorAll and save them that way instead. Example below of accessing a single input's checked value:
function save() {
// you can access it directly on this line
var g1 = document.querySelector('input[type="radio]').checked;
localStorage.setItem("g1", g1);
}
For saving them all
Lastly, it seems you are not actually calling the save() function. If your intention is to have the radios checked state saved to localStorage on click you may want to add an event to the submit button. For example:
<form id="quiz"> </form>
<script>
let object;
let httpRequest = new XMLHttpRequest();
httpRequest.open("GET", "quiz.json", true);
httpRequest.send();
httpRequest.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
object = JSON.parse(this.response);
console.log(object)
}
let json = object
let quiz = document.getElementById("quiz");
let keyList = Object.keys(json.quiz);
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let questionItem = json.quiz[key];
let html = "<div>";
html += "<div><h2>Question " + (i + 1) + ": " + questionItem.question + "</h2></div>";
html += "<div>";
for (let i = 0; i < questionItem.options.length; i++) {
html += "<div >";
html += "<input type=\"radio\" id=\"q\" checked=\"checked\" name=\"qzz" + key + "_option\" value=\"" + questionItem.options[i] + "\">" + questionItem.options[i] ;
html += "</div>";
}
quiz.innerHTML += html;
}
quiz.innerHTML += "<input type=\"submit\" value=\"submit\">";
function save() {
// you can access it directly on this line
var g1 = document.querySelector('input[type="radio]').checked;
localStorage.setItem("g1", g1);
}
let submitButton = document.querySelector('input[type="submit"]');
submitButton.onclick = (event) => {
/* this prevents page refresh and submission to the backend which is a form default */
event.preventDefault();
// then we call the save function here
save();
};
});
If this was helpful please consider selecting as the answer

Data from spreadsheet doesn't populate in the body of the email

I am trying to email some details regularly and my script doesn't seem to work well. I just need the display value of A3:C7 to be sent in a click of a button but the email isn't showing exactly the way it was on my spreadsheet. I am new on Coding . Below is the code:
function sendReport (){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var raw = sheet.getSheetByName('Raw Data');
var subType = raw.getRange('C3');
var jobType = subType.getValue();
var subID = raw.getRange('C4');
var jobID = subID.getValue();
var subBody = sheet.getSheetByName('Email Sheet');
var body1 = subBody.getRange('A3:C7');
var body = body1.getDisplayValues();
var subject = "RCA Report " + jobType + "-" + jobID
var message = "Hi TL, below is the " + subject
var closing = "For any clarifications, please do not hesitate to reach out to any of the QAs. Thanks! ";
var emailBody = message + body + closing;
MailApp.sendEmail("sample#sample.com",subject,emailBody)
};
The result looks like this:
Hi TL, below it the RCA report + jobType + "-" + jobIDCategory.Count.Judgment.16.0.27%.Did Not Load.....
So the data which looks like a table in my spreadsheet was somehow written continuously in a single line on my email.
Desired result:
Message...
Table A3:C7 (5 rows/3 columns including header)
Message...
To provide spreadsheet data in a table inside your e-mail, you can build an HTML <table> in your e-mail body, and populate data from the spreadsheet into the HTML table.
To do this, you need to iterate over the data in the selected spreadsheet range.
Currently you have this:
var body1 = subBody.getRange('A3:C7');
To iterate over this data, you can use 2 loops. The first will iterate over each row, and the second will iterate over each cell in the current row:
var dataRows = body1.getValues();
for (var i = 0; i < dataRows.length; i++) {
var dataRow = dataRows[i];
for (var j = 0; j < dataRow.length; j++) {
var cellContents = dataRow[j];
}
}
You can use these basic loops to build a string containing an HTML table:
var style = 'style="border: 1px solid black; border-collapse: collapse; padding: 5px;"';
var tableOutput = '<br><br><table ' + style + '>';
var dataRows = body1.getValues();
for (var i = 0; i < dataRows.length; i++) {
tableOutput = tableOutput + '<tr>';
var dataRow = dataRows[i];
for (var j = 0; j < dataRow.length; j++) {
var cellContents = dataRow[j];
tableOutput = tableOutput + '<td ' + style + '>' + cellContents + '</td>';
}
tableOutput = tableOutput + '</tr>';
}
tableOutput = tableOutput + '</table><br>';
Finally, because we are using HTML embedded in the body of the e-mail, we need to use the htmlBody parameter (documented here):
htmlBody: if set, devices capable of rendering HTML will use it instead of the required body argument
To do this, we need to change how we send the e-mail:
var emailBody = message + tableOutput + closing;
MailApp.sendEmail({
to: "sample#sample.com",
subject: subject,
htmlBody: emailBody
});
Here, we are explicitly using htmlBody as the body parameter, instead of the default plain string parameter.
Assuming the following input:
This will build the following e-mail body:
In my example I provided only the most basic styling to the table, to show black border lines around each cell, with some cell padding. You can obviously change that to whatever styling you wish to use.

Google Scripts to draft replies to emails with keyword in subject and inputting data from Google Sheets

I'm new to Google Apps Script so I'm looking for some advice. There's multiple parts and I managed to do some of it but I'm stuck on others. Any help would be much appreciated.
I'm trying to make a script that:
drafts a reply to emails that contain specific keywords (found in the body or the subject line).
I also want it to include a template with data inputted from a Google Sheets file.
It would be preferable if the draft can be updated without making a duplicate whenever the Sheet is modified.
I plan on also including a row of values (the first one) that correspond to the Subject columns in the second row the but I haven't gotten to it yet.
Some details about the Google Sheet:
Each row corresponds to a different person and email address that regularly emails me.
The first three columns are details about the person which I include in the body of my draft.
Each column after that represents a different string or keyword I expect to find in the subject of the emails sent to me.
The rows underneath contain two patterned code-words separated by a space in one cell that I want to be able to choose from. Such as:
3 letters that can contain permutations of the letters m, g, r (for ex: mmg, rgm, rgg, gmg)
and 0-3 letters with just p's (for ex: p, pp, ppp, or blank)
I want to be able to detect the different codes and assign it to a variable I can input into my draft.
What I have so far:
I'm able to draft replies for emails within my specified filter. However, I only have it set up to reply to the person's most recent message. I want to be able for sort through the filter for specific emails that contain a keyword in the subject line when it loops through the columns.
I'm able to input static strings from the Sheet into the body of my email but I'm still having trouble with the patterned codewords.
I was able to loop through more than one row in earlier version but now it's not. I'll look over it again later.
Here's my code:
function draftEmail() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 1; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 2; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var grader = row[0]; // Col A: Grader's name
var firstName = row[1]; // Col B: Student's first name
var studentEmail = row[2]; // Col C: Student's email
var grade = row[3].split(' '); // Col D: Grade
var pgrade = grade[1];
var hgrade = grade[0];
for (var n = 1; n < data.length; ++n) {
var srow = data[n];
var subjectCol = srow[3];
var threads = GmailApp.getUserLabelByName('testLabel').getThreads();
for (i=0; i < threads.length; i++)
{
var thread = threads[i];
var messages = thread.getMessages(); // get all messages in thread i
var lastmsg = messages.length - 1; // get last message in thread i
var emailTo = WebSafe(messages[lastmsg].getTo()); // get only email id from To field of last message
var emailFrom = WebSafe(messages[lastmsg].getFrom()); // get only email id from FROM field of last message
var emailCC = WebSafe(messages[lastmsg].getCc()); // get only email id from CC field of last message
// form a new CC header for draft email
if (emailTo == "")
{
var emailCcHdr = emailCC.toString();
} else
{
if (emailCC == "")
{
var emailCcHdr = emailTo.toString();
} else
{
var emailCcHdr = emailTo.toString() + "," + emailCC.toString();
}
}
var subject = messages[lastmsg].getSubject().replace(/([\[\(] *)?(RE|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$/igm,"");
// the above line remove REs and FWDs etc from subject line
var emailmsg = messages[lastmsg].getBody(); // get html content of last message
var emaildate = messages[lastmsg].getDate(); // get DATE field of last message
var attachments = messages[lastmsg].getAttachments(); // get all attachments of last message
var edate = Utilities.formatDate(emaildate, "IST", "EEE, MMM d, yyyy"); // get date component from emaildate
var etime = Utilities.formatDate(emaildate, "IST", "h:mm a"); // get time component from emaildate
if (emailFrom.length == 0)
{
// if emailFrom is empty, it probably means that you may have written the last message in the thread. Hence 'you'.
var emailheader = '<html><body>' +
'On' + ' ' +
edate + ' ' +
'at' + ' ' +
etime + ',' + ' ' + 'you' + ' ' + 'wrote:' + '</body></html>';
} else
{
var emailheader = '<html><body>' +
'On' + ' ' +
edate + ' ' +
'at' + ' ' +
etime + ',' + ' ' + emailFrom + ' ' + 'wrote:' + '</body></html>';
}
var emailsig = '<html>' +
'<div>your email signature,</div>' +
'</html>'; // your email signature i.e. common for all emails.
// Build the email message
var emailBody = '<p>Hi ' + firstName + ',<p>';
emailBody += '<p>For ' + subjectCol + ', you will be graded on #1, 2, and 3: <p>';
emailBody += '<p>Participation: ' + pgrade + '</p>';
emailBody += '<p>HW grade: ' + hgrade + '</p>';
emailBody += '<p>If you have any questions, you can email me at ' + grader + '#email.com.<p>';
emailBody += '<p>- ' + grader;
var draftmsg = emailBody + '<br>' + emailsig + '<br>' + emailheader + '<br>' + emailmsg + '\n'; // message content of draft
// Create the email draft
messages[lastmsg].createDraftReply(
" ", // Body (plain text)
{
htmlBody: emailBody // Options: Body (HTML)
}
);
}
}
}
function WebSafe(fullstring)
{
var splitString = fullstring.split(",");
var finalarray = [];
for (u=0; u < splitString.length; u++)
{
var start_pos = splitString[u].indexOf("<") + 1;
var end_pos = splitString[u].indexOf(">",start_pos);
if (!(splitString[u].indexOf("<") === -1 && splitString[u].indexOf(">",start_pos) === -1)) // if < and > do exist in string
{
finalarray.push(splitString[u].substring(start_pos, end_pos));
} else if (!(splitString[u].indexOf("#") === -1))
{
finalarray.push(splitString[u]);
}
}
var index = finalarray.indexOf(grader + "#email.com"); // use your email id. if the array contains your email id, it is removed.
if (index > -1) {finalarray.splice(index, 1);}
return finalarray
}
}
I've never coded in JavaScript before or used Google Scripts so I mostly looked at similar examples.
Thank you for any feedback.
I prefer reading code that isn't too nested. So I took the liberty to re-write your code and make it easier to read.
Your main function:
function mainFunction(){
// Use data from the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var threads = GmailApp.getUserLabelByName('<YOUR-LABEL-HERE>').getThreads();
var subject1 = data[1][3];
// Work through each row in the spreadsheet omit headers
for (var i = 2; i < data.length; ++i) {
// Get grader's data
var grader = getGrader(data[i]);
console.log(grader);
// Loop through threads
for (j=0; j < threads.length; j++){
var thread = threads[j];
// Get last message in thread
var messages = thread.getMessages();
var lastMsg = messages[messages.length - 1];
var email = new Email(grader, lastMsg, subject1);
// Create the draft reply.
var draftMessageBody = createDraftMessage(email);
lastMsg.createDraftReply(draftMessageBody);
}
}
}
Support functions:
Function getGrader:
function getGrader(array){
var row = array
var grader = {}
grader.grader = row[0];
grader.firstName = row[1];
grader.studentEmail = row[2];
var grade = row[3].split(' ');
grader.pgrade = grade[1];
grader.hgrade = grade[0];
return grader
}
Function webSafe:
function webSafe(fullstring, grader){
var splitString = fullstring.split(",");
var finalarray = [];
for (u=0; u < splitString.length; u++){
var start_pos = splitString[u].indexOf("<") + 1;
var end_pos = splitString[u].indexOf(">",start_pos);
// if < and > do exist in string
if (!(splitString[u].indexOf("<") === -1 && splitString[u].indexOf(">",start_pos) === -1)){
finalarray.push(splitString[u].substring(start_pos, end_pos));
} else if (!(splitString[u].indexOf("#") === -1)){
finalarray.push(splitString[u]);
}
}
// use your email id. if the array contains your email id, it is removed.
var index = finalarray.indexOf(grader.grader + "#mangoroot.com");
if (index > -1) {
finalarray.splice(index, 1);
}
return finalarray
}
Function Email: Behaves like a class
var Email = function(grader, lastMsg, subject){
this.signature = "your_email_signature,";
this.grader = grader;
this.to = webSafe(lastMsg.getTo(), this.grader);
this.from = webSafe(lastMsg.getFrom(), this.grader);
this.cc = webSafe(lastMsg.getCc(), this.grader);
this.subject = lastMsg.getSubject().replace(/([\[\(] *)?(RE|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$/igm,"");
this.message = lastMsg.getBody();
this.date = lastMsg.getDate();
this.attachments = lastMsg.getAttachments();
this.subject1 = subject;
this.ccHeader = function() {
var ccHeader = "";
if (this.to == "" || this.cc == ""){
ccHeader = this.cc.toString();
}
else {
ccHeader = this.to.toString() + "," + this.cc.toString();
}
return ccHeader
}
this.eDate = function() {
return Utilities.formatDate(this.date, "IST", "EEE, MMM d, yyyy");
}
this.eTime = function() {
return Utilities.formatDate(this.date, "IST", "h:mm a");
}
this.header = function() {
var header = ''.concat('On ');
if (this.from.length == 0){
header += this.eDate().concat(' at ',this.eTime(),', you wrote: ');
}
else {
header += this.eDate().concat(' at ',this.eTime(),', ',this.from,' wrote: ');
}
return header
}
this.body = function(){
var grader = this.grader;
var body = '<div>'.concat('<p>Hi ',grader.firstName,',</p>');
body += '<p>For '.concat(this.subject1,', you will be graded on #1, 2, and 3: </p>');
body += '<p>Participation: '.concat(grader.pgrade,'</p>');
body += '<p>HW grade: '.concat(grader.hgrade,'</p>');
body += '<p>If you have any questions, you can email me at '.concat(grader.grader,'#mangoroot.com.</p>');
body += '<p>- '.concat(grader.grader,'</p>','</div>');
return body;
}
}
Function createDraftMessage:
function createDraftMessage(email){
var draft = '<html><body>'.concat(email.body);
draft += '<br>'.concat(email.signature);
draft += '<br>'.concat(email.header);
draft += '<br>'.concat(email.message);
draft += '<br>'.concat('</body></html>');
return draft;
}
Now when you run mainFunction() you should get your expected drafts.
Notes:
It is good practice to keep functions flat, flat is better than nested. Makes the code more readable and maintainable.
Also be consistent in your variable naming style.
var emailMsg = ''; // Good.
var emailmsg = ''; // Hard to read.
Have a read about classes

How to Log value of all cells in a column on google app scripts

I am trying to get all the values in column L which is indexed as column 11(var check). However I am only getting the value of the first cell in the column and it stops looping through. I have created a comment for a reference.
Could someone please help me?
Please ignore:
It looks like your post is mostly code; please add some more details.
It looks like your post is mostly code; please add some more details.
It looks like your post is mostly code; please add some more details.
function myFunction(e) {
var sheet = SpreadsheetApp.openById("1naSWINA8_uxeLUsj0lFntqILyDj2nirb56uvkBel79Y").getSheetByName("CRM Feedback");
var ss = SpreadsheetApp.getActive().getSheetByName("Form Responses 1");
var data = sheet.getRange(4, 1, ss.getLastRow(), ss.getLastColumn()).getValues();
var manager_email = "XXXXX";
for( var i = 0; i< data.length;i++ ) {
var timestamp = data[i][0];
var requesterEmail = data[i][1];
var starRating = data[i][2];
var requestCatergory = data[i][3];
var description = data[i][4];
var label = data[i][5];
var ticketId = data[i][6];
var comment = data[i][7];
var status = data[i][8];
var priority = data[i][9];
var office = data[i][10];
//I am trying to log all the values in column 11
var check = data[i][11];
Logger.log(check)
var checkTimestamp = data[i][0]
if(check == false){
continue;
} else {
var subject = "CT IT feedback - ";
var body = "<body>";
body += "<br><b>Requester email:</b> " + requesterEmail
body += "<br><b>Star Rating:</b> " + starRating
body += "<br><b>Request Category</b> " + requestCatergory
body += "<br><b>Description:</b> " + description
body += "<br><b>label: </b> " + label
body += "<br><b>Ticket ID: </b>" + ticketId
body += "<br><b>Comment: </b>" + comment
body += "<br><b>status: </b>" + status
body += "<br><b>priority:</b> " + priority
body += "<br><b>office: </b>" + office
body += "</body>";
MailApp.sendEmail(manager_email, subject, body, {htmlBody:body})
var sent_string = "sent";
ss.getRange(i + 1, 12).setValue(sent_string)
if (sent_string){
return
}
}
}
}
You want to loop through all data rows and send emails for each row where the status is not set to "sent" yet
You want to set the status of a row to "sent" after sending an email
The problem is that
you have a return statement which makes you exit the for loop and stop iterating
You seem not to change the status for the right sheet and the right row
I suggest you to modify your code as following:
function myFunction(e) {
var sheet = SpreadsheetApp.openById("1naSWINA8_uxeLUsj0lFntqILyDj2nirb56uvkBel79Y").getSheetByName("CRM Feedback");
var ss = SpreadsheetApp.getActive().getSheetByName("Form Responses 1");
var data = sheet.getRange(4, 1, ss.getLastRow(), ss.getLastColumn()).getValues();
var manager_email = "XXX";
for( var i = 0; i< data.length;i++ ) {
var timestamp = data[i][0];
var requesterEmail = data[i][1];
var starRating = data[i][2];
var requestCatergory = data[i][3];
var description = data[i][4];
var label = data[i][5];
var ticketId = data[i][6];
var comment = data[i][7];
var status = data[i][8];
var priority = data[i][9];
var office = data[i][10];
//I am trying to log all the values in column 11
var check = data[i][11];
Logger.log(check)
var checkTimestamp = data[i][0]
if(check != "sent"){
var subject = "CT IT feedback - ";
var body = "<body>";
body += "<br><b>Requester email:</b> " + requesterEmail
body += "<br><b>Star Rating:</b> " + starRating
body += "<br><b>Request Category</b> " + requestCatergory
body += "<br><b>Description:</b> " + description
body += "<br><b>label: </b> " + label
body += "<br><b>Ticket ID: </b>" + ticketId
body += "<br><b>Comment: </b>" + comment
body += "<br><b>status: </b>" + status
body += "<br><b>priority:</b> " + priority
body += "<br><b>office: </b>" + office
body += "</body>";
MailApp.sendEmail(manager_email, subject, body, {htmlBody:body})
var sent_string = "sent";
//are you sure you want to set the stutus in ss and not in sheet to 'sent'?
//Keep in mind that you start with row 4
sheet.getRange(i +4, 12).setValue(sent_string)
}
}
}

sort key value pairs in Google Script

I have the below script running on a google sheet to automatically send an email with the sheet info to a specific emails. It is working perfectly but I am trying to optimize it. The problem I am having is every-time the email is sent the order of the text (Key value pairs) is different I am trying to order the key value pair based on the way they are in the email.
function onFormSubmit(e) {
var values = e.namedValues;
var sendFrom = '';
var ccEmail = '';
var subject = '';
var htmlBody = '<ul>';
for (Key in values) {
var label = Key;
var data = values[Key];
htmlBody += '<li>' + label + ": " + data + '</li>';
};
htmlBody += '</ul>';
MailApp.sendEmail(sendFrom, subject, htmlBody, {
htmlBody: htmlBody,
cc: ccEmail,
name: 'Automated Email',
noReply: true
});
}
Thank you for help in advance
You can access just the values (in correct order) with e.values, then dynamically create the "keys" by accessing the header row from the destination 'Form Responses' sheet:
function onFormSubmit(e) {
var values = e.values;
var vlen = values.length;
//get headers from response sheet (i.e. form questions)
var keys= SpreadsheetApp.getActive().getRange('Form Responses 1!A1:1').getValues()[0];
var i;
var htmlBody = '<ul>';
for (i=0;i<vlen;i++) {
var label = keys[i];
var data = values[i];
htmlBody += '<li>' + label + ": " + data + '</li>';
};
htmlBody += '</ul>';
/mail part etc.]
This way any edits the the questions in the form won't break your code.
A key value pair doesn't maintain order. So, you should create an array of keys to maintain the order instead, then iterate the array to retrieve each item in values.
example
var orderedKeys = ['firstName', 'lastName', 'email', 'phone']
Then in your function, instead of iterating on values, you iterate on orderedKeys instead.
for (var key of orderedKeys) {
var data = values[Key];
htmlBody += '<li>' + key + ": " + data + '</li>';
}

Categories