Sending HTML email from spreadsheets - javascript

I'm making some improvements to a tutorial. The code sends an email from a Google spreadsheet and take the subject there and marks when the email has been sent, I'm trying to make the message in html.
var EMAIL_SENT = 'Correo Enviado';
//non-duplicate emails with data from the current spreadsheet.
function sendEmails2() {
var templ = HtmlService.createTemplateFromFile('Correo_HTML').evaluate();
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = SpreadsheetApp.getActiveSheet().getRange(2,7).getValue(); // Number of rows
var dataRange = sheet.getRange(startRow, 1, numRows, 3);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0];
var message = templ.getContent();
var emailSent = row[3];
if (emailSent !== EMAIL_SENT) { // Prevents sending duplicates
var subject = row[2];
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 4).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
and I'm writing the HTML code in another window, is super simple but I don't know where could be the trouble
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2> Test 2</h2>
<p>
Hello World
</p>
<p><strong> learning </strong></p>
</body>
</html>
So how can I get the message in the email with the format in the HTML code?

Related

I'm writing a script so that on entering a specific customer code in column A in Sheet 2 it will match and copy the matching row from Sheet 1

I have a customer details in Sheet 1 with a customer account code for each customer under column A and the corresponding customer name under column B and address under column C.
In sheet 2 I want to start with row 1 column A where I will enter a customer account code which when matches with the customer account code under column A in Sheet 1 will copy the data in the corresponding rows over to sheet 2.
Then again when I enter the row 2 in sheet 2 this will match and copy that corresponding data from sheet 1.
The code I have will work when I enter in Sheet 2 row 1 column A, but I cannot get it to code to work when I proceed to enter data in further rows under column A. Any assistance will be greatly appreciated. Thanks
var ss = SpreadsheetApp.getActiveSpreadsheet();
var docketsSheet = ss.getSheetByName('Dockets');
var customersSheet = ss.getSheetByName("Customers");
docketsSheet.getRange("A20:I1000").clear();
var i = 1; i <= lastRow; i++;
var getLastRow = docketsSheet.getLastRow();
var code = docketsSheet.getRange(1,1).getValue();
var lastRow = customersSheet.getLastRow() + 1;
var foundRecord = false;
for(var j = 2; j < lastRow; j++)
{
if(customersSheet.getRange(j,1).getValue() == code)
{
var nextRow = docketsSheet.getLastRow() +1;
var getCopyRange = customersSheet.getRange('A' + j +':F' + j);
getCopyRange.copyTo(docketsSheet.getRange(nextRow, 2));
foundRecord = true;
}
}
if(foundRecord == false)
{
docketsSheet.getRange(5,1).setValue(['no record found']);
}
}```
I'm very new to coding and will be very grateful of any assistance.
Thanks
I have modified your code to update the customer list and write "no foundwhen the code is not listed, the only difference is thatclearValue()` can be skipped:
function updateData(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var docketsSheet = ss.getSheetByName('Dockets');
var customersSheet = ss.getSheetByName("Customers");
var lastCust = customersSheet.getLastRow();
var cusList = customersSheet.getRange(2,1,lastCust,3).getValues();
var newCUst = docketsSheet.getLastRow();
docketsSheet.getRange(newCUst,2).setValue("Not found");
var code = docketsSheet.getRange(newCUst,1).getValue();
for (j = 0;j <cusList.length;j++){
if (cusList[j][0] == code){
var name = cusList[j][1];
var address = cusList[j][2];
docketsSheet.getRange(newCUst,2).setValue(name)
docketsSheet.getRange(newCUst,3).setValue(address)
}
}
}

The Java Script Results not showing in HTML

I wrote a GAS code to check if the employee is In or Not in (extracting data from Google sheets).
The console log give me the right answer but When I click on the button the answer doesn't appear at the front end. Can you help me to troubleshoot on where I went wrong?
<div>
<script>
function onStatus(notify) {
var employee = "John Peter";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = ss.getSheetByName("MAIN");
var data = mainSheet.getDataRange().getValues();
for (var j = 0; j < data.length; j++){
var row = data[j];
var mainSheet2 = row[4];
var mainSheet3 = row[0];
var status = (mainSheet2 =="IN" && mainSheet3 == employee) ;
if (status == true){
var notify = employee +" You Are In"
return notify;
}
}
document.getElementById('status').innerHTML= notify;
}
</script>
<button onclick="onStatus()">Check Status</button>
<font color='Green' id="status" ></font>
</div>
Google provides a very good Client-to-Server Communication guide that I highly suggest you read to get a better understanding of how this works.
You cannot put apps script code (e.g. SpreadsheetApp.getActiveSpreadsheet()) in your frontend scripts. That code has to be run by the apps script server in the backend and you'll then call it using a google.script.run call.
Code.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Index');
}
function checkStatus() {
var employee = "John Peter";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = ss.getSheetByName("MAIN");
var data = mainSheet.getDataRange().getValues();
for (var j = 0; j < data.length; j++){
var row = data[j];
var mainSheet2 = row[4];
var mainSheet3 = row[0];
var status = (mainSheet2 =="IN" && mainSheet3 == employee) ;
if (status == true){
return employee + " You Are In";
}
}
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div>
<button onclick="onStatus()">Check Status</button>
<font color='Green' id="status" ></font>
</div>
<script>
function onStatus() {
google.script.run
.withSuccessHandler(updateStatus) // Send the backend result to updateStatus()
.checkStatus(); // Call the backend function
}
function updateStatus(notify) {
document.getElementById('status').innerHTML= notify;
}
</script>
</body>
</html>

How to fix {"result":"error","error":{"name":"Exception"}} in google apps scripts

.gs
var sheetName = 'Sheet1'
var scriptProp = PropertiesService.getScriptProperties()
function doPost (e){
Logger.log(JSON.stringify(e))
if (!e || !e.parameter){
return;
}
var lock = LockService.getScriptLock();
lock.tryLock(10 * 1000);
try {
var ss = SpreadsheetApp.getActive();
var sheet1 = ss.getSheetByName(sheetName);
var headers = sheet1.getRange(1, 1, 1, sheet1.getLastColumn()).getValues()[0];
var nextRow = sheet1.getLastRow() + 1;
var newRow = headers.map(function(header) {
return header === 'Timestamp' ? new Date() : e.parameter[header]
});
sheet1.getRange(nextRow, 1, 1, newRow.length).setValues([newRow]);
var TEMPLATE_ID = '....ID....'
var PDF_FILE_NAME = newRow[3];
var RESULTS_FOLDER_ID = '....ID....'
var templateFile = DriveApp.getFileById(TEMPLATE_ID);
var copyFile = templateFile.makeCopy();
var copyId = copyFile.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
var headerValue;
var activeCell;
var activeRow = sheet1.getRange(nextRow, 1, 1, newRow.length).getValues();
for (var columnIndex = 0; columnIndex < headers.length; columnIndex++){
headerValue = headers[columnIndex]
activeCell = activeRow[0][columnIndex]
copyBody.replaceText('<<' + headerValue + '>>', activeCell);
copyDoc.saveAndClose();
var newFile = DriveApp.createFile(copyFile.getAs('application/pdf'));
copyFile.setTrashed(true);
newFile.setName(PDF_FILE_NAME);
if (RESULTS_FOLDER_ID !== ''){
DriveApp.getFolderById(RESULTS_FOLDER_ID).addFile(newFile)
DriveApp.removeFile(newFile)
}
}
return ..
}
catch (e){
return ContentService ..
}
finally{
lock.releaseLock()
}
}
The purpose of the code is to:
Post data to google sheet
Create a new pdf file every time a new row is submitted using the new row data
I receive the data in the sheet successfully and also the new pdf is created in the drive but with the following errors:
I am supposed to have 4 updated fields but only the first one is updated in the pdf
In the template doc I have: Name1, Name2, Name3, Name4 to be updated as in the sheet header
So when a new row is submitted to the sheet for example with Tom, Mike, John, Andy - I get that in the pdf Tom, Name2, Name3, Name4 (only the first value is updated)
Redirected to {"result":"error","error":{"name":"Exception"}} after submit
.html
<!DOCTYPE html>
<html lang="en">
<body>
<head>
<base target="_top">
</head>
<form action="....URL...." target="_blank" method="POST">
<div>
Name1
<input type="text" required name="Name1">
</div>
<div>
Name2
<input type="text" required name="Name2">
</div>
<div>
Name3
<input type="text" required name="Name3">
</div>
<div>
Name4
<input type="text" required name="Name4">
</div>
<button type="submit">Post</button>
</form>
</body>
</html>
Any help is appreciated. Thanks in advance
How about this modification? Please think of this as just one of several possible answers.
Modification points:
In your script, createFile and setTrashed are run in the for loop of for (var columnIndex = 0; columnIndex < headers.length; columnIndex++){}. In this case, at the 1st loop, a PDF file is created, and copyFile is moved to the trash box. I think that the reason of your issue might be this.
In order to avoid above situation, how about the following modification?
Modified script:
When your script is modified, please modify as follows.
From:
for (var columnIndex = 0; columnIndex < headers.length; columnIndex++){
headerValue = headers[columnIndex]
activeCell = activeRow[0][columnIndex]
copyBody.replaceText('<<' + headerValue + '>>', activeCell);
copyDoc.saveAndClose();
var newFile = DriveApp.createFile(copyFile.getAs('application/pdf'));
copyFile.setTrashed(true);
newFile.setName(PDF_FILE_NAME);
if (RESULTS_FOLDER_ID !== ''){
DriveApp.getFolderById(RESULTS_FOLDER_ID).addFile(newFile)
DriveApp.removeFile(newFile)
}
}
To:
for (var columnIndex = 0; columnIndex < headers.length; columnIndex++){
headerValue = headers[columnIndex]
activeCell = activeRow[0][columnIndex]
copyBody.replaceText('<<' + headerValue + '>>', activeCell);
}
copyDoc.saveAndClose();
var newFile = DriveApp.createFile(copyFile.getAs('application/pdf'));
copyFile.setTrashed(true);
newFile.setName(PDF_FILE_NAME);
if (RESULTS_FOLDER_ID !== ''){
DriveApp.getFolderById(RESULTS_FOLDER_ID).addFile(newFile);
DriveApp.removeFile(newFile);
}
Note:
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Pleases be careful this.
If I misunderstood your question and this was not the result you want, I apologize. At that time, in order to correctly understand about your situation, can you provide a sample Spreadsheet including your script? By this, I would like to confirm it. Of course, please remove your personal information.

How to detect row and relatively go to the cell in next column?

I wrote a code to send mails automatically from google sheet. Every day if column Status has the cell "Timing" I want to send email. And it works. But I don't want to send mails to the people that received mail in previous days, so that I created CHECK to fill the another column by 'sent' after sending an email. It failed. I can't detect the row with an emailaddress that program used to go relatively to another column to insert "sent".
Could you help me?
function sendEmails() {
var she = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("basic");
var startRow = 2;
var numRows = 1000;
var dataRange = she.getRange(startRow, 1, numRows, 1000)
var data = dataRange.getValues();
var text = she.getRange("L2");
var message = text.getValues();
for (i in data) {
var col = data[i];
var emailAddress = col[1];
var subject = "Project reminder";
var status = col[3];
var check = col[8];
if (status == "Timing"){
MailApp.sendEmail(emailAddress, subject, message) &&
check.setValue('sent');} //moment when I want to insert 'sent'
}
}
Updated part of the code:
for(var a=0; a < values.length; a++ ){
if(values[a][1] == "not" && values[a][3] == "Timing"){
var emailAddress = values[a][0];
Logger.log("NEED TO SEND AN EMAIL TO " + values[a][0]);
var message = messag + " " + values[a][5];
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
Here's a mini solution for your use case. Just play with it to understand how it works. The (0,0), (0,1),etc represent the index number of the array.
Here's the sample table
function checkIfSent(){
var ss = SpreadsheetApp.openById("123454567890abcdefghi").getSheetByName("12345");
var values = ss.getSheetValues(1, 1, 6, 2);
for(var i=0; i < values.length; i++ ){
for(var j=0; j < values.length; j++ ){
if(values[i][j] == "NOT"){
Logger.log("NEED TO SEND AN EMAIL TO " + values[i][0]);
//Send an Email method here()
//. . .
}
}
}
}
If the values under column CHECK are labeled as NOT, you can place your method to send an email to that person (values[i][0]).

Getting blank screen after running Google web app script

I am working on a check-in app though Google Sheets and want to make a search function that that takes a sport name as input in an HTML form and then returns information about the sport from the sheet in a HTML table. However, when I try to test the web app, nothing happens. How can I fix this?
Here is my code:
Index.html
<!DOCTYPE html>
<html>
<head>
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
</head>
<body>
<fieldset id="tasks-panel">
<legend>Sports</legend>
<form name="sport-form" id="sport-form">
<label for="sport-name">Search a sport by name:</label>
<input type="text" name="sport-name" id="sport-name" />
<button onclick='addTable()' id='submit-button'>Press this</button>
</form>
<p>List of things:</p>
<div id="toggle" style="display:none"></div>
</fieldset>
<?!= HtmlService.createHtmlOutputFromFile('Javascript').getContent(); ?>
</body>
</html>
Javascript.html
<script>
function addTable() {
var sportInput = $('sport-name').value();
var columnNames = ["Names", "Times"];
var dataArray = google.script.run.getSportData(sportInput);
var myTable = document.createElement('table');
$('#divResults').append(myTable);
var y = document.createElement('tr');
myTable.appendChild(y);
for(var i = 0; i < columnNames.length; i++) {
var th = document.createElement('th'),
columns = document.createTextNode(columnNames[i]);
th.appendChild(columns);
y.appendChild(th);
}
for(var i = 0 ; i < dataArray.length ; i++) {
var row= dataArray[i];
var y2 = document.createElement('tr');
for(var j = 0 ; j < row.length ; j++) {
myTable.appendChild(y2);
var th2 = document.createElement('td');
var date2 = document.createTextNode(row[j]);
th2.appendChild(date2);
y2.appendChild(th2);
}
}
}
</script>
Code.gs
//Setting up global variables
var ss = SpreadsheetApp.openById("-spreadsheetID-");
var sheet = ss.getSheetByName("Sheet1");
var sportsFromSheet = sheet.getRange("D4:D12");
var namesFromSheet = sheet.getRange("B4:B12").getValues();
var timesFromSheet = sheet.getRange("A4:A12").getValues();
var NAMES = [];
var TIMES = [];
var OUTPUT = [];
//doGet function
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate()
.setTitle('Check In Data')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
//Gets both names and times of checked-in people
function getSportData(input) {
var sportInput = input;
getNamesInSport(sportInput);
getTimesInSport(sportInput);
OUTPUT = [
[NAMES],
[TIMES]
];
Logger.log(OUTPUT);
return OUTPUT;
}
//Puts the names of every person from an inputted sport into an array.
function getNamesInSport(input) {
var data = sportsFromSheet.getValues();
for (var i = 0; i < data.length; i++) {
if(data[i] == input){
NAMES.push(namesFromSheet[i][0]);
}
}
}
//Puts the times of every person from an inputted sport into an array.
function getTimesInSport(input){
var data = sportsFromSheet.getValues();
for (var i = 0; i < data.length; i ++) {
if(data[i] == input){
TIMES.push(timesFromSheet[i][0]);
}
}
}
JQuery id selectors must be prefixed with # so to grab the value from the the 'sport-name' input you'll need to select it using
var sportInput = $('#sport-name').val();
Additionally, as Robin comments above, if you want to use the JQuery library you'll need to load it, the code you've shown indicates you might not have done this?
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
Although if this were the case you'd probably be seeing a '$ is not defined' error straight away.

Categories