Transform HTML content with formatting into a PDF format using Google Apps Script, then bundle it with an email attachment. Generate a PDF blob directly from the

Seeking help with customizing HTML output from a Google Apps Script form to have different styles for email and PDF files.

Current code:

function doGet(request) {
  return HtmlService.createTemplateFromFile('index')
      .evaluate();//not all caps but it has to match the name of the file and it doesn't - Change to PAGE
}

function include(filename) {
  return HtmlService.createHtmlOutputFromFile(filename)
      .getContent();
}


/****** SHEET ****/
function userClicked(userInfo){
    var url = "https://docs.google.com/spreadsheets/your-sheet-ID";
    var ss = SpreadsheetApp.openByUrl(url);
    var ws = ss.getSheetByName("Data");
    ws.appendRow([userInfo.name, userInfo.email, userInfo.comment, new Date()]);

}


function submitData(form) {
  var subject='New Feedback';
  var body=Utilities.formatString('name: %s <br />email: %s<br />Comment: %s', form.name,form.email,form.comment);
  
/*** FOR HTML EMAIL ***/
    var htmlTemplate = HtmlService.createTemplateFromFile("PDF-page.html");
    htmlTemplate.name = form.name;
    htmlTemplate.email = form.email;
    var htmlBody = htmlTemplate.evaluate().getContent();

/*** CREATE PDF ***/

  var folderId = "your-folder-ID"; // Please set the folder ID.  // Added
  var blob = Utilities.newBlob(htmlBody, MimeType.HTML, form.name).getAs(MimeType.PDF);  // Added - PDF from html email - comment line for serve PDF from document template 
  var file = DriveApp.getFolderById(folderId).createFile(blob);  // Added

//****email****//  
  var aliases = GmailApp.getAliases()
   Logger.log(aliases); //returns the list of aliases you own
   Logger.log(aliases[0]); 

...

For more information about this application, check out my post here:

Google App Script setTimeout Function problem


The following two sections illustrate different styles:

The first section uses the Gmail basic style, specifying the fields edited in the form:

  • Name: example name

    Email: example email

    Comment: example comment

var body=Utilities.formatString('name: %s <br />email: %s<br />Comment: %s', form.name,form.email,form.comment);

/****************************************************************************/

GmailApp.sendEmail(...) 

The second section defines the page style using a separate HTML file ("PDF-page.html"):

var htmlTemplate = HtmlService.createTemplateFromFile("PDF-page.html");
    htmlTemplate.name = form.name;
    htmlTemplate.email = form.email;
    var htmlBody = htmlTemplate.evaluate().getContent(); 

I hope this explanation clarifies the script adjustments made. If you need further assistance, feel free to ask. Thank you!

...

Answer №1

  • If you're looking to generate a PDF file that includes images and CSS from HTML, this answer might be helpful.
  • The HTML for email sending is already prepared.

Based on your goal, here are some modification points to consider:

Key Changes:

  • To include an image in the PDF, you need to encode the image as base64 data. Reference
    • In your script, using cid:image in PDF-page.html won't work for adding images to the PDF file.

Updated Script:

Make these adjustments when modifying your script:

Google Apps Script Updates:

From:
/*** FOR HTML PDF **/
var htmlTemplate = HtmlService.createTemplateFromFile("PDF-page.html");
htmlTemplate.name = form.name;
htmlTemplate.email = form.email;
var pdf_html = htmlTemplate.evaluate().getContent();

/*** CREATE PDF ***/

var folderId = "your-folder-ID"; // Please set the folder ID
var blob = Utilities.newBlob(pdf_html, MimeType.HTML, form.name).getAs(MimeType.PDF); 
var file = DriveApp.getFolderById(folderId).createFile(blob);
To:
/*** FOR HTML PDF **/
var htmlTemplate = HtmlService.createTemplateFromFile("PDF-page.html");
htmlTemplate.name = form.name;
htmlTemplate.email = form.email;
var fileIdOfImageFile = "MY-IMAGE-ID";  // Set the file ID of the image file.
var imageBlob = DriveApp.getFileById(fileIdOfImageFile).getBlob();  
htmlTemplate.imageData = imageBlob.getContentType() + ';base64,' + Utilities.base64Encode(imageBlob.getBytes());  
var pdf_html = htmlTemplate.evaluate().getContent();

/*** CREATE PDF ***/
var folderId = "your-folder-ID";
var blob = Utilities.newBlob(pdf_html, MimeType.HTML, form.name).getAs(MimeType.PDF);
var file = DriveApp.getFolderById(folderId).createFile(blob);

HTML Modifications: PDF-page.html

Update:
<p class="image-logo"><img src='cid:image' width="150" height="56"></p>
To:
<p class="image-logo"><img src="data:<?= imageData ?>" width="150" height="56" /></p>

Note:

  • It seems like the text-pdf style from your css-pdf.html isn't utilized in PDF-page.html. Is <p class="email-simply"> in PDF-page.html meant to match <p class="text-pdf"> based on the image provided?
  • Not all CSS styles may work seamlessly in this context. Apologies for any inconvenience caused by this limitation.

Additional Resources:

  • How to display Base64 images in HTML?
  • Show images inside a pdf created with Google Apps Script Blob

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to update an element in an array inside a JavaScript object

In my NodeJS code, I have an object structured like this: const jsonData= { "description": "description", "hosts": [ "host1", "host2", "host3" ] } The task at ...

Strange glitches and slow loading problems plaguing website. (GoDaddy)

TackEmporium.com Lately, I have been revamping my website, which was originally given to me by a friend. I have been making slight adjustments to update its appearance while keeping its classic look with enhanced resolution and cleaned-up HTML5 code. Rec ...

Invoking a function within an HTML file does not result in triggering an alert message

Hello everyone, thank you for taking the time to look at this. I'm attempting to execute a javascript function when I click on the update button. Here is the javascript code: var text2Array = function() { // This function takes the value from the t ...

Is it better to use e.target instead of refs when testing?

I have been frequently creating components like this: <input ref="ckbx" type="checkbox" checked={this.props.checked} onChange={() => this.props.onChange(this.refs.ckbx.checked)} /> However, I recently realized that testing this is ...

Type Error: Issue encountered while resolving module specifier

Upon trying to import the d3.js library in a project that utilizes npm, I encountered the error message: TypeError: Error resolving module specifier: d3. This issue specifically occurred while using Firefox. index.html <!DOCTYPE html> <html lang ...

How callbacks inside a loop can leverage Javascript closures

How can I ensure that the last line of code in the loop returns a value? $scope.runActionwithObjects = function() { for (var i = 0; i < $scope.Objects.length; i++) { console.log($scope.Objects[i]); //$scope is being acces ...

Row Carousel Share - Horizontal Perspective

Having some trouble getting my carousel to align horizontally with other text in a row – it keeps taking up the full width instead of the 40% I've set. Below, you'll find the code snippet and screenshots for reference. In the screenshot above ...

JavaScript WYSIWYG Algorithm

Despite my searches on SO, it appears that most questions revolve around simply making a div editable using contenteditable="true". I am interested in finding the most effective method for tracking all formatting tags applied to a document. Merely togglin ...

Can a jumbotron and navigation bar be permanently attached to the top of a screen?

Currently, I am in the process of constructing my website using Bootstrap and my goal is to ensure that the header and navigation bar remain fixed at the top of the page while the content below scrolls underneath. While I am aware that it is possible to fi ...

The image is not appearing on the webpage even though the online URLs are functioning correctly

I am currently facing an issue with my Django portfolio website where I cannot get my photo to display even though the path is correct. However, online images are displaying properly on the site. <html lang="en"><head><link href="https: ...

"Loopback's MongoDB is successfully retrieving data for GET requests, however, it is not providing

myModel.remoteMethod('getName', {accepts: {arg: 'id', type: 'Number', required: true}, http: {path: '/customer/:id', verb: 'get'}, returns: {arg: 'results',type: 'Obje ...

Error in scrolling previews detected in Jssor horizontal template maker

I've been working with Jssor Slider Maker and I'm using the vertical preview template that features two columns on the left side and a maximized image on the right side. After pulling the code from the developers pack, it includes scripts, CSS an ...

Making changes to a list by adding or removing items, as well as adjusting the overall total

I'm in the process of creating a unique feature similar to a shopping cart, but instead of adding items to the cart, I'm adding them to a shortlist. My goal is to add the item to the shortlist, update the count on the shortlist, and then display ...

Tips for creating a div element that closes on the second click:

On the PC version, I have three blocks that open and close perfectly when clicked. However, on the mobile version, when I click on one block, it opens but does not close unless I click on another block. Additionally, if I click again on the same block th ...

Utilizing Angular JS to ensure services are universally accessible across controllers and views

Imagine we have a service like this: myApp.factory('FooService', function () { ... Now, from a controller, the code would look something like this: myApp.controller('FooCtrl', ['$scope', 'FooService', function ($s ...

Trouble with apostrophes rendering in JavaScript on WordPress posts

My current challenge involves adding a post to Wordpress using an external script. This post includes a JavaScript section that contains an iframe for displaying movies. Knowing that Wordpress splits default tags, I have implemented a special plugin to han ...

Personalize the hover effect of CardActionArea

I'm attempting to personalize the hover effect of material-ui's CardActionArea for a specific component in my React application. Unfortunately, I am struggling to locate detailed documentation on how to style it effectively. Even after experimen ...

The transparency in Three.js took a turn for the worse after the update from r67 to r68

I encountered a strange problem when switching from three.js version 67 to version 68. In version 67, everything appeared correctly (triangles behind transparent triangles were visible), but in version 68, something seems to have gone awry. Below are two ...

Combine assorted fabrics and materials in selected designs

Is it possible to incorporate multiple texture maps into a material such as phong? I am aware that using shadermaterial and passing them as uniforms makes it simple to mix them in the shader, but I prefer to utilize existing specular maps, environment map ...

conducting a validation using ajax when submitting

Currently, I am exploring the implementation of AJAX validation within a submit() handler for a web form. The AJAX functionality is executed using $.ajax() from jQuery. While setting async: false yields successful results, it triggers a deprecation notice, ...