Sending only one sheet or active sheet as pdf via email - javascript

Hello I have been trying to write my first script to send just one of the sheet from one of my google document but everytime I end up sending all the sheets instead. The document has a main page daily where i have the list of emails and then 7 sheets called monday, tuesday, etc
This is the code i use - can you help?
function emailActivesheetAsPDF() {
DocumentApp.getActiveDocument();
DriveApp.getFiles();
const ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1_3VpJaFliJVYt1JL3cLSKw2ftsmsLeDjznHJ66-wq9w/edit");
const value = ss.getSheetByName("Daily").getRange("B5").getValue();
const email = value.toString();
const subject = 'Yesterday Handover';
const body = "Please find attached yesterday handover";
const url = 'https://docs.google.com/spreadsheets/d/1_3VpJaFliJVYt1JL3cLSKw2ftsmsLeDjznHJ66-wq9w/export?';
const exportOptions =
'exportFormat=pdf&format=pdf'
'&size=legal'
'&portrait=true'
'&fitw=false'
'&sheetnames=false&printtitle=false'
'&pagenumbers=false&gridlines=false'
'&fzr=false'
'&gid=1263775066';
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var response = UrlFetchApp.fetch(url+exportOptions, params).getBlob();
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments: [{
fileName: "Handover" + ".pdf",
content: response.getBytes(),
mimeType: "application/pdf"
}]
});
}

Explanation / Issue:
You forgot to concatenate the options in the exportOptions variable and therefore exportOptions gets only the value of &size=legal and ignores the rest of the parameters including gid which you specify the sheet id. One solution is to concatenate the options via +.
I also improved your code to make it more flexible. For example, instead of defining a sheet by its gid in the code, you can define it by its name in the variable sheetToPrint and then GAS will get its gid and use it as an export option for the pdf.
Solution:
function emailActivesheetAsPDF() {
const sheetToPrint = "Daily"; // name of the sheet to print
const ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1_3VpJaFliJVYt1JL3cLSKw2ftsmsLeDjznHJ66-wq9w/edit");
const ssID = ss.getId();
const email = ss.getSheetByName("Daily").getRange("B5").getValue();
const subject = 'Yesterday Handover';
const body = "Please find attached yesterday handover";
const shID = ss.getSheetByName(sheetToPrint).getSheetId();
const url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=pdf&id="+ssID;
const exportOptions =
'&size=legal'+
'&portrait=true'+
'&fitw=false'+
'&sheetnames=false&printtitle=false'+
'&pagenumbers=false&gridlines=false'+
'&fzr=false'+
'&gid='+shID;
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var response = UrlFetchApp.fetch(url+exportOptions, params).getBlob();
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments: [{
fileName: "Handover" + ".pdf",
content: response.getBytes(),
mimeType: "application/pdf"
}]
});
}

Related

I have an error code in my getBody() function and I dont know why

So I'm creating this code where the template is selected through a series of If statements. so it is a changing variable. I am simply trying to now replace text in the selected template and I keep getting the same error that getBody() is not a function. Any help is greatly appreciated!
var doc = DriveApp.getFileById(templateId);
var copy = doc.makeCopy();
var destination = DriveApp.getFolderById('1mGCx4yXX_NnLHsHsGWBGkzwAVhG-cTrc');
destination.addFile(copy);
copy.setName(regno + ' statistical analysis');
var copiedTemplateId = copy.getId();
var body = doc.getBody();
var header = doc.getHeader();
DriveApp.getFileById returns a File.
So, doc is of type File.
There is no "getBody" function for a File, at least it doesn't exist in the documentation: https://developers.google.com/apps-script/reference/drive/file
This works:
function myfunk() {
const regno = "test";
var file = DriveApp.getFileById("fileid");
var destination = DriveApp.getFolderById("folderid");
let name = regno + ' statistical analysis';
var copy = file.makeCopy(name, destination);
var copiedTemplateId = copy.getId();
let doc = DocumentApp.openById(copiedTemplateId);
var body = doc.getBody();
var header = doc.getHeader();
Logger.log('id: %s, body: %s, header: %s',copiedTemplateId,body,header);
}
File was a Google Document and a copied was created in the appropriate directory and renamed correctly.

Adding image from spreadsheet into an e-mail with Apps Script

I'm creating an automatic e-mail which includes many data that change every week.
I'm new in Apps Script and I would like to add an image at the end of the e-mail.
Here the code :
// Drive where is stored the image
const folder = DriveApp.getFolderById("1XXXXXXXXX");
// Retrieve ID file where is stored the image
const file = folder.getFilesByName("file")
const fileIDs = [];
while (file.hasNext()) {
var files = file.next();
fileIDs.push(files.getId());
}
var ssFile = SpreadsheetApp.openById(fileIDs[0]);
SpreadsheetApp.setActiveSpreadsheet(ssFile);
//Spreadsheet
var mail = ssFile.getSheetByName("Mail");
//Retrieve image from the spreadsheet
var retrieveImage = mail.getImages()[0];
var arrayImage = new Array();
var image = {};
arrayImage[0] = retrieveImage.getAs('image/png')
image["image"+0] = arrayImage[0];
//Fonction to send mail
function sendEmailS(){
var message = "Test";
message += "<img src='cid:image" +0+ "'> <br>";
GmailApp.sendEmail("email#email.com", "subject", "",
{
htmlBody: message,
inlineImages: image
}
);
}
I've got the error that getAs is not a function. Could help me or give me any clue to finish my script ?
Issue and workaround:
From your showing script and the error of I've got the error that getAs is not a function., I thought that the reason for your issue is due to that the image cannot be retrieved as a blob from Spreadsheet.
In the current stage, unfortunately, there is no method for directly retrieving the image on Spreadsheet as a blob. So, in this answer, I would like to propose a workaround. In this workaround, a Google Apps Script library is used. This library supports for the processes that the current Google services cannot directly achieve.
Usage:
1. Install Google Apps Script library.
Please install DocsServiceApp of Google Apps Script library. You can see how to install it at here.
2. Modified script.
When your script is modified using this library, it becomes as follows.
function sendEmailS() {
// Drive where is stored the image
const folder = DriveApp.getFolderById("1XXXXXXXXX");
// Retrieve ID file where is stored the image
const file = folder.getFilesByName("file")
const fileIDs = [];
while (file.hasNext()) {
var files = file.next();
fileIDs.push(files.getId());
}
var ssFile = SpreadsheetApp.openById(fileIDs[0]);
SpreadsheetApp.setActiveSpreadsheet(ssFile);
//Spreadsheet
var mail = ssFile.getSheetByName("Mail");
//Retrieve image from the spreadsheet
var retrieveImage = mail.getImages()[0];
var arrayImage = new Array();
var image = {};
const anchor = retrieveImage.getAnchorCell().getA1Notation();
const res = DocsServiceApp.openBySpreadsheetId(fileIDs[0]).getSheetByName("Mail").getImages();
const obj = res.find(({ range: { a1Notation } }) => a1Notation == anchor);
if (!obj) return;
arrayImage[0] = obj.image.blob;
image["image" + 0] = arrayImage[0];
//Fonction to send mail
var message = "Test";
message += "<img src='cid:image" + 0 + "'> <br>";
GmailApp.sendEmail("email#email.com", "subject", "",
{
htmlBody: message,
inlineImages: image
}
);
}
3. Testing.
When this script is run, an image of mail.getImages()[0] is retrieved as a blob. And, an email is sent using the retrieved image blob.
Reference:
DocsServiceApp of Google Apps Script library
Maybe some ideas here for you?....
...this gets image file from G.drive and emails it...
function emailImage(){
fileList = DriveApp.getFilesByName('imageNameInDrive.jpg');
while (fileList.hasNext()) { image = fileList.next().getId(); }
var insertImage = DriveApp.getFileById(image).getBlob();
var message = 'Test<br>';
message += '<img src="cid:insertImage" > <br>';
GmailApp.sendEmail("email#gmail.com", "subject", "",
{
htmlBody: message,
inlineImages: {
insertImage: insertImage
}
}
);
}
In addition to Tanaike's answer, which in my opinion would be a good workaround, there is an open Feature Request for converting Spreadsheet images to BlobSource.
Remember to hit the +1 button to tell Google that you are also interested.
Update OverGridImage to support BlobSource interface

Blob would be exported before changes are made to the files

I wrote a google script to generate resume and cover letter faster. It does the following
use ui.prompt to input content
create a folder and copy docs to the folder
replace keyword to content
convert docs to pdf in the folder
However, somehow the docs would be converted to PDFs before the keywords were replaced.
I have tried below but to no avail:
async awaits to wait for the main function before starting exporting PDFs
use utilities.sleep() to delay the exports
I have the main function and export function below for your information.
function jobHuntAutomation() {
//UI prompts for documents
var ui = DocumentApp.getUi();
var companyName = ui.prompt('Cover Letter', 'Enter Company Name: \n', ui.ButtonSet.OK);
var positionName = ui.prompt('Cover Letter', 'Enter Position Name: \n', ui.ButtonSet.OK);
var hiringManagerName = ui.prompt('Cover Letter', 'Enter Hiring Manager Name: \n', ui.ButtonSet.OK);
//Create some file name strings
var folderName = `${companyName.getResponseText()}_${positionName.getResponseText()}`
var coverLetterName = `${companyName.getResponseText()}_${positionName.getResponseText()}_Coverletter`
var resumeName = `${companyName.getResponseText()}_${positionName.getResponseText()}_Resume`
//Get new folder object and Id
var newFolder = DriveApp.getFolderById(mainFolderId).createFolder(folderName);
var newFolderId = newFolder.getId();
var newFolderUrl = newFolder.getUrl()
//Make a copy
console.log('Making Copies')
DocumentApp.getUi().showModalDialog(modalMessage('Making Copies...'), 'Status');
var coverLetterId = DriveApp.getFileById(coverLetterTemplateId).makeCopy(coverLetterName, newFolder).getId();
var resumeId = DriveApp.getFileById(resumeTemplateId).makeCopy(resumeName, newFolder).getId();
//Status
DocumentApp.getUi().showModalDialog(modalMessage('Updating Content...'), 'Status');
//Get the coverLetter document body as a variable
var coverLetterBody = DocumentApp.openById(coverLetterId).getBody();
//Get the resume document body as a variable
var resumeBody = DocumentApp.openById(resumeId).getBody();
//Update Content
doc.replaceText(keyword, input.getResponseText())
.
.
.
//you get the idea
//export PDFs
convertToPdf(resumeId, newFolder)
convertToPdf(coverLetterId, newFolder)
DocumentApp.getUi().showModalDialog(folderLink(newFolderUrl), 'Link');
}
function convertToPdf(fileId, dest) {
doc = DriveApp.getFileById(fileId);
docblob = doc.getAs('application/pdf');
console.log(`Converting ${doc.getName()}...`)
/* Add the PDF extension */
docblob.setName(doc.getName() + ".pdf");
// add file to the dest Folder
dest.createFile(docblob);
}
It would be much appreciated if someone knows a solution to export PDFs AFTER the keywords are replaced. TIA
I figured it out. the docs need to be saveAndClose() before exporting so the changes would be flushed

Google Sheet to PDF Get Only Active Sheet/Tab

This script converts pdf in inside the folder which is fine.
There are three tabs on this sheet when the function run.
Merge all the tab in pdf and save in the drive folder with active sheet tab name
var pdfName = "Invoice " + sheetName.getRange("d6").getValue();
What I want
When I run the script only active tab/sheet convert in pdf. and not marge all tab in pdf.
function PDF() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet();
var folderID = "1_gA4D7ybJ60dfgsdfgdsfInqVoo9D769cqmAnJI7g7";
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1jBl_82etnHsdfgsdfgsdfgsdgcjaCpcTG6VvhKYNNrQQXJMUUOQkFGfORY/edit#gid=1167579479');
var pdfName = "Invoice " + sheetName.getRange("d6").getValue();
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var folder = DriveApp.getFolderById(folderID);
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))
//delete redundant sheets
var sheets = destSpreadsheet.getSheets();
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
Explanation:
Your current solution is not the proper way to create a pdf of a sheet. You need to use getOAuthToken() and Class UrlFetchApp.
Also I improved your script in many different ways. You are defining variables you are not using anywhere. And also you don't need to create a copy of the spreadsheet file and then delete it. You can simply create a pdf file of your source spreadsheet directly.
The following script will create a pdf file of the active sheet. Keep in mind that the active sheet is the sheet selected in the UI.
Solution:
function PDF(){
var sss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getActiveSheet();
var ssID = sss.getId();
var shID = sheet.getSheetId().toString();
var folderID = "1_gA4D7ybJ60dfgsdfgdsfInqVoo9D769cqmAnJI7g7";
var folder = DriveApp.getFolderById(folderID);
var pdfName = "Invoice " + sheet.getRange("d6").getValue();
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=pdf&id="+ssID+"&gid="+shID;
var result = UrlFetchApp.fetch(url , requestData);
var newFile = folder.createFile(result.getBlob()).setName(pdfName)
}

email Google Doc as PDF attachment

abc#example.comAfter struggling for a while with this I am calling for help from the crowd.
I am trying to attach 2 Google Docs to an email as PDFs. I see many examples in regard to Google Sheets and have successfully been able to email copies of sheets as PDF, but I have not been able to port this over to Docs.
In multiple different scenarios, the PDF attachments are either a copy of my original template Doc or an image capture of "One Account. All of Google" sign in page. When I look at the links that are generated (Logger.log) and use them, a copy of the correct Doc is downloaded.
Below is an example of my scenario in which I am trying to create the email attachments. See function emailDocAsPDF() towards the bottom
Thanks in advance for any guidance on this issue.
function myFunctionUpdated() {
var testTemplateId = searchDriveFile('Test Template');
Logger.log('test template id = ' + testTemplateId);
var fileName = 'Copy of Test Template'
Logger.log(fileName);
DriveApp.getFileById(testTemplateId).makeCopy(fileName);
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var range = ss.getRange(1, 1, 3, 2).getValues();
var copyNewTemplateId = searchDriveFile(fileName);
var copyTemplate = DocumentApp.openById(copyNewTemplateId);
var copyTemplateBody = copyTemplate.getBody().editAsText();
for (i=0; i<range.length; i++) {
copyTemplateBody.replaceText(range[i][0], range[i][1]);
}
copyTemplate.saveAndClose();
emailDocAsPDF(fileName)
}
// Searched Google Drive for a file name and returns the file ID.
function searchDriveFile(fileName) {
var files = DriveApp.searchFiles(
'title = "'+ fileName +'"');
while (files.hasNext()) {
var file = files.next();
var id = file.getId();
return id;
}
}
// Send document in an email as PDF
function emailDocAsPDF(fileName) {
var staticDoc = 'FILE-ID';
var attachmentDoc = UrlFetchApp.fetch("https://docs.google.com/document/d/" + copyTemplateId + "/export?format=pdf");
Logger.log("https://docs.google.com/document/d/" + copyTemplateId + "/export?format=pdf");
var attachmentStaticDoc = UrlFetchApp.fetch("https://docs.google.com/document/d/" + staticDoc + "/export?format=pdf");
Logger.log("https://docs.google.com/document/d/" + staticDoc + "/export?format=pdf");
var fileBlob = [];
fileBlob[0] = attachmentDoc.getBlob().getAs('application/pdf');
fileBlob[1] = attachmentStaticDoc.getBlob().getAs('application/pdf');
var body = "Bird is the WORD!! <br>" +
"<a href='http://www.example.com'>Visit Example</a>";
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail("email#example.com", "Test Documents Email", body, {
htmlBody: body,
attachments:[fileBlob[0],fileBlob[1]]
});
}
EDIT -- Successful Updates with code provided by Sandwich.
// Send document in an email as PDF
function emailDocAsPDF(fileName) {
var staticDoc = 'FILE-ID';
var copyTemplateId = searchDriveFile(fileName);
var blobs = [];
var doc = DriveApp.getFileById(copyTemplateId);
blobs[0] = doc.getBlob().getAs('application/pdf').setName('MyAttachment1.pdf');
var doc = DriveApp.getFileById(staticDoc);
blobs[1] = doc.getBlob().getAs('application/pdf').setName('MyAttachment2.pdf');
var zipBlob = Utilities.zip(blobs).setName('Documents.zip');
var recipient = 'abc#example.com';
var subject = 'Test Email';
var body = 'Bird is the WORD';
MailApp.sendEmail(recipient, subject, body, {attachments: [zipBlob]});
}
To attach any kind of document as a PDF, call getBlob on the file, specify content type as with .getAs('application/pdf') and optionally set a name with setName. That's all:
var doc = DriveApp.getFileById('ID_HERE');
var blob = doc.getBlob().getAs('application/pdf').setName('MyAttachment.pdf');
var recipient = 'user#example.com';
var subject = 'Email subject';
var body = 'Text here';
MailApp.sendEmail(recipient, subject, body, {attachments: [blob]});
You were trying to use "export as PDF via URL query", which is a poorly documented feature that is sometimes useful for Sheets (setting the boundaries of exported region), but is unnecessary for Docs, if it even exists for them. The above method should work for any kind of content stored in Google Drive.
By the way, it is preferable to use MailApp instead of GmailApp when sending email, because it keeps the level of authorization to what you need: sending emails. With GmailApp, the script is also granted permission to access and delete all of your existing emails, which is unadvisable for scripts composed by trial, error, and copying code from the Internet.

Categories