HtmlService.createHtmlOutputFromFile mail merge - cannot change placeholders - google-apps-script

I've built an HTML file inside the Google Script code editor.
Inside the HTML I've included placeholders, such as {{NAME}}.
My goal is to replace these placeholders with data from a Google Sheet.
Well...it's not working :)
The email is received with just HtmlOutput in the body.
Code below. What am I missing?
var emailBody = HtmlService.createHtmlOutputFromFile('client_intro_email');
emailBody = emailBody.replace({{NAME}}, clientname);
GmailApp.sendEmail(clientemail, 'subject', '',
{htmlBody: emailBody.getContent(),
}
Hi {{NAME}},
Here are the variables I'd like to push into the HTML. Content of the cells is text.
var clientname = spreadsheet.getRange('C2').getValue();
var clientemail = spreadsheet.getRange('P2').getValue();

Answer:
You can use templated HTML to dynamically insert HTML content from your script.
More Information:
From the documentation on scriptlets:
Apps Script templates can contain three special tags, called scriptlets. Inside a scriptlet, you can write any code that would work in a normal Apps Script file: scriptlets can call functions defined in other code files, reference global variables, or use any of the Apps Script APIs. You can even define functions and variables within scriptlets, with the caveat that they can't be called by functions defined in code files or other templates.
So, you can create an HTML Template file (from the File > New > HTML file menu item in the Apps Script UI) and set it up ready to receive data from whatever your Apps script function processes.
Setting up your HTML:
As a simple example, you can create an HTML file called emailTemplate.html which contains the following data:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hi <?!= name ?>, your email address is <?!= email ?>.
</body>
</html>
Then in your Code.gs file, you can load the data you want directly into your HTML template before evaluating it:
var htmlTemplate = HtmlService.createTemplateFromFile('emailTemplate.html');
var clientname = spreadsheet.getRange('C2').getValue();
var clientemail = spreadsheet.getRange('P2').getValue();
htmlTemplate.email = clientemail;
htmlTemplate.name = clientname;
var emailBody = htmlTemplate.evaluate();
GmailApp.sendEmail(clientemail, 'subject', '',
{
htmlBody: emailBody.getContent(),
});
This mitigates any need to do replacing with emailBody.replace({{NAME}}, clientname); as the template is directly loaded with the variables that have been set in Apps Script.
For a person called John Doe with an email address of john.doe#example.com, the above example will send an email which will appear as:
Hi John Doe, your email address is john.doe#example.com.
References:
HTML Service: Templated HTML | Apps Script | Google Developers

Related

Apps Script - Use a Code.gs variable in HTML script

Here, the task is to use a variable from Code.gs to be used in the HTML side.
The best idea I've had is using google.script.run to get access to Code.gs where I have stored a variable that I wish to use in the HTML script. Eg: Suppose there is a variable in the Code.gs side that turned out to be 1+1. Then I would very much have liked the following to work:
Code.gs
function getMyGSValue() {
return 1+1
}
HTML
<script>
google.script.run.withSuccessHandler(myGsValue => {
myScriptVar = myGsValue
}).getMyGsValue()
// Here use MyScriptVar endlessly.
</script>
Which unfortunately fails to work. If it's of any help, I'm more interested in using string variables from the Code.gs side as these will be more likely the link to the images I want to display if particular conditions are met.
A related question follows:
Passing variable from Code.gs to html in Google App Script
But to be honest, It seemed to have its focus elsewhere.
Doing it with google.script.run. I just used window.onload event to get the data from the server
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<input type="text" id="txt1" />
<script>
window.onload = () =>{
//console.log("window.onload")
google.script.run.withSuccessHandler((v) => {
document.getElementById("txt1").value = v;
}).getMyGsValue()
//console.log("Code");
}
</script>
</body>
</html>
gs:
function getMyGsValue() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
return sh.getRange("A1").getValue();
}
function launchmydialog() {
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile("ah2"),"Title");
}
If you need that the "variable" from the server side be ready when the web browser start parsing the web application, instead of using client-side code to retrieve the "variable", generate the client-side code with the "variable" that you need by generating first a HtmlTemplate, then assigns the variable to a HtmlTemplate property and finally evaluates it.
Below is an over simplistic example:
function doGet(e){
const myServerVariable = 1 + 1;
const template = `<body><script>const myClientVariable = <?!= tmpProp?> </script></body>`;
return (
HtmlService.createTemplate(template)
.tmpProp = myServerVariable
).evaluate();
}
The above example is so simple that you could do the same by using regular JavaScript string manipulation. Anyway, <?!= tmpProp?> is a force-printing scriptlet, also there are standard scriptlets and printing scriptlets that might be more frequently used on .html files in Google Apps Script.
Be careful when using scriptlets to built the client-side code to not make them to take too much time to generate the client-side code as this will impact how fast the web app responds to the initial request.
By the other hand, if you want to keep using google.script.run, just declare a global variable, and update it in the withSuccessHandler callback
<script>
var MyScriptVar;
google.script.run.withSuccessHandler(myGsValue => {
MyScriptVar = myGsValue
}).getMyGsValue()
// Here use MyScriptVar endlessly.
</script>
Just consider the case that MyScriptVar will be undefined while the google.script.run finish it's execution.
Related
How to pass a parameter to html?
Passing variable from google script to html dialog
References
https://developers.google.com/apps-script/guides/html/templates

How to have Google Forms send automated email with new responses

I have a Google Form which I would like to automatically email someone when a new response is submitted. So far, I have just a simple HTML page with text in the body, however I would like the email content to include the form data as well.
Currently, this is what I have written:
function sendEmail(e) {
//response
var html = HtmlService.createTemplateFromFile("email.html");
var htmlText = html.evaluate().getContent();
var emailTo = "jeffreyabr#gmail.com"
var subject = "New SAP Role Request"
var textBody = "This email requires HTML support. Please make sure you open it with an email client that supports HTML"
var options = {htmlBody: htmlText};
GmailApp.sendEmail(emailTo, subject, textBody, options);
This came from following this basic YouTube tutorial.
Is there more Google Apps Script that I can add to accomplish this? Can I do this from Forms or must I do it from within Sheets?
The e.response object also contains the form data, which can be accessed by using e.response.getItemResponses().
Then to get the question, use getItem().getTitle(). To get the answer, use getResponse().
If you do not need the HTML response, then you can append the questions and answers to the textBody to display them on the email. Otherwise, you would have to add a script in your email.html using HTML scripts or google.script.run.
References:
Event Objects | onFormSubmit(e)
Class FormResponse

Google Script - Convert HTML-Template to string

So, I've been looking through StackOverlow for a while now, and the closest answer I found is this.
I have built a template for sending emails and I'd like to reuse it for other purposes, such as the description of an event. I'm struggling to get a printout of the HTML template in a readable format, exactly as you get it in the email.
Here's the HTML template:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<p>Hi <?!= OOOCLIENTFIRSTNAME?>,</p>
</body>
</html>
Here's the template code:
var emailtemplate = HtmlService.createTemplateFromFile('XXXXX');
emailtemplate.OOOCLIENTFIRSTNAME = clientfirstname;
var emailbody = emailtemplate.evaluate();
So, when I place it into the sendEmail method parameter's htmlbody property, it works perfectly and email is sent as planned. Here's the GmailApp code:
GmailApp.sendEmail(clientemail, 'TEST TITLE', '',
{htmlBody: emailBody.getContent()};
I want to get the result as a simple string, such as "Hi firstname".
I have tried to use .getContent but this results in getting the HTML source code, and not its output. Any ideas?
I suggest you a different approach:
Just build your greeting in the Apps Script part before passing it to HTML.
Code:gs
function myFunction() {
var emailtemplate = HtmlService.createTemplateFromFile('index');
var greeting = "Hi " + clientfirstname + ",";
emailtemplate.OOOCLIENTFIRSTNAME = greeting;
var emailBody = emailtemplate.evaluate();
GmailApp.sendEmail(clienemail, 'TEST TITLE', '',{htmlBody: emailBody.getContent()});
var reusedGreeting = greeting + " how are you?";
Logger.log(reusedGreeting);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<p> Hi <?!= OOOCLIENTFIRSTNAME?>,</p>
</body>
</html>
Why?
When you evaluate a template within a normal function, (opposed to building a WebApp with a doGet() function that would allow you to pass a variable to serverside with google.script.run) there is no easy way to retrieve the inner HTML.
You'd need to either
extract the string with Regex
or parse the html as explained e.g. here
Both solutions would be an overkill for what you are trying to do.

How to monitor page activity of a google site using Google Apps Script

Problem
I want to be able to monitor user activity on my google site using Apps Script, specifically which pages users are accessing. I can not use Google Analytics (it is not within my contract with Google). Apps Script has so far been able to return user ID (email address) of the user when a page is accessed, however I can not work out how to return which page(s) are activated by that user.
What I have done so far
I have created a web app and deployed / embedded it within to 2 pages in a test google site. It returns the values to a table in a linked google sheets file. Here is the script:
function doGet(event) {
return HtmlService.createHtmlOutputFromFile('UserLog.html');
}
function getPage(pageTitle) {
var user = Session.getActiveUser();
var ss = SpreadsheetApp.getActive();
var db = "Webapp Log";
var db_ss = ss.getSheetByName(db);
var now = new Date();
var page = pageTitle;
var values = [now,user,page,"User activated webapp",Session.getTemporaryActiveUserKey()];
db_ss.getRange(db_ss.getLastRow()+1, 1, 1, 5).setValues([values]);
};
The "UserLog.html" code is this:
<html>
<head>
<base target="_top">
</head>
<body>
<script>
var page = [Solution]
google.script.run.getPage(page);
</script>
</body>
</html>
And so far the return values look like this (with addresses anonymised):
Table Values
As you can see, the 'Page' field is blank.
What I need
Use the embedded web app to return the activated page URL OR to return another unique aspect of the activated page, for example the page title or "page 1", "page 2", etc. (all pages on the site have a unique title).
How can this be done? Is this even possible?
You can do it with e.parameters
E.g. incorporate a parameter page that you append at the end of the WebApp URL.
When you embedd the WebApp URL in each page, assign a unique value to page, like https://script.google.com/a/XXX/macros/s/XXX/exec?page=1, https://script.google.com/a/XXX/macros/s/XXX/exec?page=2
Now, in Apps Script you just have to slightly modify your doGet() function to retrieve the page:
function doGet(event) {
var page = event.parameter.page;
return HtmlService.createHtmlOutputFromFile('UserLog.html');
}
The rest depends on your preferences. The easiest would be to directly paste the value of page into the spreadsheet from the doGet() function - this will avoid passing the parameter to the html file and then, with google.script.run back to a .gs function.

Customize invitation email in Google Forms

I want to custom the invitation email when I share a google form. I have looking up in Google Script documentation and I haven't found some method or class useful. How can I customize this invitation email?.
Normally this email looks like:
I want to add a corporative image in the footer and maybe some text.
There isn't a method to create your own customized message. Below I am going to propose an alternate solution.
You can create a function that sends a customized mail. Just create an HTML file with your customized HTML content.
// i called this share.html in the apps script project
<h1>This is a header 1</h1>
<p>This is a paragraph</p>
<img src="<<SOME IMAGE SRC HERE>>" />
Then back in your code.gs file create a function like below:
function shareForm() {
var html = HtmlService.createHtmlOutputFromFile('share').getContent();
var recipient = '<<EMAIL ADDRESS>>';
var subject = 'this is the subject';
var body = 'this will get overridden by the HTML service';
var options = {
htmlBody: html
};
MailApp.sendEmail(recipient, subject, body, options)
}
You can run this function from the script editor, or you can build a button to add into the add-ons drop down options.