Embed images in the body of an automated email - Apps Script Issue - javascript

I am trying to create an automated email with an embedded image. It works on Apps Scripts but when I send the email, I receive the code of my function. So far, I have created an HTML file with the base64 image code (it works), the file with the function and the main code, with the spreadsheets and everything. Does anyone know how to fix it?
Main code:
function inlineImages() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("EAD");
var range = sheet.getDataRange();
var values = range.getValues();
var rows = range.getNumRows();
for (var row = 1; row < rows; row++) {
var email = values[row][5];
var name = values[row][4];
MailApp.sendEmail(email, "This is a test", doGet);
}
}
Function HtmlService:
function doGet() {
return HtmlService.createHtmlOutputFromFile('imagem');
}
Here is the HTML code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<img src="data:image/png;base64, /codeHere" alt="Red dot"/>
</body>
</html>

Related

Return Sheets data based on URL Parameter in Google Apps Script / Web App

This is a piece of a larger project. Essentially, I'm going to have a link with a parameter ("formid" in this case) that I need to use to retrieve the correct row number from a Google sheets table. The code below works the way I want it to with the exception of the parameters not being used and the rows being retrieved are hard coded. I'd like to change this so the getBody row corresponds to formid number (ie.: if formid=4 then the 4th row would be displayed. Column positions can be hardcoded, I only need the one variable to be used.
Index.html:
<!DOCTYPE html>
<html>
<head>
</head>
<style>
</style>
<body>
<form>
<h1><center>Sheet</center></h1>
</form>
<script>
google.script.url.getLocation(function(location) {
document.getElementById("formid").value = location.parameters.formid[0];
});
</script>
<div>
<table>
<thead>
<? const headers = getHeaders();
for (let i = 0; i < headers.length; i++) { ?>
<tr>
<? for (let j = 0; j < headers[0].length; j++) { ?>
<th><?= headers[i][j] ?></th>
<? } ?>
<? } ?>
</thead>
<tbody>
<? const body = getBody();
for (let k = 0; k < body.length; k++) { ?>
<tr>
<? for (let l = 0; l < body[0].length; l++) { ?>
<td><?= body[k][l] ?></td>
<? } ?>
<? } ?>
</tbody>
</table>
</div>
</body>
</html>
Code.gs:
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
function getHeaders() {
var url = "https://docs.google.com/spreadsheets/d/1NnG5lEKowlU6i2ZzkyCD1bjFtFGcgaODKZxvG179XfM/";
const sheet = SpreadsheetApp.openByUrl(url).getSheetByName("Sheet1");
return sheet.getRange(1, 1, 1, sheet.getLastColumn()).getDisplayValues();
}
function getBody() {
var url = "https://docs.google.com/spreadsheets/d/1NnG5lEKowlU6i2ZzkyCD1bjFtFGcgaODKZxvG179XfM/";
const sheet = SpreadsheetApp.openByUrl(url).getSheetByName("Sheet1");
const firstRow = 8;
const numRows = 1;
return sheet.getRange(firstRow, 1, numRows, sheet.getLastColumn()).getDisplayValues();
}
I've reviewed many related questions but either the solutions didn't seem to work or it wasn't clear what the full solution was. Perhaps I missed something.
I've tried inserting "formid" into the "return sheet.getRange()" but I keep getting an error that formid isn't an int.
I've made several attempts at this and the code above represents the closest and simplest script that has gotten me most of the way there.
I believe your goal is as follows.
You want to show only a row from the Spreadsheet by giving the row number using the query parameter like formid=5.
Modification points:
In your script, it seems that you are retrieving the query parameter on the HTML side. In this case, when the template is used, after the HTML is loaded, google.script.url.getLocation is run. So, in this answer, I would like to propose retrieving the query parameter on the Google Apps Script side.
In the current stage, when the loop process is included in the HTML template, the process cost becomes high. Ref (Author: me)
When these points are reflected in your script, how about the following modification?
HTML side:
In your HTML, document.getElementById("formid") is not found. So, in this modification, only HTML template without the script is used.
<!DOCTYPE html>
<html>
<head>
</head>
<style>
</style>
<body>
<form>
<h1>
<center>Sheet</center>
</h1>
</form>
<div>
<table>
<?!= table ?>
</table>
</div>
</body>
</html>
Google Apps Script side:
In this modification, only doGet function is used as follows.
function doGet(e) {
const url = "https://docs.google.com/spreadsheets/d/1NnG5lEKowlU6i2ZzkyCD1bjFtFGcgaODKZxvG179XfM/";
const { formid } = e.parameter;
const sheet = SpreadsheetApp.openByUrl(url).getSheetByName("Sheet1");
const [header, ...values] = sheet.getDataRange().getValues();
const h = "<thead><tr>" + header.map(e => `<th>${e}</th>`).join("") + "</tr></thead>";
const b = values[formid - 1] ? "<tbody><tr>" + values[formid - 1].map(e => `<td>${e}</td>`).join("") + "</tr></tbody>" : "";
const html = HtmlService.createTemplateFromFile('i16');
html.table = h + b;
return html.evaluate();
}
In this modification, for example, when a Web Apps URL like https://script.google.com/macros/s/###/dev?formid=5 including the query parameter is used, formid=5 is retrieved in the doGet function, and only the row of formid=5 is shown.
Note:
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".

Move sheet when drop-down menu is selected

I want to implement a function that moves to the selected sheet when selecting the drop-down menu (sheet name) in Google spreadsheet, but it's not working well.
The menu shows all the seat names, but if you select that particular seat, nothing will happen.
I keep searching and searching, but I don't see a clear solution. What should I do? Please help me.
The code I wrote is as follows.
code.gs
function onOpen() {
createMenu()
}
function createMenu(){
const ui = SpreadsheetApp.getUi()
const menu = ui.createMenu("Sidebar")
menu.addItem("Open Sidebar", "openSidebar");
menu.addToUi()
}
function openSidebar() {
ss = SpreadsheetApp.getActiveSpreadsheet();
var html = HtmlService.createTemplateFromFile('sidebar')
.evaluate()
.setTitle('Salesforce')
.setWidth(400);
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showSidebar(html);
}
sidebar.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id = "moveButton" class="button alert">Move</button>
<select name="Available sheets" onchange="moveSheet()" style="width:280px;height:30px;">
<? var sheets=ss.getSheets(); ?>
<? for(var i=0;i<sheets.length;i++) { ?>
<option value=<?=sheets[i].getName()?>> <?= sheets[i].getName()?></option>
<? } ?>
</select>
<script>
function myJsFunction(){
var name = document.getElementsByName("Available sheets")[0].value;
}
function moveSheet(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(name);
if(sheet !=null){
ss.moveActiveSheet(sheet);
}else{
//
}
}
document.getElementById("moveButton").addEventListener("click",moveSheet());
//google.script.run.withSuccessHandler(name);
};
</script>
</body>
</html>
I believe your goal is as follows.
You want to move the sheet by selecting the sheet name from the dropdown list at the sidebar of Spreadsheet.
When I saw your showing script, I thought that you are trying to run the Google Apps Script at the sidebar. At the sidebar and dialog of Spreadsheet, the Javascript is run with the client browser. On the other hand, Google Apps Script is run on the internal server side of Google. I thought that this might be the reason for your issue.
When your showing script is modified for achieving your goal, how about the following modification?
Google Apps Script side: code.gs
In this modification, your function of openSidebar is modified and a new function of moveSheet is added.
Here, in order to move the active sheet, activate() is used.
function moveSheet(e) {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(e).activate();
}
function openSidebar() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var options = ss.getSheets().map(s => {
var sheetName = s.getSheetName();
return `<option value="${sheetName}">${sheetName}</option>`;
}).join("");
var html = HtmlService.createTemplateFromFile('sidebar');
html.options = options;
var h = html.evaluate().setTitle('Salesforce').setWidth(400);
SpreadsheetApp.getUi().showSidebar(h);
}
HTML side: sidebar.html
I modified select tag and removed moveSheet().
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="moveButton" class="button alert">Move</button>
<select name="Available sheets" onchange="google.script.run.moveSheet(this.value)" style="width:280px;height:30px;">
<?!= options ?>
</select>
<script>
document.getElementById("moveButton").addEventListener("click",moveSheet());
//google.script.run.withSuccessHandler(name);
};
</script>
</body>
</html>
When you run openSidebar, a sidebar is opened. And, you can see the dropdown list including the sheet names. When you change the dropdown list, the active sheet is changed to the sheet of the selected sheet name.
References:
HTML Service: Templated HTML
activate()

Google apps script html to spreadsheet

I am learning google apps script at the moment by myself.
I have been trying to get someone's mail and append it to a google spreadsheets.
My code.gs looks actually like this:
function doGet() {
return HtmlService.createHtmlOutputFromFile("page");
};
function addEmail (mail) {
var mysheet = SpreadsheetApp.openById("1k3vWmg9859mYykNNl0xDWoR_LUhnvLlq1qW8kSRuL_Q").getSheetByName("Sheeet1");
mysheet.appendRow(mail);
};
And my html file looks like this:
<html>
<head>
<base target="_top">
</head>
<body>
<h1>hello</h1>
</body>
<label for="getUserMail">Type your mail here</label> <input type="text" id="getUserMail">
<button id="trigger">Submit!</button>
<script>
document.getElementById("trigger").addEventListener("click",sendMailToCode);
function sendMailToCode () {
var umail = document.getElementById("getUserMail");
google.script.run.addEmail(umail);
};
</script>
</html>
But it doesn't work. I have tried doing multiple stuff to fix it, even adding a tag on html but it does not save the value on the spreadsheet. Could someone please give an advice?
Try this:
This will append the html to the sheet but it will not render it.
function addEmail (mail='<html><head><basetarget="_top"></head><body><h1>hello</h1></body><labelfor="getUserMail">Typeyourmailhere</label><inputtype="text"id="getUserMail"><buttonid="trigger">Submit!</button><script>document.getElementById("trigger").addEventListener("click",sendMailToCode);functionsendMailToCode(){varumail=document.getElementById("getUserMail");google.script.run.addEmail(umail);};</script></html>') {
var ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
sh.appendRow([mail]);
}
appendRow
Reading the description of row contents: "An array of values to insert after the last row in the sheet."

Updating or inserting data from a Spreadsheet into a Dialog box inside a dropdown

Goal: The purpose is that a sheet will contain information, this information is placed inside a namedrange, the namedrange will be dynamic (the entire column is given a namedrange).
I created a html popup which contains a dropdown list. This dropdown list must contain the list of information from the namedrange.
I am unable to understand how this is to be done. Here is the code below:
function fncOpenMyDialog() {
var htmlDlg = HtmlService.createHtmlOutputFromFile('HTML_myHtml')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(200)
.setHeight(150);
SpreadsheetApp.getUi()
.showModalDialog(htmlDlg, 'New File');
};
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('New')
.addItem('New Save File Extension','fncOpenMyDialog')
.addToUi();
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select name="nameYouWant" placeholde="File Type">
<option value="something">Word</option>
<option value="anything">MS Excel</option>
<option value="anything">MS Powerpoint</option>
<option value="anything">MS Slides</option>
</select>
<hr/>
<p>Choose a file, which will then be saved into your Google Drive.</p>
<button onmouseup="closeDia()">Close</button>
<button onmouseup="onOpen()">Save</button>
<script>
window.closeDia = function() {
google.script.host.close();
};
window.saveDia = function() {
onOpen();
};
</script>
</body>
</html>
As you can see in my html file, that the extensions are currently hardcoded.
I am trying to make this dynamic, how do I achieve this?
I believe your goal as follows.
You want to put the values to the dropdown list by retrieving from the named range of the Spreadsheet.
In this case, is the named range the same with this thread?
For this, how about this answer?
Modification points:
From google.script.host.close(), I understood that the HTML file of HTML_myHtml is included in the Google Apps Script project. By this, I would like to propose to achieve your goal using google.script.run.
If the named range is the same with your previous question, you can use it by modifying a little.
When above points are reflected to your script, it becomes as follows.
Modified script:
HTML and JavaScript side: HTML_myHtml
Please modify HTML_myHtml as follows.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<select id="select" name="nameYouWant" placeholde="File Type"></select>
<hr />
<p>Choose a file, which will then be saved into your Google Drive.</p>
<button onmouseup="closeDia()">Close</button>
<button onmouseup="onOpen()">Save</button>
<script>
google.script.run.withSuccessHandler(v => {
const obj = document.getElementById("select");
v.forEach(e => {
const option = document.createElement("option");
option.text = e;
option.value = e;
obj.appendChild(option);
});
}).readNamedRange();
window.closeDia = function() {
google.script.host.close();
};
window.saveDia = function() {
onOpen();
};
</script>
</body>
</html>
Google Apps Script side: Code.gs
At above HTML, readNamedRange() is used. So please put the following script. If you have the same function names, please modify them. In this script, the values are retrieved from the named range of listDown, and sent to HTML side using google.script.run.
function readNamedRange() {
var activeSheet = SpreadsheetApp.getActiveSheet();
var result = activeSheet.getRange("listDown").getValues();
var end = activeSheet.getLastRow();
var values = [];
for (var i = 0; i < end; i++) {
if (result[i][0] != "") {
values.push(result[i][0]);
}
}
return values;
}
Note:
About window.saveDia = function() {onOpen()};, unfortunately, I couldn't understand about what you want to do.
Reference:
Class google.script.run

How to load an XML file in JavaScript, get specific info from it, and then display it through alert()?

So, I want to make a program that will be able to get user data(a ton of bug names separated by commas), go through, get data for each one, then display all of that data in a table. I have been through rewriting this like 5 times and still nothing happens. Anyone know what is wrong with this code?
My html code:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1 align="center">Bugs</h1>
<p>In the area below, type in each of the insects you want information
about, seperate them with a comma.</p>
<textarea id="insects"></textarea>
<br>
<button type="button" id="go">Find out!</button>
<br>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
document.getElementById('go').onclick = function() {
var input = document.getElementById('insects').value;
var splitted = input.split(',');
for (i = 0; i<splitted.length; i++) {
var bug1 = splitted[i];
var part1 = // I need to assign it to bug1 without any whitespace
var finish = part1.toLowerCase();
find1(bug1);
}
}
function find1(bug) {
var xmlDocument = $.parseXML("externalfile:drive-77136639a78ffb21e72c7c4dfe7f7bb73604aeb3/root/Bugs/bugs.xml");
var pain = $(xmlDocument).find("value[type='" + bug + "'] pain").text();
alert(pain); <!-- This is to see if it works -->
}
</script>
</body>
Here is my XML code(btw the XML file is called bugs.xml and yes they are in the same exact folder in My Drive/Bugs:
<?xml version="1.0" encoding="UTF-8"?>
<bugs>
<bug type="blisterbeetle">
<name>Blister Beetle</name>
<pain>55</pain>
<conservation></conservation>
<habitat></habitat>
<rarity></rarity>
<class></class>
<order></order>
<family></family>
<species></species>
<dangerous></dangerous>
<external></external>
</bug>
</bugs>

Categories

Resources