Correct script to send only the last row of data in Google Sheets - javascript

The script I have is sending out the information in the format I want. The problem I have is that it is sending out each row as an indiviual email instead of only sending out the latest data. I only want the last row of data to be sent out.
function CustomEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
lastRow = sheet.getLastRow();
startrow= 2;
var range = sheet.getRange("A2:Z1000");
var UserData = range.getValues();
for (i in UserData) {
var row = UserData[i];
var name = row[2];//market
var senderEmail = ''
if (name === 'South')
{senderEmail = 'tom#no.com';}
else if (name === 'West')
{senderEmail = 'bob#bob.com';}
else if (name === 'East')
{senderEmail = 'non#no.com';}
var AgentOwner = row[18];//Agent Owner
var address = row[20];//Address
var City = row[21];//City
var State = row[22]//state
var Incident = row[17]//incident type
var Date = row[4]//date and time
emailBody = "New Security Incident Report from: " +AgentOwner+ "\nAddress: " +address+ "\nCity: " +City+ "\nState: " +State + "\nIncident: " +Incident + "\nDateTime:" +Date
MailApp.sendEmail(senderEmail,"Security Incident Report", emailBody);
}
}

Try this -
function CustomEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getRange(sheet.getLastRow(), 1, 1, sheet.getLastColumn())[0];
Logger.log(row);
var name = row[2]; //market
var senderEmail = '';
if (name === 'South') {
senderEmail = 'tom#no.com';
} else if (name === 'West') {
senderEmail = 'bob#bob.com';
} else if (name === 'East') {
senderEmail = 'non#no.com';
}
var AgentOwner = row[18]; //Agent Owner
var address = row[20]; //Address
var City = row[21]; //City
var State = row[22]; //state
var Incident = row[17]; //incident type
var Date = row[4]; //date and time
emailBody =
'New Security Incident Report from: ' +
AgentOwner +
'\nAddress: ' +
address +
'\nCity: ' +
City +
'\nState: ' +
State +
'\nIncident: ' +
Incident +
'\nDateTime:' +
Date;
MailApp.sendEmail(senderEmail, 'Security Incident Report', emailBody);
}
Edit:
Go to script, paste new code, run the function, then in menu, View > Log and see if the row values are logged properly. If any issues with data indices, adjust them accordingly.

Related

Google Sheet Auto Email Script

I have a form that contains 84 questions, not all of them are mandatory.
This is the script I manage to write so far:
function SendEmail() {
var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var StartRow = 2;
var RowRange = ActiveSheet.getLastRow() - StartRow + 1;
var WholeRange = ActiveSheet.getRange(StartRow,1,RowRange,84);
var AllValues = WholeRange.getValues();
var message = "";
for (i in AllValues) {
var CurrentRow = AllValues[i];
var EmailSent = CurrentRow[85];
if (EmailSent == "Sent")
continue;
# I know this part takes only the first 5 column, I wrote them only as an example. In bold the headers of each column.
message =
"<p><b>Kind of content: </b>" + CurrentRow[2] + "</p>" +
"<p><b>Project Name: </b>" + CurrentRow[3] + "</p>" +
"<p><b>Project Description: </b>" + CurrentRow[4] + "</p>" +
"<p><b>Name of your team: </b>" + CurrentRow[5] + "</p>" +
"<p><b>Scope of work: </b>" + CurrentRow[6] + "</p>";
var setRow = parseInt(i) + StartRow;
ActiveSheet.getRange(setRow, 85).setValue("sent");
}
var SendTo = "email#gmail.com";
var Subject = "New"+" " + CurrentRow[2] +" "+"project request";
MailApp.sendEmail({
to: SendTo,
cc: "",
subject: Subject,
htmlBody: message,
});
}
What I want is to send an email every time somebody fills the form and the content of the email should include only the last row and only the columns with data with their header.
The way this script is written will generate an email with 84 rows, most of them empty and not relevant. Can somebody give me a hand with it?
Thank you so much for your help!!
You can use sheet.getLastRow() to get the index of the last row in the sheet that has data.
For finding columns that have data, you can iterate through the row data and look for cell values that are not blank.
var header = sheet
.getRange(1,1,1,sheet.getLastColumn())
.getDisplayValues()[0];
var data = sheet
.getRange(sheet.getLastRow(),1,1,sheet.getLastColumn())
.getDisplayValues()[0];
var output = [];
for (var d=0; d<data.length; d++) {
if (data[d] !== "") {
output.push(header[d] + " = " + data[d]);
}
}
return data.join("\n");
I know you are too naive to coding and Amit is a busy person, so just to help you, I am plugging in the code he has provided to your code with a small correction, so you can just copy the entire code :)
function SendEmail() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lRow = sheet.getLastRow();
var emailSent = sheet.getRange(lRow, 86).getValue();
var header = sheet
.getRange(1,1,1,sheet.getLastColumn())
.getDisplayValues()[0];
if (emailSent != "Sent"){
var data = sheet
.getRange(lRow,1,1,sheet.getLastColumn())
.getDisplayValues()[0];
var output = [];
for (var d=0; d<data.length; d++) {
if (data[d] !== "") {
output.push(header[d] + " = " + data[d]);
}
}
var message = output.join("\n");
var SendTo = "email#gmail.com";
var Subject = "New"+" " + sheet.getRange(lRow, 3).getValue() +" "+"project request";
MailApp.sendEmail({
to: SendTo,
cc: "",
subject: Subject,
htmlBody: message,
});
sheet.getRange(lRow, 86).setValue("sent");
}
}
You can use filter, for example
var AllValues = WholeRange.getValues().filter( row => row[5] != '');
will reduce AllValues to only those there column 6 isn't empty

Google Apps Script - Setting a row to complete only after it's been ran through the loop

I have Google Apps Script which inputs events into my google calendar from a spreadsheet. Anyone know how to have the script set a row's background color to green & last column value to "complete" only if it's been ran through the loop?
Currently I have it just setting the full range to these parameters, but would like to prevent certain rows from being included if the last column is equal to "Invalid".
function inputEvents() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange("B1").getValue();
var calendar = CalendarApp.getCalendarById(calendarId)
var lr = spreadsheet.getLastRow();
var count = spreadsheet.getRange("A3:AF"+lr+"").getValues();
for (x=0; x<count.length; x++) {
var events = count[x];
var name = events[2];
var phone = events[3];
var email = events[4];
var title = events[5];
var startTime = events[6];
var endTime = events[7];
var description = events[8];
var location = events[9];
var eventId = events[31];
var contactHeader = "CONTACT:";
var descriptionHeader = "DESCRIPTION:";
var complete = "Complete";
var invalid = "Invalid";
var info =
contactHeader.bold() + "\n"
+ name + "\n"
+ phone + "\n"
+ email + "\n"
+ "\n" + descriptionHeader.bold() + "\n"
+ description;
var options = {
'guests' : email,
'description': info,
'sendInvites': 'True',
'location': location,
}
if (eventId != complete && eventId != invalid){
calendar.createEvent(title, startTime, endTime, options);
spreadsheet.getRange("AF3:AF"+lr+"").activate().setValue('Complete');
spreadsheet.getRange("A3:AF"+lr+"").activate().setBackground('#d9ead3');
}
}
}
You're using the setValue and setBackground methods to the entire range, you need to apply them only to the range you're interested in, try setting a currentRow variable and change the range you're getting inside your if statement, like this:
var currentRow = 3 + x;
if (eventId != complete && eventId != invalid){
calendar.createEvent(title, startTime, endTime, options);
spreadsheet.getRange("AF" + currentRow).setValue('Complete');
spreadsheet.getRange("A"+ currentRow + ":AF" + currentRow).setBackground('#d9ead3');
}

Resolve 'Parsing Error: Please check your selector. (line XX)' Javascript/AWQL

First off, let me say that I am not a developer, nor do I really code beyond basic HTML. So I appreciate your patience. :)
I'm working with a script that is for AdWords, but I believe it's more or less written in Javascript. (I've included the script below.)
Basically, I'm receiving the error message 'Parsing Error: Please check your selector. (line XX)' when I preview the script.
I've searched all around for hours and have yet to find a solution.
I think it may be that a query being returned contains either a single or double quote, and may be messing up the code? Though I can't actually prove that.
Also, yes, I was sure to update lines 17-21 with the correct details.
Any help would be much appreciated!
Thanks!
John
/*
// AdWords Script: Put Data From AdWords Report In Google Sheets
// --------------------------------------------------------------
// Copyright 2017 Optmyzr Inc., All Rights Reserved
//
// This script takes a Google spreadsheet as input. Based on the column headers, data filters, and date range specified
// on this sheet, it will generate different reports.
//
// The goal is to let users create custom automatic reports with AdWords data that they can then include in an automated reporting
// tool like the one offered by Optmyzr.
//
//
// For more PPC management tools, visit www.optmyzr.com
//
*/
var DEBUG = 0; // set to 1 to get more details about what the script does while it runs; default = 0
var REPORT_SHEET_NAME = "report"; // the name of the tab where the report data should go
var SETTINGS_SHEET_NAME = "settings"; // the name of the tab where the filters and date range are specified
var SPREADSHEET_URL = "https://docs.google.com/spreadsheets/d/1dttJTb547L81XYKdTQ56LcfO9hHhbb9wm06ZY5mKhEo/edit#gid=0"; // The URL to the Google spreadsheet with your report template
var EMAIL_ADDRESSES = "example#example.com"; // Get notified by email at this address when a new report is ready
function main() {
var currentSetting = new Object();
currentSetting.ss = SPREADSHEET_URL;
// Read Settings Sheet
var settingsSheet = SpreadsheetApp.openByUrl(currentSetting.ss).getSheetByName(SETTINGS_SHEET_NAME);
var rows = settingsSheet.getDataRange();
var numRows = rows.getNumRows();
var numCols = rows.getNumColumns();
var values = rows.getValues();
var numSettingsRows = numRows - 1;
var sortString = "";
var filters = new Array();
for(var i = 0; i < numRows; i++) {
var row = values[i];
var settingName = row[0];
var settingOperator = row[1];
var settingValue = row[2];
var dataType = row[3];
debug(settingName + " " + settingOperator + " " + settingValue);
if(settingName.toLowerCase().indexOf("report type") != -1) {
var reportType = settingValue;
} else if(settingName.toLowerCase().indexOf("date range") != -1) {
var dateRange = settingValue;
} else if(settingName.toLowerCase().indexOf("sort order") != -1) {
var sortDirection = dataType || "DESC";
if(settingValue) var sortString = "ORDER BY " + settingValue + " " + sortDirection;
var sortColumnIndex = 1;
}else {
if(settingOperator && settingValue) {
if(dataType.toLowerCase().indexOf("long") != -1 || dataType.toLowerCase().indexOf("double") != -1 || dataType.toLowerCase().indexOf("money") != -1 || dataType.toLowerCase().indexOf("integer") != -1) {
var filter = settingName + " " + settingOperator + " " + settingValue;
} else {
if(settingValue.indexOf("'") != -1) {
var filter = settingName + " " + settingOperator + ' "' + settingValue + '"';
} else if(settingValue.indexOf("'") != -1) {
var filter = settingName + " " + settingOperator + " '" + settingValue + "'";
} else {
var filter = settingName + " " + settingOperator + " '" + settingValue + "'";
}
}
debug("filter: " + filter)
filters.push(filter);
}
}
}
// Process the report sheet and fill in the data
var reportSheet = SpreadsheetApp.openByUrl(currentSetting.ss).getSheetByName(REPORT_SHEET_NAME);
var rows = reportSheet.getDataRange();
var numRows = rows.getNumRows();
var numCols = rows.getNumColumns();
var values = rows.getValues();
var numSettingsRows = numRows - 1;
// Read Header Row and match names to settings
var headerNames = new Array();
var row = values[0];
for(var i = 0; i < numCols; i++) {
var value = row[i];
headerNames.push(value);
//debug(value);
}
if(reportType.toLowerCase().indexOf("performance") != -1) {
var dateString = ' DURING ' + dateRange;
} else {
var dateString = "";
}
if(filters.length) {
var query = 'SELECT ' + headerNames.join(",") + ' FROM ' + reportType + ' WHERE ' + filters.join(" AND ") + dateString + " " + sortString;
} else {
var query = 'SELECT ' + headerNames.join(",") + ' FROM ' + reportType + dateString + " " + sortString;
}
debug(query);
var report = AdWordsApp.report(query); //THIS IS LINE 103 WITH THE ERROR
try {
report.exportToSheet(reportSheet);
var subject = "Your " + reportType + " for " + dateRange + " for " + AdWordsApp.currentAccount().getName() + " is ready";
var body = "currentSetting.ss<br>You can now add this data to <a href='https://www.optmyzr.com'>Optmyzr</a> or another reporting system.";
MailApp.sendEmail(EMAIL_ADDRESSES, subject, body);
Logger.log("Your report is ready at " + currentSetting.ss);
Logger.log("You can include this in your scheduled Optmyzr reports or another reporting tool.");
} catch (e) {
debug("error: " + e);
}
}
function debug(text) {
if(DEBUG) Logger.log(text);
}
The area between SELECT and FROM is the selector. You're not selecting any fields with that query. That's happening because the headerNames array is empty. Verify the value of REPORT_SHEET_NAME

Automated duplicate check & bcc using Google Script

I wrote this JS to send email automatically using Google Script into a spreadsheet.
Unfortunately, the duplicate check is not working, and the bcc line trigger an error.
Actually I want to send an email only for the LAST answer into the spreadsheet everytime.
Could you help me?
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = active;
var dataRange = sheet.getRange(startRow, 1, numRows, 14)
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[2];
var surname = row[3];
var salesRepEmail = row[4];
var qualityAnalystEmail = "john#doe.com"
var customerEmail = row[5];
var websiteURL = row[6];
var solution1 = row[7];
var solution2 = row[8];
var solution3 = row[9];
var toResolve1 = row[10];
var toResolve2 = row[11];
var toResolve3 = row[12];
var checkDate = row[13];
var message = 'Bonjour '+ name + ' ' + surname + ', ' + 'blablabla';
var emailSent = row[14]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Votre Optimisation De Site Mobile pour " +websiteURL;
MailApp.sendEmail(customerEmail, subject, message, {
cc: "",
bcc: qualityAnalystEmail,+ " " + salesRepEmail,
});
sheet.getRange(startRow + i, 15).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Your code is triggering on bcc line cause you put a extra comma. As seen on the documentation, the bcc parameters should be a string with
a comma-separated list of email addresses to BCC
In your cas, you should'nt have:
bcc: qualityAnalystEmail,+ " " + salesRepEmail
but:
bcc: qualityAnalystEmail + ", " + salesRepEmail
which gives:
MailApp.sendEmail(customerEmail, subject, message, {
cc: "",
bcc: qualityAnalystEmail+ ", " + salesRepEmail
});
(You also put a extra comma after your bcc parameters which is not good)
Thank you so much , Please find below the datas and the script.
I will try to call the variables into the HTML afterwards using Google Scriptlet. For the moment, the simple text is sufficient. It seems to be working like that, but the code is not clean.
Image Du Tableau
// This constant is written in column O for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function testSchemas() { {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = sheet.getLastRow();
var numRows = 1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 15)
// 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 name = row[2];
var surname = row[3];
var salesRepEmail = row[4];
var qualityAnalystEmail = "xxx#yyy.com"
var customerEmail = row[5];
var websiteURL = row[6];
var solution1 = row[7];
var solution2 = row[8];
var solution3 = row[9];
var toResolve1 = row[10];
var toResolve2 = row[11];
var toResolve3 = row[12];
var checkDate = row[13];
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Logger.log(doGet);
var htmlBody = HtmlService.createHtmlOutputFromFile('Index').getContent();
var message = 'Bonjour '+ name + ' ' + surname + ', ' + 'c\'est avec grand plaisir que je vous écris pour résumer ... - '+solution1+' \n\n- '+solution2+' \n\n- '+solution3+' \n\nMalgré...';
var emailSent = row[14]; // Third column
if (emailSent != "EMAIL_SENT") { // Prevents sending duplicates
/*MailApp.sendEmail(customerEmail, subject, message, {
cc: "",
bcc: qualityAnalystEmail + ", " + salesRepEmail
}); */
MailApp.sendEmail({
to: customerEmail,
bcc: qualityAnalystEmail + ", " + salesRepEmail,
subject: 'Résumé De Notre Consultation Du Site Mobile ' + websiteURL,
htmlBody: htmlBody,
});
}
Logger.log(name);
sheet.getRange(startRow + i, 15).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}

SpreadsheetApp.openById not going through in Google Spreadsheet

I am trying to run the function "onReportOrApprovalSubmit()" when I click on the message box that pops up when I open my google spreadsheet. The function runs perfectly fine when I run it in the script editor. However, when I try to run it using the message box that pops up when I first open the spreadsheet, the function stops running/gets stuck just before the line:
"var approvalsSpreadsheet = SpreadsheetApp.openById(APPROVALS_SPREADSHEET_ID);"
Does anyone have any idea why this is happening?
var APPROVALS_SPREADSHEET_ID = "1NC6mBPRXKCA4Blbn7C9lFt9YnTZioS3_vidbVuPvZos";
var APPROVAL_FORM_URL = "https://docs.google.com/a/londonhydro.com/forms/d/1BKuKdNwsUDXyLdqy18GAcQmE_SzS7Sq_OTxVNwyCH44/viewform";
var STATE_MANAGER_EMAIL = "MANAGER_EMAIL";
var STATE_APPROVED = "APPROVED";
var STATE_DENIED = "DENIED";
var COLUMN_STATE = 6;
var COLUMN_COMMENT = 7;
function onReportOrApprovalSubmit() {
// This is the Expense Report Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// Also open the Approvals Spreadsheet
var ui = SpreadsheetApp.getUi(); // DEBUG
ui.alert("heelo"); // DEBUG
var approvalsSpreadsheet = SpreadsheetApp.openById(APPROVALS_SPREADSHEET_ID);
var ui = SpreadsheetApp.getUi(); // DEBUG
ui.alert('Requests sentsee'); // DEBUG
var approvalsSheet = approvalsSpreadsheet.getSheets()[0];
// Fetch all the data from the Expense Report Spreadsheet
// getRowsData was reused from Reading Spreadsheet Data using JavaScript Objects tutorial
var data = getRowsData(sheet);
// Fetch all the data from the Approvals Spreadsheet
var approvalsData = getApprovalData(approvalsSheet);
// For every expense report
for (var i = 0; i < data.length; i++) {
var row = data[i];
row.rowNumber = i + 2;
Logger.log("Row num: " + row.rowNumber);
Logger.log("row state before: " + row.state);
Logger.log("row email before: " + row.emailAddress);
if (!row.state) {
Logger.log("row state: " + row.state);
sendReportToManager(row);
sheet.getRange(row.rowNumber, COLUMN_STATE).setValue(row.state);
Logger.log("row state: " + row.state);
} else if (row.state == STATE_MANAGER_EMAIL) {
for (var j = 0; j < approvalsData.length; ++j) {
var approval = approvalsData[j];
if (row.rowNumber != approval.expenseReportId) {
Logger.log("failed expenseId: " + approval.expenseReportId + " rowNumber: " + row.rowNumber);
continue;
}
Logger.log("pass");
// Email the employee to notify the Manager's decision about the expense report.
sendApprovalResults(row, approval);
// Update the state of the report to APPROVED or DENIED
sheet.getRange(row.rowNumber, COLUMN_STATE).setValue(row.state);
break;
}
}
}
}
Row = function(){
};
function getRowsData(sheet){
var data = sheet.getDataRange().getValues();
var row = new Row();
var rows = [];
var counter = 0;
for (var i = 0; i < data.length; i++) {
row = new Row();
row.time = data[i][0];
row.emailAddress = data[i][1];
row.amount = data[i][2];
row.description = data[i][3];
row.managersEmailAddress = data[i][4];
row.state = data[i][5];
if(i != 0){
Logger.log("row state1: " + row.state);
rows[counter] = row;
counter++;
}
}
Logger.log("rowsss:");
Logger.log(rows);
Logger.log("data length: " + rows.length);
Logger.log("data display: ");
for(var k = 0; k < rows.length; k++){
Logger.log(rows[k].state);
}
return rows;
}
ApprovalData = function(){
};
function getApprovalData(sheet){
var data = sheet.getDataRange().getValues();
var row = new ApprovalData();
var rows = [];
for (var i = 0; i < data.length; i++) {
row.time = data[i][0];
row.emailAddress = data[i][1];
row.expenseReportId = data[i][2];
row.approveExpenseReport = data[i][3];
row.comments = data[i][4];
rows[i] = row;
}
return rows;
}
// Sends an email to an employee to communicate the manager's decision on a given Expense Report.
function sendApprovalResults(row, approval) {
var approvedOrRejected = (approval.approveExpenseReport == "Yes") ? "approved" : "rejected";
var message = "<HTML><BODY>"
+ "<P>" + approval.emailAddress + " has " + approvedOrRejected + " your expense report."
+ "<P>Amount: $" + row.amount
+ "<P>Description: " + row.description
+ "<P>Report Id: " + row.rowNumber
+ "<P>Manager's comment: " + (approval.comments || "")
+ "</HTML></BODY>";
MailApp.sendEmail(row.emailAddress, "Expense Report Approval Results", "", {htmlBody: message});
if (approval.approveExpenseReport == "Yes") {
row.state = STATE_APPROVED;
} else {
row.state = STATE_DENIED;
}
}
// Sends an email to a manager to request his approval of an employee expense report.
function sendReportToManager(row) {
var message = "<HTML><BODY>"
+ "<P>" + row.emailAddress + " has requested your approval for an expense report."
+ "<P>" + "Amount: $" + row.amount
+ "<P>" + "Description: " + row.description
+ "<P>" + "Report Id: " + row.rowNumber
+ '<P>Please approve or reject the expense report here.'
+ "</HTML></BODY>";
MailApp.sendEmail(row.managersEmailAddress, "Expense Report Approval Request", "", {htmlBody: message});
row.state = STATE_MANAGER_EMAIL;
Logger.log("id: " + row.rowNumber);
}
function onOpen() {
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.alert(
'Do you want to get new requests?',
ui.ButtonSet.YES_NO);
// Process the user's response.
if (result == ui.Button.YES) {
// User clicked "Yes".
onReportOrApprovalSubmit();
ui.alert('Requests sent');
} else {
// User clicked "No" or X in the title bar.
ui.alert('No requests sent');
}
}
The function onOpen can only access the spreadsheet it is bound to, not others. The UI prompt doesn't change that: showing a custom dialog doesn't add any authorization to the function. One cannot access other spreadsheets from a process that is launched by a simple trigger, such as onOpen.
Solution: let onOpen add menu items that will be used to launch any functions requiring authorization.
function onOpen() {
var menu = [{name: "Get New Requests", functionName: "onReportOrApprovalSubmit"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu("Script", menu);
}

Categories

Resources