I have a script that produces an automated email from cell content in a Google Sheet. Is it possible to restrict the width of a cell's output in the email, forcing the text to wrap? I have tried using textarea tags as follows:
+ <textarea rows="4" cols="20">
+ sheet.getRange(6,9,1,1).getValue()
+ </textarea>
However, this simply outputs as "+ sheet.getRange(6,9,1,1).getValue() +" (i.e. it doesn't generate the cell content).
Is this possible?
Here's how I have built the script:
function EmailFormConfirmation() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
Utilities.sleep(60000);
var sheet = ss.getSheetByName("Form responses");
var lock = LockService.getPublicLock();
lock.waitLock(60000);
lock.releaseLock();
var email = sheet.getRange(2,9,1,1).getValue();
var message = "<HTML><BODY>"
+ "<P >Hi "
+ sheet.getRange(4,9,1,1).getValue()
+ ","
etc.
EDIT The below produces the cell content, but doesn't wrap the text.
var htmlMsg = "<HTML><BODY>"
+ "<textarea rows='4' cols='10'>"
+ sheet.getRange(6,9,1,1).getValue()
+ "</textarea>"
+ "</HTML></BODY>";
MailApp.sendEmail(email, "LMI Request", "", {htmlBody: htmlMsg});
To respond to the question re: textbox, the following did as you requested
var htmlMsg = "<HTML><BODY>"
+ "<textarea rows='4' cols='20'>"
+ sheet.getRange(6,9,1,1).getValue()
+ "</textarea>"
+ "</BODY></HTML>";
GmailApp.sendEmail("m....l#gmail.com", "subject","hi" , {htmlBody: htmlMsg});
note how the single and double quotes are used.
Here is an example of how you can use templates to build your email responses. The documentation can be found here:
https://developers.google.com/apps-script/guides/html/templates
In code.gs
function myFunction(){
var sheet = SpreadsheetApp .....
var value = sheet.getRange(6,9,1,1).getValue();
var emailHtml = buildTemplate(value);
GmailApp.sendEmail("person#example.com", "subject","Hello", {htmlBody: emailHtml});
}
function buildTemplate(values){
var template = HtmlService.createTemplateFromFile('emailTemplate');
template.tmpValues = values;
return template.evaluate().getContent();
}
in emailTemplate.html
<html>
<body>
<textarea rows='4' cols='20'>
<?=tmpValues?>
</textarea>
</body>
</html>
Related
I am doing a program in which I would like to press a button and be able to send by email the information of two specific sheets as attachments in PDF, which I would also like to save it in a folder in my Drive to keep the information organize
I have checked some of your information but can't do the PDF part
function sendEmail(){
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var ss = spreadsheet.getActiveSheet()
var NoInf =ss.getRange(10, 11).getValue();
var Email = ss.getRange(12, 15).getValue();
var propietario = ss.getRange(10, 7).getValue();
var Paciente = ss.getRange(11,7).getValue();
var TipoInforme = ss.getSheetName()
var Imagen = spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Imagenes'),true);
var Asunto = NoInf + " - " + TipoInforme + " - " + propietario + " - " +Paciente;
var Mensaje = "Anexo a la presente envĂo informe: " + '\n\n' + "No de Informe: " + NoInf;
MailApp.sendEmail(Email, Asunto, Mensaje)
};
Based on your last comment I understand that you want to send two Sheets as PDF in an email attachment. If that is correct, then you can use a code like the following one.
function sendMail() {
var spreadsheet1 = DriveApp.getFileById(
'{MY FIRST SPREADSHEET ID}');
var spreadsheet2 = DriveApp.getFileById(
'{MY SECOND SPREADSHEET ID}');
MailApp.sendEmail('{EMAIL TO}', '{EMAIL SUBJECT}',
'{MESSAGE BODY}', {
name: '{MY NAME}',
attachments: [spreadsheet1.getAs(MimeType.PDF), spreadsheet2.getAs(
MimeType.PDF)]
});
}
In this example the Sheets are opened by DriveApp.getFileById() and later attached as PDF by using File.getAs(). Please, don't hesitate to ask me to further clarify.
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.
I have applied this solution to e-mail the rows of a google sheet as part of the HTML body.
Unfortunately, it errors out because there is a limit set on the HTML body. The number of rows in my data is dynamic.
Limit Exceeded: Email Body Size. (line 209, file "SideBar")
Is there a way of getting around this? I would be OK with providing a preview of the rows, let's say 10 rows with all columns, on the HTML body and then providing a link to view the rest. Because the content on the sheet changes, the link should not be to that sheet. Instead I was thinking of saving a copy of the sheet as a new file on their own drive and linking to that. Another option is attaching an HTML file that has all the rows.
Here is what I currently have:
function emailBreakdown(emailUser, bodyAdd){
SpreadsheetApp.getActiveSpreadsheet().toast('Please wait while information is refreshed.');
if(emailUser == null){emailUser = 'xxxxx#yyyyyy.com'}
if(bodyAdd == null){bodyAdd = 'Testing running of function on script editor'}
var ss = SpreadsheetApp.getActive();
var detailsSht = ss.getSheetByName("Details");
var dataRange = detailsSht.getDataRange();
var curDate = Utilities.formatDate(new Date(), "GMT+1", "MM/dd/yyyy");
var subject = 'Summary - Exported Data ' + curDate;
var body = '<br />---------------------------------------------------------------<br />You have received an export of a dataset from the Summary dashboard. Please see below:<br /><br />' //provide link to the whole dashboard.
convSheetAndEmail(dataRange, emailUser, body, bodyAdd, subject);
}
function convSheetAndEmail(rng, emailUser, body, bodyAdd, subject){
var HTML = SheetConverter.convertRange2html(rng);
MailApp.sendEmail(emailUser, subject, '', {htmlBody : bodyAdd + body + HTML});
}
The following is code I've been able to assemble through further research. It works well and addresses my requests. Here is what it does:
Attaches a sheet. In this case an xls file. Chose this over HTML. To allow user to manipulate in excel if needed.
Provides a preview of 10 lines as HTML in the body of the e-mail.
Preview and attached file preserves format.
What it does not address:
Save file to user's personal drive.
Here it goes:
function emailBreakdown(emailUser, bodyAdd){
SpreadsheetApp.getActiveSpreadsheet().toast('Please wait while information is refreshed.');
//If running on script editor the variables will not be transferred. Assign values below:
if(emailUser == null){emailUser = 'xxxxxx#yyyyyyy.com'}
if(bodyAdd == null){bodyAdd = 'Testing running of function on script editor'}
var ss = SpreadsheetApp.getActive();
var detailsSht = ss.getSheetByName('Details');
var dataRange = detailsSht.getRange('A1:FS11'); //For the preview we are only looking at the first 10 rows of data.
var curDate = Utilities.formatDate(new Date(), 'GMT+1', 'MM/dd/yyyy');
//Gather data to convert specific sheet to excel document so it can be attached to the e-mail
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId();
var sheetID = detailsSht.getSheetId().toString()
var requestData = {'method': "GET", 'headers':{'Authorization':'Bearer ' + ScriptApp.getOAuthToken()}};
var url = 'https://docs.google.com/spreadsheets/d/' + ssID + '/export?format=xlsx&id=' + ssID + '&gid=' + sheetID;
var result = UrlFetchApp.fetch(url , requestData);
var contents = result.getContent();
//Assemble E-mail components
var subject = 'Summary - Exported Data ' + curDate;
var body = bodyAdd +
'<br /><br /><hr style="border: none;border-top: 3px double #333;color: #333;overflow: visible;text-align: center;height: 5px;"><br />' +
'You have received an export of a dataset from the Summary dashboard. Below is a preview of the dataset:<br /><br />'
var afterBody = '<br /><br /><b>You can view the full dataset through the attached XLS file.</b>'
convSheetAndEmail(ss, contents, dataRange, emailUser, body, afterBody, subject);
};
function convSheetAndEmail(ss, contents, rng, emailUser, body, afterBody, subject){
var HTML = SheetConverter.convertRange2html(rng);
//Send email
MailApp.sendEmail(
emailUser,
subject,
'',{
htmlBody : body + HTML + afterBody,
name: 'Full Data Export',
attachments:[{fileName:'Export Data - ' + ss.getName() + '.xls', content:contents, mimeType:'application//xls'}]
}
);
};
Apart from the resource listed in the question, I also borrowed code from here.
I am new to Google Apps and Google sheets and would appreciate a little help. I have a google sheet with some data in a table that is simply a date column and then a few columns of data collected from that date with a new row for each days data. I wish to copy the last 7 days, 30 days, 60 days etc to a new sheets. Essentially copy the last (x)Rows of a table to a new sheet where I can vary (x).
Is there a simply function that I can use on a new sheet to get the desired (x) rows from the table.
Or do I have to use a script. If so how do I proceed.
Any replies would be greatly appreciated.
Thank you
I use the same technique in an activities schedule I built for the school I work for. In my version I created I created a sheet for today and the next 7 days. https://docs.google.com/spreadsheet/ccc?key=0AnQ7SpwUoM8odDRKZWE2eVh4QTNzOWsyQmlkb3JvRVE&usp=sharing#gid=10
Below is the filter function I used for the next 7 days.
=filter('All Events'!A:H,('All Events'!A1:A1654=DATEVALUE(now()))+('All Events'!A1:A1654=DATEVALUE(now()+1))+('All Events'!A1:A1654=DATEVALUE(now()+2))+('All Events'!A1:A1654=DATEVALUE(now()+3))+('All Events'!A1:A1654=DATEVALUE(now()+4))+('All Events'!A1:A1654=DATEVALUE(now()+5))+('All Events'!A1:A1654=DATEVALUE(now()+6))+('All Events'!A1:A1654=DATEVALUE(now()+7)))
To add a menu, and run code I've created the following code and explanation:
Add a Function the runs when the spreadsheet opens:
Choose TOOLS, SCRIPT EDITOR and the code editor will open. Paste in this onOpen() function.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Custom Menu')
.addItem('Display User Dialog', 'displayUserDialog')
.addToUi();
};
That code will run when you open the spreadsheet. You will see a new Menu Item.
That code is set up to trigger some more code when you choose 'Display User Dialog' from the Custom Menu. You need to add more code. Add this function:
function displayUserDialog() {
//Logger.log('displayUserDialog ran: ');
var html = HtmlService.createTemplateFromFile('Dialog Copy Choices')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.NATIVE)
.setWidth(500)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(html, 'My custom dialog');
};
The above two functions go into a gs script file. I think a new script file is usually automatically created name: Code.gs
Create a new HTML file:
From the FILE menu, choose NEW - HTML
HTML File named "Dialog Copy Choices"
<div id="outer" style="padding:1;"/>
<div>
<br>Sheet To Copy To:<br>
<select id="idSheetNames">
<?!= getSheetNames(); ?>
</select>
<br>
<br>
<div>Copy To:</div>
<input id="idToCol" type='text' placeholder='Column To Copy to:'>
<br>
<input id="idToRow" type='text' placeholder='Row To Copy to:'>
<br>
<br>
<div>Copy From:</div>
<input id="idFromStart" type='text' placeholder='A1'>
<br>
<input id="idFromEnd" type='text' placeholder='D20:'>
<br>
<br>
<input type="button" value="Copy Cells" id="idCopyBtn" onclick="myFunction()">
</div>
<script>
function myFunction() {
var sheetToGetData = document.getElementById("idSheetNames").value;
var copyToRow = document.getElementById("idToRow").value;
var copyToCol = document.getElementById("idToCol").value;
var copyFromStart = document.getElementById("idFromStart").value;
var copyFromEnd = document.getElementById("idFromEnd").value;
//console.log("values of variables: " + sheetToGetData + " : " + copyToCol + " : " + copyToRow + " : " + copyFromStart + " : " + copyFromEnd);
google.script.run.gsCopyData(sheetToGetData, copyToCol, copyToRow, copyFromStart, copyFromEnd);
google.script.host.close();
};
</script>
Refresh the spreadsheet after adding all that code, and a new custom menu should appear. Use the custom menu to display the dialog.
The custom dialog displays all the sheets in your spreadsheet in a drop down field. The drop down allows you to choose what sheet to copy the data to:
gs Code to Get Sheet Names
function getSheetNames() {
var allSheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var howManySheets = allSheets.length;
var sheetNames = [];
var htmlSelectOptions = "";
var thisName = "";
for (var i = 0;i < howManySheets; i++) {
thisName = allSheets[i].getName();
htmlSelectOptions += '<option value="' + thisName + '">' + thisName + '</option>';
};
return htmlSelectOptions;
};
gs Code to Copy Data
function gsCopyData(sheetToGetData, copyToCol, copyToRow, copyFromStart, copyFromEnd) {
//Logger.log(sheetToGetData + " : " + copyToCol + " : " + copyToRow + " : " + copyFromStart + " : " + copyFromEnd);
//Logger.log("gsCopyData ran");
var alphaBet = 'abcdefghijklmnopqrstuvwxyz';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var rowStartCopy = Number(copyFromStart.slice(1));
var colStartCopy = copyFromStart.slice(0,1);
colStartCopy = 1 + alphaBet.indexOf(colStartCopy.toLowerCase());
var rowEndCopy = Number(copyFromEnd.slice(1));
var colEndCopy = copyFromEnd.slice(0,1);
colEndCopy = 1 + alphaBet.indexOf(colEndCopy.toLowerCase());
var numRows = rowEndCopy - rowStartCopy + 1;
var numColumns = colEndCopy - colStartCopy + 1;
var rangeToCopy = sheet.getRange(rowStartCopy, colStartCopy, numRows, numColumns);
copyToCol = alphaBet.indexOf(copyToCol.toLowerCase()) + 1;
var destinationSheet = ss.getSheetByName(sheetToGetData);
//Logger.log(destinationSheet + copyToCol + numColumns + copyToRow + numRows);
rangeToCopy.copyValuesToRange(destinationSheet, copyToCol, numColumns, copyToRow, numRows);
};
A starting point would be to look at the three FILTER functions.
FILTER
SORT
UNIQUE
Here is the link to the list of Google Spreadsheet functions:
Google Support - Spreadsheet Function List
I'm sure there is a way, using functions, to filter the data you want. If you want something more automated, you'd need to program something. That would be more work.
Either way, it's possible.
I am using a script to have form results e-mailed to me every time the form is submitted. Entire code is posted in Google Groups here:
http://groups.google.com/a/googleproductforums.com/d/topic/apps-script/1rObNfuez6k/discussion
Here's the current code:
function contactUsMailer2(e) {
// var ss = SpreadsheetApp.getActive();
// SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data'); //default sheets - change if you
var setup = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Setup'); //rename the sheets
var width = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data').getLastColumn(); //get "width" of sheet, used to enumrate fields
var myEmailAddress = setup.getRange('B3').getValue(); //get email recipient(s) from "Setup" (default)
var myEmailSubject = setup.getRange('B4').getValue(); //get a subject line from "Setup" (default)
//from row 1 of "Data"
var sheetURL = SpreadsheetApp.getActiveSpreadsheet().getUrl(); //get sheet url to include in email
var formURL = SpreadsheetApp.getActiveSpreadsheet().getFormUrl(); //get form url to include in email
var column = 'A';
var message = '';
var htmlBody = '<html><body><table>'; //generated email will have both an HTML table and a plain-text part
//to be RFC compliant. beginning of html and table.
for (var c=1; c<=width; ++c) {
var data = sheet.getRange(1, c, 1, 1).getValue(); //this gets the "filed" names from the 1st row of "Sheet1"
try {
//retrieve field data and build the HTML and plain-text emails
var message = message + data + ': ' + e.namedValues[data].toString() + '\r\n'; //plain-text
var htmlBody = htmlBody + '<tr><td><b>' + data + ': </b></td><td>' + e.namedValues[data].toString() + '</td></tr>'; //HTML
}
catch (a) {
var message = message + data + ': n/a\r\n';
var htmlBody = htmlBody + '<tr><td><b>' + data + ': </b></td><td>n/a</td></tr>';
}
var column = String.fromCharCode(column.charCodeAt() + 1); //increment column letter
}
var htmlBody = htmlBody + '</table>'; //close table
var message = message + '\r\n\r\nData from form located at ' + formURL + '\r\n'; //put form url in text email
var message = message + 'Data posted to spreadsheet at ' + sheetURL; //put sheet url in text email
var htmlBody = htmlBody + '<br><br>Data from form located here<br>'; //put form url in HTML email
var htmlBody = htmlBody + 'Data posted to spreadsheet here<br>'; //put sheet url in HTML email
var htmlBody = htmlBody + '</body></html>'; //close html
MailApp.sendEmail(myEmailAddress, myEmailSubject, message, {htmlBody: htmlBody}) ; //send the email
}
function showid() {
Browser.msgBox("The sheet ID is:\r\n\r\n" + SpreadsheetApp.getActiveSpreadsheet().getId());
}
Script now works fine with the original spreadsheet, but when I try to use it with a new form and spreadsheet it fails to send the e-mail. The form fill in the spreadsheet just fine and we get the usual e-mail stating that the spreadsheet has been updated, but the script e-mail doesn't come through.
Funny thing is when I debug the script it does send the e-mail, just null entries in all fields (which is what I would expect). Debug doesn't report any errors in the script itself. What am I missing?
Have you authorized the script in your new form ? Since your script is required to send out an email it requires explicit authorization.
Try removing the quote around
for (var c=1; c<=width; ++c) {
var data = sheet.getRange(column + '1').getValue(); //this gets the "filed" names from the 1st row of "Sheet1"
I do something similar in a script and the following works for me.
var rangeval = "B"+(i+1);
var nameFld = filesheet.getRange(i+1,1).getValue();
Joe
Make sure trigger is set to "On Submit". Mine was set to "On Open".