I am completely new to Google Scripts. I experimented with the script found here (as written by Snipe and edited by Govoni in the first comment).
What I am trying to do is combine both scripts, to get an email on form submit that would:
only show answered questions (it works)
format questions in bold (it works)
populate the subject line (I can't get it to work)
The code below works.
function newResponse()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formName = ss.getSheetByName('Form Responses 1');
var lastRow = formName.getLastRow();
var lastColumn = formName.getLastColumn();
var email = "sample#myemail.com";
var name = "My Email";
var subject = 'New form response: ';
var body = '';
var cell = '';
for (var i = 1; i <= lastColumn ; i++)
{
var title = formName.getRange(1,i).getDisplayValue();
var cell = formName.getRange(lastRow, i).getDisplayValue();
if (cell != '' && cell != 0)
{
body = body + '<b>'+ title + '</b>: ' + cell + '<br>';
};
};
MailApp.sendEmail({
to: email,
name: name,
subject: subject,
htmlBody: body
});
}
So, to try and add variable entries to the subject line I changed 'function newResponse()' to 'function newResponse(e)' and added this line before MailApp:sendEmail:
// The email subject line should look like this: "New form response: Item (Company, Country)"
// Item, Company and Country are the 2nd, 3rd and 4th columns from my form
subject += e.namedValues[title[1]].toString() + " (" + e.namedValues[title[2]].toString()+ ", "
+ e.namedValues[title[3]].toString()+ ")";
But when I do this, it doesn't send an email at all. If I change e.namedValues and instead put something like [title[0]], it then returns the first letter of the last question answered.
I am not quite sure what to try next?
From your code snippet, I suppose title variable holds a string, so title[0] is the first character of the string. e.namedValues[title[1]] will be undefined if no questions are single-character. undefined.toString() will throw an error, crashing the entire script.
You'll need to save an array of titles of all columns in the sheet.
var titles = [];
for (var i = 1; i <= lastColumn ; i++) {
var title = formName.getRange(1,i).getDisplayValue();
titles.push(title);
var cell = formName.getRange(lastRow, i).getDisplayValue();
...
}
Afterwards, you'll be able to use e.namedValues[titles[1]]. Note that I use titles, the array.
Subject is not a member of the advanced parameters object its just a mailapp.senEdmail parameter.
Try:
sendEmail(email, subject, '', {name: name, htmlBody: body});
Related
I am new to Google Apps Script. I have a sheet that collects some "Order Number" from form submit. I want to send mails through an event (On form submit) from my spreadsheet. The form will serve an order number. When the form is submitted, it will match the older submitted order numbers throughout the whole column. If it got matched once, the mail won't be sent. If it doesn't match then it will send a mail to the email address next to the order number.
The email address will come from another sheet on the same spreadsheet using VLOOKUP. I managed to do this.
Sorry if I make any mistake with my English.
Edit:
I tried map() , filter() , indexOf() these methods. But I too new with this.
function search(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Copy of orderStatus");
var lr = ss.getLastRow() - 1;
var keyword = ss.getRange("H5").getValue();
var dataSource = ss.getRange(2, 2, lr, 1).getValues();
var mapped = dataSource.map(function(r){
return r[0]});
var showPos = mapped.indexOf(keyword) + 2;
var getMail = ss.getRange(showPos, 4).getValue();
var filted = mapped.filter(filterlogic);
}
var filterlogic = function(r){
if(r !== "zil20200010"){
return true;
} else {
return false;
}
}
On form submit, select the column (range) where you store all the order numbers and create a TextFinder and store it in a variable using the createTextFinder(findText) method for the specified range.
Get the TextFinder from the previous step and search the order number using the findNext() method.
If findNext() returns null then move to the next step. else, do nothing.
Get the email address to which you plan to send the order number.
After having the email address, use the sendEmail(recipient, subject, body, options) method to send the email. If you'd like, you can use HTML in the body to make it more professional.
For additional information, read:
the reference guide on creating TextFinders,
the reference guide on finding text using a TextFinder,
and the reference guide on GmailApp.
Sample code:
// imagine you store all the order numbers in column C, starting from row 2 to the last row in the column:
var emailRecipient = test#test.com;
var ordernumber = 123;
var RangeToSearch = sheet.getRange(2,3,sheet.getLastRow());
var TextFinder = RangeToSearch.createTextFinder(ordernumber);
var found = TextFinder.findNext();
if (found == null) {
MailApp.sendEmail({
to: emailRecipient,
subject: "New Order! Order Number: " + ordernumber,
htmlBody: html
});
}
First of all, thanks to all of you who helped me to reach this point. I found the solution to my problem after some "trial and error". I wanted to limit sending emails.
This code takes the Range. Get its values in an array. I mapped that array to act as a string. Then I added .pop() to that string, it removes our last/newly submitted data in that range. Then I used .includes() method to search my value in the mapped array, and assigned it to a variable called final (just came to my mind). This variable returns true/false depending on search results. If the order number does not exist then it returns false. After that, we set an if statement to execute our mailing function. If our order number does not match and return final as false our mailing function happens. Else it does nothing (means no email sents). And that's it!
Here is the code that solved my problem
function orderStatus(e) {
try {
var theirMail, subject, message;
var ourName, theirName;
var sSheet, orderNum, cosmetics, orderSts, phNum, lr,dataSource, mapped, final;
ourName = "My Company Name";
orderNum = e.namedValues["Order Number"].toString();
sSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("orderStatus");
lr = sSheet.getLastRow() - 1;
dataSource = sSheet.getRange(2, 2, lr).getValues();
mapped = dataSource.map(function(r){
return r[0].toString()});
mapped.pop();
final = mapped.includes(orderNum);
orderSts = sSheet.getRange(sSheet.getLastRow(),1).getValue();
theirMail = sSheet.getRange(sSheet.getLastRow(),4).getValue();
theirName = sSheet.getRange(sSheet.getLastRow(),5).getValue();
phNum = sSheet.getRange(sSheet.getLastRow(),6).getValue();
subject = "Order status notification from " + ourName + " to " + theirName;
if (final == false){
message =
"<div style='text-align: left; padding-left: 30px;'><h2>Dear <b>" + theirName +
",</b></h2><p>Your order no is <b><span style='font-size: 14px;'>" + orderNum +
"</span>.</b> <b><span style='font-size: 14px;'>Your order has been processed.</span>" +
"</b></p><p>We packaged your order and dropped it to the logistics. You will recieve phone call on <b><span style='font-size: 14px;'>" + phNum +
"</span></b> from logistics.<br>Thanks for purchasing from <b><span style='font-size: 14px;'>" + ourName +
"</span></b>.</p><p>Best regards,<br><b><span style='font-size: 14px;'>"+ourName+"</span></b></p></div>"+
"<p style='text-align: center;'><br><b>For further information please visit our facebook page <a href='https://www.facebook.com/' target='_blank' rel='noopener'>"+ourName+"</a>.</b></p><hr />";
textbody = message.replace("<br>", "\n\n");
cosmetics = {name: ourName, htmlBody: message};
MailApp.sendEmail(theirMail, subject, message, cosmetics);
}
}
catch (e) {
Logger.log(e.toString());
}
}
I have an emailer script that I would like to run for specified tabs and also make sure it skips any rows with blank values as it currently seems to break down as soon as it hits a blank row.
I have successfully built the script to work for one tab, but it seems to break down as soon as I try and get it to work for multiple tabs.
function reminders() {
var ss = SpreadsheetApp.openById("SHEET-ID");
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3")));
var editedCell = sheet.getActiveRange().getColumnIndex();
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++)
(function(val) {
var row = data[i];
var recipient = row[4];
var name = row[2];
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
})(i);
}
This currently works for sheet_1 but does not work for sheet_2 or sheet_3.
Does anyone have any suggestions for how I can improve this script to send to multiple sheets and also skip blank rows?
You want to send emails using the values of column "C" and "E" from the Spreadsheet.
You want to run your script for the sheet names of "sheet_1", "sheet_2" and "sheet_3".
You want to skip the rows which have no values of the column "C" and/or "E".
If my understanding is correct, how about this modification?
Modification points:
It seems that when var sheet = SpreadsheetApp.setActiveSheet(ss.getSheetByName(("sheet_1","sheet_2","sheet_3"))); is run, only "sheet_3" is retrieved.
In your case, I think that setActiveSheet() might not be required to be used.
Number of arguments of getSheetByName(("sheet_1","sheet_2","sheet_3")) is one.
When you want to use multiple sheets, please use each sheet name in the loop.
var editedCell = sheet.getActiveRange().getColumnIndex(); is not used in your script.
val of (function(val) { is not used in your script.
When you want to skip the empty rows, please put the if statement before GmailApp.sendEmail(). By this, the error is removed at GmailApp.sendEmail().
When above points are reflected to your script, it becomes as follows. Please think of this as just one of several answers.
Modified script:
Please copy and paste the following modified script to the script editor.
function reminders() {
var sheets = ["sheet_1","sheet_2","sheet_3"]; // Please set the sheet names here.
var ss = SpreadsheetApp.openById("SHEET-ID");
for (var s = 0; s < sheets.length; s++) {
var sheet = ss.getSheetByName(sheets[s]);
var dataRange = sheet.getDataRange();
var data = dataRange.getValues();
var text1 = 'Insert body of email here';
for (var i = 1; i < data.length; i++) {
var row = data[i];
var recipient = row[4];
var name = row[2];
if (!recipient || !name) continue; // Here, the empty rows are skipped.
var replyto = 'reply_to#email.com';
var body = 'Dear' + ' ' + name + ',' + '\n\n' + text1;
var subject = 'Hello World';
GmailApp.sendEmail(recipient, subject, body, {from:'reply_to#email.com', replyto:'reply_to#email.com'});
}
}
}
Note:
In this modified script, when "recipient" or "name" are not existing, the row is skipped.
When you send a lot of emails, please be careful the quotas of "Email read/write". You can see it at here.
References:
getSheetByName(name)
Quotas for Google Services
If I misunderstood your question and this was not the result you want, I apologize.
My goal is to create email drafts automatically from a Google Sheets list. Everything works mostly, the only problem I am having is that the message in the email just says [object Object].
The subject is fine, the email address is fine, and the break to keep it from sending to the same person again is fine.
I am not sure what is wrong.... but I am guessing it starts at //Build the email message.
Any suggestions?
I have the following:
var EMAIL_DRAFTED = "EMAIL DRAFTED";
function draftPastDueEmails() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 2; // 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 = 0; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var clientName = row[12]; // Client name
var clientEmail = row[14]; // Client email
var reference = row[1]; // Account Reference
var invNum = row[0]; // Invoice number
var emailStatus = row[20]; // Email Status
// Prevent from drafing duplicates and from drafting emails without a recipient
if (emailStatus !== EMAIL_DRAFTED && clientEmail) {
// Build the email message
var emailBody = '<p>Hello ' +clientName+ ',</p>';
emailBody += '<p>I hope all is well.</p>';
emailBody += '<p>I noticed that invoice <strong>' +invNum+ '</strong> is currently past due.</p>';
emailBody += '<p>Could you please take a moment to check your records to see if a payment has been made and provide a receipt to allow me to track it in my system.</p>';
emailBody += '<p>If no payment has been made for whatever reason, please do so as soon as possible so I can post it to your account.</p>';
emailBody += '<p>Please let me know if you have any questions.</p>';
emailBody += '<p>Best,</p>';
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference+ // Subject
'',
{
htmlBody: emailBody // Options: Body (HTML)
}
);
sheet.getRange(startRow + i, lastColumn).setValue(EMAIL_DRAFTED); // Update the last column with "EMAIL_DRAFTED"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
}
}
}
It looks like the problem is here:
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference+ // Subject
'',
{
htmlBody: emailBody // Options: Body (HTML)
}
);
The method is expecting 3 strings -- a recipient, subject and a body -- followed by options with your "htmlBody" parameter. The code above only provides a recipient and a subject. Try this instead:
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
'Past due account - '+reference, // Subject
'', // Plaintext body
{
htmlBody: emailBody // Options: Body (HTML)
}
);
I'm trying to set up an email alert system based on a project tracking sheet my team uses at work. I need it to send an email when a task's status is changed to "Done" in column K. I got the code to work on a test sheet, but when I copy it to the live sheet the getValue() code stops working? Since the email is sent based on if() statements, the script runs, but doesn't actually work. I'm not sure if it's a permissions issue since I am not the owner of the live sheet?
I hope that is descriptive enough -- I have taught myself javascript in order to get this working and it seems so close, but I am stuck!!
Here is a screenshot of what the project tracking sheet looks like.
function emailUpdate(e) {
var emailInfoRange = sheet.getRange("B:O");
var edit = e.range.getA1Notation(); // Gets edited cell location
var editColumn = edit.substring(0,1) // Gets column of edited cell
var editRow = edit.substring(1,3) // Gets row of edited cell
if(editColumn == "K") { // gets all relevent information needed for email
var taskTypeCell = emailInfoRange.getCell(editRow,1);
var taskType = taskTypeCell.getValue();
var requestedByCell = emailInfoRange.getCell(editRow,3);
var requestedBy = requestedByCell.getValue();
var emailRequestCell = emailInfoRange.getCell(editRow,4);
var emailRequest = emailRequestCell.getValue();
var projectIdCell = emailInfoRange.getCell(editRow,5);
var projectID = projectIdCell.getValue();
var taskDescriptionCell = emailInfoRange.getCell(editRow,6);
var taskDescription = taskDescriptionCell.getValue();
var claimedByCell = emailInfoRange.getCell(editRow,9);
var claimedBy = claimedByCell.getValue();
var taskStatusCell = emailInfoRange.getCell(editRow,10);
var taskStatus = taskStatusCell.getValue();
if(taskStatus == "Done") {
if(emailRequest == "Yes" || emailRequest == "yes") { // Determines if status is "Done", and email notification is "Yes" or "yes"
var emailAddress;
var getEmailAddress = function(personelArray) { // Defines function to search email address arrays for the one that belongs to requestedBy
for (var i = 0; i < personelArray.length; i++) {
if(requestedBy === personelArray[i]) {
emailAddress = personelArray[i+1];
} } }
// Searches through all email arrays to find the one belonging to requester
getEmailAddress(specialistsAndEmails)
getEmailAddress(coordinatorsAndEmails)
getEmailAddress(managersAndEmails)
// Sends email
MailApp.sendEmail(emailAddress,
"AUTOGEN: " + taskType + " for " + projectID + " " + taskDescription + " completed by " + claimedBy + ".", "This email has been automatically generated by an edit to the work available sheet. \n"
+ "PLEASE DO NOT REPLY");
} else (Logger.log("No email requested"))
} else (Logger.log("Status not changed to done"))
} else (Logger.log("Update not to status cell"))
}
I would make the following changes to help prevent issues with string manipulations. Which could be the cause for your issues with getValues().
function emailUpdate(e) {
var emailInfoRange = sheet.getRange("B:O");
var edit = e.range // Gets edited cell location
var editColumn = edit.getColumn() // Gets column of edited cell
var editRow = edit.getRow() // Gets row of edited cell
if(editColumn == 11) // Column K should correspond to column number 11, if i can count correctly.
{
/// Remainder of the code should be the same as above
}
}
So instead of converting the range to A1 notation, you should get column number and row number using getColumn and getRow() on the range object. This will prevent issues with text to number manipulation and could be the cause of your problems.
I have a Spreadsheet in Google Drive, which has two sheet in it "Production" and "Germination"
For the Production sheet, I to an email notification if a change has been made to the columns from A - F. Also if there is a row added or delete from the sheet.
The following code does the trick to some extent:
function onEdit( e ){
//To get email notification if any changes to the perticular cells
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("production");
var cell = ss.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
var recipients = "zeeshanrang#gmail.com";
var message = '';
if(cell.indexOf('C')!=-1){
message = sheet.getRange('D'+ sheet.getActiveCell().getRowIndex()).getValue()
}
var subject = 'Update to '+sheet.getName();
var body = sheet.getName() + ' has been updated. Visit ' + ss.getUrl() + ' to view the changes on row: «' + row + '». New comment: «' + cellvalue + '». For message: «' + message + '»';
Logger.log(body);
//MailApp.sendEmail(recipients, subject, body);
};
But it sends me a mail on every edit, which is not required. It's required to send mail once every hour (if there is a change). Also right now it is only checking for changes on only Column C and not the rest of them.
Also, I was unable to understand if(cell.indexOf('C')!=-1) . Can someone explain me what does this statement means.
TIA
It means the following:
if(cell.indexOf('C')!=-1) // means that if you edit column C
....... //the following will happen
}
So to explain in more detail:
cell.indexOf('C')-> search for 'C'
!= -> Does not equal
-1 -> not there/ not found
if(cell.indexOf('C')!=-1) -> if indexOf('C') does not equal '-1' (i.e. if 'C' is there, do the 'if' statement