Reputation: 5716
I've been following the instructions here to have my Gmail signature template display the image stored on Google Drive as a logo.
The goal is to have the 'src' attribute of the image tag point to the image and display it inline. In the answer linked above, the image blob is fetched using UrlFetchApp. In my code, I'm calling the openById(id) method of the DriveApp to open the image file and get the blob.
However, neither approach seems to work. It's only when I have the 'src' point directly to the image URL that it loads the image. I tried using both base64Encode and base64EncodeWebSafe but the signature only shows the empty container for the image.
What am I missing here?
HTML template
<table>
<tbody>
<tr>
<td>
<img src="{{config.imgData}}" alt="my logo">
</td>
<td>
<table>
<tbody>
<tr><td> My name is {{config.name}} </td> </tr>
<tr><td> www.example.com </td> </tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
GS code
var config = {
name: "Anton",
imgData: ""
}
function updateSignature() {
var imgFileId = "DRIVE FILE ID";
var imgFile = DriveApp.getFileById(imgFileId);
var imgBlob = imgFile.getBlob().getAs("image/png"); //getAs doesn't change anything
//Get content type and bytes
var contentType = imgBlob.getContentType();
var imgBytes = imgBlob.getBytes();
var imgData = contentType + ";base64," + Utilities.base64Encode(imgData);
config.imgData = imgData;
var alias = Gmail.Users.Settings.SendAs.get("me", myEmail);
//Get signature html as a string
var templateString = HtmlService.createHtmlOutputFromFile("signature_template").getContent();
for (var configKey in config) {
if (config.hasOwnProperty(configKey)) {
templateString = templateString.replace("{{config." + configKey + "}}", config[configKey]);
}
}
var finalTemplate = HtmlService.createHtmlOutput(templateString).getContent();
alias.signature = finalTemplate;
Gmail.Users.Settings.SendAs.update(alias, "me", myEmail);
}
Upvotes: 0
Views: 1169
Reputation: 64110
Try this:
All you need to do is to add a default image file id to the function convertImageToDataURI and then launch the dialog. Or you can deploy as a webapp also. For my purposes I usually reduce the size of the images to something less than 1000 pixels wide and keep the aspect ratio less than one.
Code.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('Display Dialog', 'displayDialog')
.addItem('Get File Ids from FolderId','getFileIds')
.addToUi();
}
function convertImageToDataURI(fileId) {
var fileId=fileId||'default image file id';
if(fileId) {
var file=DriveApp.getFileById(fileId);
var blob=file.getBlob();
var dataUri='data:' + blob.getContentType() + ';base64,' + Utilities.base64Encode(blob.getBytes());
return dataUri;
}
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function displayDialog() {
var userInterface=HtmlService.createTemplateFromFile('image').evaluate();
SpreadsheetApp.getUi().showModelessDialog(userInterface, "For the Birds");
}
function doGet() {
return HtmlService.createTemplateFromFile('image').evaluate();
}
resources.html:(not required for this example)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
css.html:(not required for this example)
<style>
body {background-color:#ffffff;}
input{padding:2px;margin:2px;}
</style>
script.html:(not required for this example)
<script>
console.log('script.html code');
</script>
content.html is empty
images.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('resources') ?>
<?!= include('css') ?>
</head>
<body>
<img id="birds" src="<?!=convertImageToDataURI()?>" width="320" />
<?!= include('content') ?>
<?!= include('script') ?>
</body>
</html>
<html><head>
If you need a tool to get the file ids of images in a folder try this function:
function getFileIds() {
var resp=SpreadsheetApp.getUi().prompt("Folder Id","Enter Folder Id", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(resp.getSelectedButton()==SpreadsheetApp.getUi().Button.OK && resp.getResponseText().length>0) {
try{
var folder=DriveApp.getFolderById(resp.getResponseText());
var files=folder.getFiles();
var html='<style>td,th{border:1px solid black;padding:2px 5px;}</style><table><tr><th>File Name</th><th>File Id</th><th>Type</th></tr>';
while(files.hasNext()) {
var file=files.next();
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td><td>%s</td></tr>', file.getName(),file.getId(),file.getMimeType());
}
html+='</table><br /><input type="button" value="Close" onClick="google.script.host.close();" />';
var userInterface=HtmlService.createHtmlOutput(html).setWidth(800).setHeight(400);
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Files in Folder");
}
catch(e){SpreadsheetApp.getUi().alert(e);}
}else{
SpreadsheetApp.getUi().alert("Invalid or Missing Inputs: No FileId Provided");
}
}
This is what my dialog looks like:
Upvotes: 1
Reputation: 201643
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
When I checked the official document, I saw the image for the signature as follows.
- If you added a photo or image from Google Drive, you'll need to share your image publicly for it to appear in your signature. Note: If you use Gmail with your work or school account, ask your administrator to let you share images publicly.
- Search for an image, like your company logo, then get the image URL.
- Add your own image to Google and use that URL.
When data:image/png;base64,###
is used for src
of the image tag, it was found that the signature updated with Gmail.Users.Settings.SendAs.update()
doesn't include src
attribute. When https://###
is used, the signature updated with Gmail.Users.Settings.SendAs.update()
includes the src
attribute.
From above situation, it is considered that data:image/png;base64,###
might not be able to be used to src
of the image tag of the signature. This might be the specification.
So in order to put the image from Google Drive, how about the following flow? I think that this is the method showing at the official document.
When your script is modified, how about the following modification?
var imgBlob = imgFile.getBlob().getAs("image/png"); //getAs doesn't change anything
//Get content type and bytes
var contentType = imgBlob.getContentType();
var imgBytes = imgBlob.getBytes();
var imgData = contentType + ";base64," + Utilities.base64Encode(imgData);
imgFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var imgData = "https://drive.google.com/uc?export=download&id=" + imgFileId;
imgData
of var imgData = contentType + ";base64," + Utilities.base64Encode(imgData);
might be imgBytes
. And when you want to put the image to src
using the base64 data, please use src="data:image/png;base64,###"
. In your script, src="image/png;base64,###"
is used.If I misunderstood your question and this was not the direction you want, I apologize.
Upvotes: 1