How to remove gridlines from the spreadsheet in google app script - google-apps-script

I am trying to write a code in google app script that can mail me the spreadsheet and everything works well. Below is the code I am using.
function convSheetAndEmail(rng, email, subj)
{
var HTML = SheetConverter.convertRange2html(rng);
MailApp.sendEmail(email, subj, '', {htmlBody : HTML});
}
function doGet()
{
// or Specify a range like A1:D12, etc.
var dataRange = SpreadsheetApp.getActiveSpreadsheet().getDataRange()
var emailUser = 'xyz#gmail.com';
var subject = 'Test Email';
convSheetAndEmail(dataRange, emailUser, subject);
}
Now when I am receiving the mail from this script it looks like this
enter image description here
But I don't want to have these Gridlines in my mail. Please advice what I am missing.

Since your are using sheetConverter library. It returns an HTML code with border style element set to 1/1px. So you will have to explicitly replace all the occurrences of border tag in your HTML like so
function convSheetAndEmail(rng, email, subj)
{
var HTML = SheetConverter.convertRange2html(rng)
Logger.log(HTML)
HTML = HTML.replace(' border="1" ',' border="0" ')
HTML = HTML.replace(/border:1px/g,'border:0px')
Logger.log(HTML)
MailApp.sendEmail(email, subj, '', {htmlBody : HTML});
}
Reference:
String.replace()

Related

How to send HTML email with multiple tables from Google Sheets?

I have been working with Google Apps Script lately and found a way to send HTML email containing a table in Google Sheets https://spreadsheet.dev/send-html-email-from-google-sheets#:~:text=Search%20for%20Content%2DType%3A%20text,the%20document%20except%20this%20HTML. But I am not able to configure how I should be doing this with multiple tables (4 in my case) in a single mail only?
function sendEmail() {
var stockData = getData();
var body = getEmailText(stockData);
MailApp.sendEmail({
to: "youremail#example.com",
subject: "Stock update",
body: body
});
}
function getEmailText(stockData) {
var text = "";
stockData.forEach(function(stock) {
text = text + stock.name + "\n" + stock.ticker + "\n" + stock.price + "\n-----------------------\n\n";
});
return text;
}
/**
* #OnlyCurrentDoc
*/
function getData() {
var values = SpreadsheetApp.getActive().getSheetByName("Data").getRange("Stocks").getValues();
values.shift(); //remove headers
var stocks = [];
values.forEach(function(value) {
var stock = {};
stock.name = value[0];
stock.ticker = value[1];
stock.price = value[2];
stocks.push(stock);
})
//Logger.log(JSON.stringify(stocks));
return stocks;
}
The above code works perfectly well for a single table. What modifications can I make to have multiple tables? Any help will be much appreciated.
I believe your goal is as follows.
You want to retrieve the values with the font styles and background color of the cells from the named ranges and want to create the HTML table and send it as an email.
In your one table, only the header row has the specific background color. And the background color of other rows is #ffffff. This is from your sample images. image1, image2.
Modification points:
In your script, the values from the named range are not converted to the HTML. And, your script used one named range. I thought that this might be the reason for your issue.
In order to achieve your goal, how about the following flow?
Retrieve the values from all named ranges including the font styles and the background colors.
Crete HTML tables from the retrieved values.
Send an email using the created HTML tables.
When this flow is reflected in a sample script, it becomes as follows.
Sample script:
In this sample script, in order to covert from the richtext to HTML, "RichTextApp" of a Google Apps Script library is used. So before you use this script, please install the library.
function myFunction() {
const namedRanges = ["sampleNamedRange1", "sampleNamedRange2",,,]; // Please set your named ranges in this array.
const emailAddress = "youremail#example.com"; // Please set the email address.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const { htmls, backgounds } = namedRanges.reduce((o, r) => {
const range = ss.getRangeByName(r);
o.htmls.push(RichTextApp.RichTextToHTMLForSpreadsheet({ range }));
o.backgounds.push(range.getBackgrounds());
return o;
}, { htmls: [], backgounds: [] });
const tables = htmls.map((v, i) => `table ${i + 1}<br><table border="1" style="border-collapse: collapse"><tr style="background: ${backgounds[i][0][0]};">${v.map(r => "<td>" + r.join("</td><td>")).join("</tr><tr>")}</tr></table>`);
MailApp.sendEmail({ to: emailAddress, subject: "Stock update", htmlBody: tables.join("<br>") });
}
When this script is run, the values are retrieved from all named ranges by including the font styles and the background color of cells, and the retrieved values are converted to the HTML tables, and then, the HTML tables are sent as an email.
References:
RichTextApp
sendEmail(message) of Class MailApp
Edit:
I updated RichTextApp. By this, the HTML table can be directly converted from the range of Spreadsheet to a HTML table. Ref When this is used, the sample script is as follows. Before you use this script, please install the library.
Sample script:
function myFunction() {
const namedRanges = ["sampleNamedRange1", "sampleNamedRange2",,,]; // Please set your named ranges in this array.
const emailAddress = "youremail#example.com"; // Please set the email address.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const htmlTables = namedRanges.map(r => RichTextApp.RangeToHTMLTableForSpreadsheet({range: ss.getRangeByName(r)}));
const tables = htmlTables.map((t, i) => `table ${i + 1}<br>${t}`);
MailApp.sendEmail({ to: emailAddress, subject: "Stock update", htmlBody: tables.join("<br>") });
}

Sheets to Docs to Email

I have created a spreadsheet that contains quite a large amount of data.
The plan is to consolidate this data into a readable email to be sent out weekly, each specific row of data is its own email.
I tried going directly from sheets to email, but frankly it never quite looked right, plus the idea was to have a document template, where we could easily update the body without messing with code.
So I decided to write a email template in DOCS, set out a table, then have a script that copied the email template and updated the table with the row of data the script was looking at, then send it via email.
The code works great, but there is one little snag, the table never quite copies over to the email properly.
Below is are images of how the table is formatted in the email compared to the format in the template.
I just can not figure out how or why the format does not carry over.
I have also listed my code below, any help or advice on how I achieve the correct formatting would be appreciated.
UPDATE;
I have updated the question to show the code where we find the url of the document and convert to HTML,
var classArray=[];
//get html from Doc
var subject= row[30];
var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+newID+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url,param).getContentText();
//docs uses css in the head, but gmail only takes it inline. need to move css inline.
//DOES NOT HANDLE HEADER CLASSES (eg h1, h2).
var headEnd = html.indexOf("</head>");
//get everything between <head> and </head>, remove quotes
var head = html.substring(html.indexOf("<head>")+6,headEnd).replace(/"/g,"");
//split on .c# with any positive integer amount of #s
var regex = /\.c\d{1,}/;
var classes = head.split(regex);
//get class info and put in an array index by class num. EG c4{size:small} will put "size:small" in classArray[4]
var totalLength = 0;
for(var i = 1; i < classes.length; i++){
//assume the first string (classes[0]) isn't a class definition
totalLength = totalLength + classes[i-1].length;
var cNum = head.substring(totalLength+2,head.indexOf("{",totalLength)); //totallength+2 chops off .c, so get what's between .c and {
totalLength = totalLength + 2 + cNum.length //add .c and the number of digits in the num
classArray[cNum] = classes[i].substring(1,classes[i].indexOf("}")); //put what's between .c#{ and } in classArray[#]
}
//now we have the class definitions, let's put it in the html
html = html.substring(headEnd+7,html.indexOf("</html>")); //get everything between <html> and </html>
var classMatch = /class=\"(c\d{1,} ){0,}(c\d{1,})\"/g
//matches class="c# c#..." where c#[space] occurs any number of times, even zero times, and c#[no space] occurs after it, exactly once
html = html.replace(classMatch,replacer); //replace class="c# c#..." with the definitions in classArray[#]
//make the e-mail!
GmailApp.sendEmail(row[31], subject, "HTML is not enabled in your email client. Sad face!", {
htmlBody: html,
});
function replacer(match){
var csOnly = match.substring(7,match.length-1); //class=" has 7 chars, remove the last "
var cs = csOnly.split(" "); //get each c#
var ret = "style=\""
for(var cCount = 0; cCount < cs.length; cCount++){
ret = ret + classArray[cs[cCount].substring(1)];
}
return ret+"\"";
}
})
}
The comments in the code says that Gmail can only use inline styling. That was true several years ago but currently Gmail allows to have a style tag inside a head tag. Considering this, the script could be much more simple that the one included in the question.
Below there is a script showing a sample that sends a Google Document content as the HTML body of an email message.
/**
* Get document as HTML
* Adapted from https://stackoverflow.com/a/28503601/1595451
*/
function getGoogleDocumentAsHTML(id) {
var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
var url = "https://docs.google.com/feeds/download/documents/export/Export?id=" + id + "&exportFormat=html";
var param = {
method: "get",
headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
muteHttpExceptions: true,
};
var html = UrlFetchApp.fetch(url, param).getContentText();
return html;
}
/**
* Send the content of a Google Document as the HTML body of a email message
*/
function sendEmail(){
const url = /* add here the URL of your Google Document */;
const id = url.match(/[^\/]{44}/)[0];
const doc = getGoogleDocumentAsHTML(id);
const head = doc
.replace(/<meta[^>]+?>/g,'') // get rid of the meta tags
.match(/<head.+?<\/head>/)[0];
const body = doc.match(/<body[^>]+?>.+<\/body>/)[0];
const htmlBody = [head,body].join('\n');
MailApp.sendEmail({
to: /*add here the recipient email address */,
subject: /*add here the email subject */,
htmlBody: htmlBody
})
}
NOTE: You might want to clear the class of the body tag to avoid the margins set for it.

How to get a variable to work in an HTML file from google forms?

I am using a google script attached to my google form to send emails of the results. When I have it sending via regular text, the variables work. But when I try to use it via an HTML file the variables are showing up as the variable name.
I got it working via Text but not HTML
The .gs file is:
function onFormSubmit(e) {
var JobName = e.values[10];
var JobDate = e.values[1];
var SubmitterName = e.values[2];
var subject = "Job Form Submitted";
var htmlBody = HtmlService.createHtmlOutputFromFile('emailtext').getContent();
MailApp.sendEmail({
to: xxx#xxxx.com
subject: 'Test Email markup - ',
htmlBody: htmlBody,
});
}
The HTML file is:
</head>
<body>
<p><strong>Submitter Name: </strong>%SubmitterName</p>
<p><strong>Job Name:</strong> %JobName</p>
</body>
The variables should display not the variable name
You want to use %SubmitterName of <p><strong>Submitter Name: </strong>%SubmitterName</p> as the variable of var SubmitterName = e.values[2].
You want to use %JobName of <p><strong>Job Name:</strong> %JobName</p> as the variable of var JobName = "e.values[10].
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Pattern 1:
In this pattern, Google Apps Script is modified as follows. The values are replaced by replace().
From:
var htmlBody = HtmlService.createHtmlOutputFromFile('emailtext').getContent();
To:
var htmlBody = HtmlService.createHtmlOutputFromFile('emailtext').getContent();
htmlBody = htmlBody.replace("%SubmitterName", SubmitterName);
htmlBody = htmlBody.replace("%JobName", JobName);
Pattern 2:
In this pattern, both Google Apps Script and HTML are modified as follows. The values are replaced using the Templated HTML.
Google Apps Script:
From:
var htmlBody = HtmlService.createHtmlOutputFromFile('emailtext').getContent();
To:
var htmlBody = HtmlService.createTemplateFromFile('emailtext');
htmlBody.obj = {JobName: JobName, JobDate: JobDate, SubmitterName: SubmitterName};
htmlBody = htmlBody.evaluate().getContent();
HTML
From:
<p><strong>Submitter Name: </strong>%SubmitterName</p>
<p><strong>Job Name:</strong> %JobName</p>
To:
<p><strong>Submitter Name: </strong><?= obj.SubmitterName ?></p>
<p><strong>Job Name:</strong><?= obj.JobName ?></p>
Note:
Please select one from above 2 patterns.
References:
replace()
HTML Service: Templated HTML
If I misunderstood your question and this was not the direction you want, I apologize.

how to put inline image in automated mail from Google sheet

I want to send mail with an inline image instead of as an attachment through google sheet. Please help
the script is as below:
function emailSummary() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sh = ss.getSheetByName("Hitesh")
var file = DriveApp.getFileById('1T8QA_WsXQkZZGwmBSN13iPV7rM8xGG_GtYy6T1eug-c')
var gmail = 'hitesh.gtg#Gmail.com';
var html = '<png>'
MailApp.sendEmail("hitesh.gtg#gmail.com", "sunject", "Dear Sir,\n\n Forwarding herewith Monthly Summaryw \n\n Regards \n Hitesh ", {
//email address, subject, message
name: 'Hitesh', //file name
attachments: [file.getAs(MimeType.PDF)] //file to attach
});
}
You can pass HTML to the .sendMail() function. This link to the official documentation includes an example for inline images!
// This code fetches the Google and YouTube logos, inlines them in an email
// and sends the email
function inlineImage() {
var googleLogoUrl = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
var googleLogoBlob = UrlFetchApp
.fetch(googleLogoUrl)
.getBlob()
.setName("googleLogoBlob");
//You can also get these images from your drive to attach them.
var imgBlob = DriveApp.getFileById("<DRIVE_FILE_ID_OF_PICTURE>")
.getBlob()
.setName("imgBlob");
MailApp.sendEmail({
to: "recipient#example.com",
subject: "Logos",
htmlBody: "inline Google Logo<img src='cid:googleLogo'> images! <br>" +
"img from drive: <img src='cid:driveImg'>"
inlineImages:
{
googleLogo: googleLogoBlob,
driveImg: imgBlob
}
});
}
Emailing Images from your Google Drive
You can use the htmlBody parameter in GmailApp.sendMail(). However, if you want to avoid having to store the image in a URL that is publicly accessible. You can do something like this.
This is a portion of my JavaScript:
function sendImgMsg() {
var fileId=$('#mediaSel').val();//This is the fileId where the image is store. In my image converter script I keep all of this images in the same folder.
google.script.run
.withSuccessHandler(function(fObj){
var msg=$('#emsg').val();//This is the contents of a textarea
var hl='<p>' + msg + '</p><br /><strong>File Name:</strong> '+ fObj.name + '<img src="'+ fObj.uri +'" title="' + fObj.filetype + '" />';
$('#email').css('display','none');
google.script.run.sendImageMessage(hl);//This is the code that sends the email
})
.getSelectedFile(fileId);
}
This is a portion of my html:
<div id="email">
<textarea id="emsg" cols="40" rows="4"></textarea>
<br /><input type="button" value="Send" onClick="sendImgMsg()" />
</div>
This is a portion of my code.gs:
function getSelectedFile(fileId){
var file=DriveApp.getFileById(fileId);
var dataURI=file.getBlob().getDataAsString();
var s=dataURI.split(',')[0];
var mediaType=s.slice(s.indexOf(':')+1,s.indexOf('/'));
var fileType=s.slice(s.indexOf('/')+1,s.indexOf(';'));
var fObj={name:file.getName(),uri:dataURI ,type:mediaType,filetype:fileType};
return fObj;
}
function sendImageMessage(hl) {
GmailApp.sendEmail('recipient', 'ImageInAnEmail', null ,{htmlBody: hl});
}
This is the code that converts external images to imageURI's:
function convImageUrl(url){
var blob=UrlFetchApp.fetch(url).getBlob();
var b64Url='data:' + blob.getContentType() + ';base64,' + Utilities.base64Encode(blob.getBytes());
return b64Url;
}
The above is a part of a script that I use for converting images to imageURI's so that I can store and access them on my Google Drive.

How to send rich text emails with GmailApp?

I’m trying to send a Google Doc, with all of its formatting, in an email.
function sendGoogleDocInEmail() {
var doc = DocumentApp.openById("example_Id");
var body = doc.getBody();
var text = body.getText();
GmailApp.sendEmail("emailaddress#gmail.com", "Hi", text);
This code works fine, but the email is sent as plain text.
I have descriptive hyperlink text pieces in the Google Doc, and they lose their hyperlinks when converted to plain text.
Is there any way I can keep all of the hypertext formatting when sending the email?
I’ve tried passing the body object to the method instead, but that just sends an email with DocumentBodySection in the body.
Thanks!
Trying using a combination of this script: https://stackoverflow.com/a/28503601/3520117
And then using the htmlBody parameter of the MailApp.sendEmail method.
Untested, but should work:
function emailGoogleDoc(){
var id = DocumentApp.getActiveDocument().getId() ;
var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+id+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url,param).getContentText();
Logger.log(html);
var email = person#domain.tld;
var subject = 'Subject line';
var body = "To view this email, please enable html in your email client.";
MailApp.sendEmail(
email, // recipient
subject, // subject
body, { // body
htmlBody: html // advanced options
}
);
}