I am looking to get a few values from a previously submitted row from a google form response and then send these values, along with the title of the form, along to an end user.
however, I think I may be going about it the wrong way, I can pull up the spreadsheet and sheet and use this to edit a field, but i can not see how to pull the values back out from here, it just comes back as "range". what is the right syntax to get a values from a range?
is there any way to pull the title of the linked form? or the spreadsheet if that is not possible, as that is just "formName" +(responses).
here is the code i have so far, it is probably just missing something simple here (the e value that it accepts is a formatted URL):
function doGet(e){
var params = JSON.stringify(e);
var message = "thank you, your Decision has been sent.";
var id = '10kf5QDeBc-vr6XJnkFxQh-ch_poQhqBQWQbgJ';
var ss = SpreadsheetApp.openById(id);
// var ss = SpreadsheetApp.getActiveSpreadsheet();
// var sheet = ss.getActiveSheet();
var sheet = ss.getSheets()[0];
var column = 20;
var datecolumn = 5;
var row = e.parameter.row;
//var title = sheet.getTitle();
var sheetname = ss.getSheetName();
var sheetnamesheet = sheet.getName();
var eventDaterange = sheet.getRange(row, datecolumn);
var eventDate = eventDaterange.getvalues();
var approval_cell = sheet.getRange(row, column);
//set default to declined
approval_cell.setValue("declined");
var approvedMessage = "<HTML><body>"+
"<h2>your request has been Approved </h2><br />"
+"<P>" + title +" " + sheet
+"<p>" + " for this date: "+ eventDate;
var deniedMessage = "<HTML><body>"+
"<h2>your request has been denied </h2><br />"
+"<P>" + ss +" " + sheet
+"<p>" + " for this date: "+ eventDate;
var aprovalResponce = (e.parameter.approval == 'true') ? approvedMessage : deniedMessage;
//var msg = "Your manager said this: " + aprovalResponce;
var msg = aprovalResponce
var replyEmail = e.parameter.reply;
if (e.parameter.approval == 'true') {
approval_cell.setValue("APPROVED");
} else {
approval_cell.setValue("DECLINED");
}
//send the actual email out
//MailApp.sendEmail(replyEmail, "Approval Request", msg);
MailApp.sendEmail(replyEmail, "Approval Request", {htmlBody: msg});
return HtmlService.createHtmlOutput(message);
}
To get values from a range, you use var values = range.getValues(); This will return a result in an 2D array of values, which is like a grid representing the range, i.e. values[row][column]. So, if our range is, say, "A1:C3", and we want the values in A1 and C3, we could do this:
var range = sheet.getRange("A1:C3");
var values = range.getValues();
var valueOne = values[0][0];
var valueTwo = values[2][2];
var msg = '"Form name" + valueOne + ValueTwo'
I don't know how to get the form name though, perhaps something as simple as e.source.title? If not, if you are using multiple forms, you may have to do this by getting the form Id from the form being submitted, and then using a switch statement to match that ID to a list of form names within your script.
Related
Here is my coding. Help me out.
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1").activate();
var lr = ss.getLastRow();
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Template").getRange(1,1).getValue();
//for (var i =2;i<=lr;i++){
var currentEmail = column(i,1);
var currentClass = column(i,3).getValues();
var currentName = ss.getRange(i,2).getValues();
var messageBody = templateText.replace("{name}",currentName).replace("{class}",currentClass);
var subjectLine = "Reminder:" + currentClass + " Upcoming Class";
MailApp.sendEmail(currentEmail,subjectLine,messageBody);
Issue:
There are many issues in your code, including undefined variables (e.g. column, i), but I think you want to do the following:
Send an email for each row in Sheet1, taking into account that:
recipient is in column A.
subject is based on the value of column C.
The message body is built by replacing the keywords {name} and {class} from a string template found in Template!A1 with the values of column B and C respectively.
Code snippet:
If the above is correct, you can do the following:
function yourFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Sheet1");
var firstRow = 2;
var numRows = sheet1.getLastRow() - firstRow + 1;
var templateText = ss.getSheetByName("Template").getRange(1,1).getValue();
var values = sheet1.getRange(firstRow,1,numRows,3).getValues(); // Retrieve data from all rows
values.forEach(row => { // Iterate through each row
var [currentEmail, currentName, currentClass] = row; // Get values from columns A-C
var messageBody = templateText.replace("{name}",currentName)
.replace("{class}",currentClass);
var subjectLine = "Reminder:" + currentClass + " Upcoming Class";
MailApp.sendEmail(currentEmail,subjectLine,messageBody);
});
}
Reference:
Tutorial: Sending emails from a Spreadsheet
Best Practices
This script works, except it sends multiple emails, This script check Column F for any value above 0 then sends an email.Column F is where i manually enter data. Trying to get it to only send one email and put a "Email Sent" in column H. Then check if column H has a "Email Sent" if so don't send email again.
Here Is what my sheet looks like
https://docs.google.com/spreadsheets/d/1o5jKMDECIFozrwAQx6EDvPL1NkoMQ1nbpkd6AdS9ULk/edit?usp=sharing
function sendEmails() {
var sSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses"); //get the sheet "Form Responses"
var data = sSheet.getRange(2, 1, sSheet.getLastRow(),sSheet.getLastColumn()).getValues(); //get the values of your table, without the header
var lastRow = sSheet.getLastRow();//gets the last row of entered data
var yourColumn = "H";//set your column
var yourFunction = ("Email Sent");//whatever function or formula or data you want,just don't forget to use lastRow do do the row number
sSheet.getRange(yourColumn+lastRow).setValue(yourFunction);
for (var i = 0; i < data.length; i++) { // For each element of your tab
var row = data[i];
if(row[5] > 0) { // If the person have got at least 1 report outstanding (column E)
var body = "Good day "+ row[0] + " you have " + row[5] + " Internal Audit reports outstanding.";
GmailApp.sendEmail(row[1],"Outstanding Internal Audit Reports", body); // Sending a mail to alert
}
}
}
Try This:
function sendEmailsToTechs() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Form Responses");
//var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var data=rg.getValues();
var hRange=sh.getRange(2,8,sh.getLastRow(),1);
var hValues=hRange.getValues();
for (var i=1;i<data.length;i++){
var row = data[i];
if(row[5] && row[7]!='Email Sent') {
var body = "Good day "+ row[0] + " you have " + row[5] + " Internal Audit reports outstanding.";
GmailApp.sendEmail(row[1],"Outstanding Internal Audit Reports", body);
//Logger.log(body);
hValues[i-1][0]='Email Sent';
}
}
hRange.setValues(hValues);//Puts the values into the spreadsheet all at one time.
}
Is it possible to encrypt a converted google sheet into PDF before sending it as an attachment in an email ?
This is my current code: It hides the sheet I don't need to be converted and converting the other sheet into PDF. What I would like to achieve here is for the converted PDF to be password encrypted because it contains some personal information.
function myFunction() {
Utilities.sleep(200);
var sheet=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
var pdfsheet=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
sheet.hideSheet();
var substringsubject = pdfsheet.getRange("B4:B4").getValues();
var substringnname = pdfsheet.getRange("B3:B3").getValues();
var substringidnum = pdfsheet.getRange("B7:B7").getValues();
var startRow =9; // First row of data to process B9:B9
var numRows =1; // Number of rows to process
// Fetch the range of cells B9:B9
var dataRange = pdfsheet.getRange(startRow, 1, numRows, 2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var email = row[1];
var emailcc = row[2];
// Subject of email message
var subject = "USER ACCOUNT DETAILS " + substringsubject + " " + substringidnum + "";
var ss= SpreadsheetApp.getActiveSpreadsheet();
// Email Body can be HTML too
var body = '<body>' + ' Hi ' + substringnname +',<br><br>' +
'Please see attached file for your account details.</p>' +
//'<p> Click here to go to google.<p>'
'</body>'
var pdf = DriveApp.getFileById(ss.getId()).getAs("application/pdf");
pdf.setName(substringsubject+" "+substringidnum+" .pdf");
// If allowed to send emails, send the email with the PDF attachment
MailApp.sendEmail({
to:email,
cc:emailcc,
subject:subject,
htmlBody:body,
attachments:[pdf]
});
sheet.showSheet();
}
}
Thank you.
You can't protect your PDF directly from Apps script. See this previous SO question.
I am hoping someone can help me with this issue. I am new to coding. I have a google spreadsheet with a script that pushes out an email. I am attempting to have the script ignore the rows where the script has already sent out an email on.
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Email Menu')
.addItem('Send Email', 'myFunction')
.addSeparator()
.addToUi();
};
function myFunction() {
var msg = 'Email sent!';
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getActiveSheet();
var range = sheet.getDataRange();
var values = range.getValues();
var EMAIL_SENT = "EMAIL_SENT";
var startRow = 2;
for (i=1; i<values.length;i++) {
//sent = values[i][4]; //added this in to try and skip a row if "X" was in Sent Column
//if (sent ==" ", ) //added this in to try and skip a row if "X" was in Send Column
var email = values[i][0];
var name = values[i][i];
var subject = values[i][2];
var body = values[i][3];
var sent = values[i][5];
if (sent != EMAIL_SENT){
MailApp.sendEmail(email, subject, body);
sheet.getRange(startRow + i,5).setValue(EMAIL_SENT);
SpreadsheetApp.getUi().alert(msg);
}
}}
Google spreadsheet
Implement the following changes in your for loop:
for (i=1; i<values.length;i++) {
var email = values[i][0];
var name = values[i][1]; //not [i][i] !
var subject = values[i][2];
var body = values[i][3];
var sent = values[i][4];
if (sent !== EMAIL_SENT){
sheet.getRange(i+1,5).setValue(EMAIL_SENT);
}
}
Basically get rid of the startRow variable (if you are not using elsewhere) and just use (i+1,5) to place "EMAIL_SENT" in the right column. I have removed parts of your code for the sake of clarity.
Small fix. Replace
sheet.getRange(startRow + i,5).setValue(EMAIL_SENT);
to
sheet.getRange(startRow + i - 1, 6).setValue(EMAIL_SENT);
According to the rest of the script, this should be the most simple fix. This assumes sent column is F (column 6) not E (column 5). Sample sheet including updated script is here.
And! You should change var name = values[i][i]; to var name = values[i][1]; as #jrook pointed. I missed it...
I've been searching for the answer to this question but have so far been unable to piece together the answer. Please explain any answer you have in really simple terms as I'm fairly new to GAS and RegEx. I've got most of the syntax down but the execution of it in GAS is giving me a hard time.
Basically, I want to write a script that, when the spreadsheet is edited, checks which rows have yet to be merged. Then, on those rows, creates a copy of a template Google Doc and names the document based on the spreadsheet data. From there (this is the hard part), I need it to replace merge tags in the template with the data from the spreadsheet.
The tags in the templates I'll be using look like this: <<mergeTag>>
My idea was to match the whole tag, and replace it with data from the spreadsheet that exists in the column with the same name as what's inside the "<<>>". Ex: <<FooBar>> would be replaced with the data from the column named FooBar. It would obviously be from the current row that needs the merging.
After that, all that's left is to send an email (a few more row-specific personalization) with that document attached (sometimes as a PDF) with the body of the message coming from an HTML file elsewhere in the project.
This is the whole thing I have so far (notice the placeholders here and there that I can personalize for each spreadsheet I use this for):
function onEdit() {
//SPREADSHEET GLOBAL VARIABLES
var ss = SpreadsheetApp.getActiveSpreadsheet();
//get only the merge sheet
var sheet = ss.getSheetByName("Merge Data");
//get all values for later reference
var range = sheet.getActiveRange();
var values = range.getValues();
var lastRow = range.getLastRow();
var lastColumn = range.getLastColumn();
//get merge checker ranges
var urlColumn = range.getLastColumn();
var checkColumn = (urlColumn - 1);
var checkRow = range.getLastRow();
var checkRange = sheet.getRange(2, checkColumn, checkRow);
var check = checkRange.getBackgrounds();
//get template determination range (unique to each project)
var tempConditionRange = sheet.getRange(row, column);
var tempConditionCheck = tempConditionRange.getValues();
//set color variables for status cell
var red = "#FF0000";
var yellow = "#FFCC00";
var green = "#33CC33";
//////////////////////////////////////////////////////////
//DOC GLOBAL VARIABLES
var docTemplate1 = DriveApp.getFileById(id);
var docTemplate2 = DriveApp.getFileById(id);
var docTemplate3 = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
//////////////////////////////////////////////////////////
//EMAIL GLOBAL VARIABLES
var emailTag = ss.getRangeByName("Merge Data!EmailTag");
var personalizers = "";
var subject = "" + personalizers;
var emailBody = HtmlService.createHtmlOutputFromFile("Email Template");
//////////////////////////////////////////////////////////
// MERGE CODE
for (i = 0; i < check.length; i++) {
//for rows with data, check if they have already been merged
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, lastRow, (lastColumn - 2))
statusCell.setBackground(red);
//for rows with data, but not yet merged, perform the merge code
//////////////////////////////////////////////////////////
//DOC CREATION
//Determine which template to use
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate1;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate2;
}
if (tempConditionCheck[i] == "") {
var docToUse = docTemplate3;
}
//Create a copy of the template
//Rename the document using data from specific columns, at specific rows
//Move the doc to the correct folder
var docName = "";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docToSend = DriveApp.getFileById(docId);
var docBody = DocumentApp.openById(docId).getBody();
Here's where I need the help
//Locate the Merge Tags
//Match Merge Tags to the column headers of the same name
//Replace the Merge Tags with the data from the matched column, from the correct row
function tagReplace() {
var tagMatch = "/(<{2}(\w+)>{2})/g";
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
The rest is just finishing up the process
//////////////////////////////////////////////////////////
//EMAIL CREATION
//Create an email using an HTML template
//Use Merge Tags to personalize email
//Attach the doc we created to the email
//Send email to recipients based on data in the sheet
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Person McPerson",
attachments: [docToSend], //[docToSend.getAs(MIME.PDF)],
html: emailBody,
});
//////////////////////////////////////////////////////////
//CHECK ROW UPDATE
statusCell.setBackground(green);
}
}
}
My sheets all have a frozen first row that acts as the header row. All my columns will be consistently named the exact same thing as the tags (minus the <<>>).
How do I match the tags to the data?
EDIT
```````````````````
The solution did not work as described when I inserted it into my code as follows:
function formMerge() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Merge Data");
var urlColumn = sheet.getMaxColumns();
var checkColumn = urlColumn - 1;
var lastRow = ss.getSheetByName("Form Responses").getLastRow();
var values = sheet.getDataRange().getValues();
var headers = values[0];
var urlRange = sheet.getRange(2, urlColumn, lastRow);
var checkRange = sheet.getRange(2, checkColumn, lastRow);
var check = checkRange.getBackgrounds();
var red = "#ff0404";
var yellow = "#ffec0a";
var green = "#3bec3b";
var docTemplate = DriveApp.getFileById(id);
var folderDestination = DriveApp.getFolderById(id);
// MERGE CODE
for (i = 0; i < check.length; i++) {
if (check[i] == green) {
continue;
} else {
var statusCell = sheet.getRange((i+2), checkColumn, 1, 1);
var urlCell = sheet.getRange((i+2), urlColumn, 1, 1);
var dataRow = sheet.getRange((i+2), 1, 1, (urlColumn - 2)).getValues();
var clientNameRange = sheet.getRange((i+2), 3);
var clientName = clientNameRange.getValue();
var dateRange = sheet.getRange((i+2), 2);
var datePreFormat = dateRange.getValue();
var timeZone = CalendarApp.getTimeZone();
var date = Utilities.formatDate(new Date(datePreFormat), timeZone, "MM/dd/yyyy");
statusCell.setBackground(red);
//EMAIL VARIABLES
var personalizers = clientName;
var subject = "Post Intake Report for " + personalizers;
var emailBody = "Please see the attached Google Doc for the Post Intake Report for " + clientName + ". The intake was performed on " + date + ".";
var emailTagRange = sheet.getRange((i+2), 24);
var emailTagValue = emailTagRange.getValue();
var emailTag = emailTagValue.split(", ");
//DOC CREATION
var docToUse = docTemplate;
var docName = "Post Intake Report - " + clientName + " [" + date + "]";
var docCopy = docToUse.makeCopy(docName, folderDestination);
var docId = docCopy.getId();
var docURL = docCopy.getUrl();
var docBody = DocumentApp.openById(docId).getBody().editAsText();
for (var j=0; j<headers.length; j++) {
var re = new RegExp("(<<"+headers[j]+">>)","g");
docBody.replaceText(re, dataRow[j]);
}
statusCell.setBackground(yellow);
urlCell.setValue(docURL);
//EMAIL CREATION
MailApp.sendEmail(emailTag, subject, emailBody, {
name: "Christopher Anderson",
attachments: [docCopy],
html: emailBody
});
statusCell.setBackground(green);
}
}
}
Build the RegExp for each tag on the fly, using the header values from your spreadsheet.
Use Body.replaceText() to perform the replacements.
var values = sheet.getDataRange().getValues();
var headers = values[0];
...
// Loop over all columns. Use header names to search for tags.
for (var col=0; col<headers.length; col++) {
// Build RegExp using column header
var re = new RegExp("(<{2}"+headers[col]+">{2})","g");
// Replace tags with data from this column in dataRow
body.replaceText(re, dataRow[col]);
}
This snippet will operate on a single row; the first couple of declarations should appear outside of your row loop. The column looping is then done after you've created and opened the new document, and obtained the body object.
It loops over all the columns in the spreadsheet, using the header names to find the tags you've defined, and replaces them with the corresponding cell contents for the current row.