So I wrote a bot with GAS for Slack and everything works fine. Now I made a copy of the bot and it starts giving out weird error "We're sorry, a server error occurred. Please wait a bit and try again." when I try to access a folder in Google drive. Since the code is exactly the same, I have no idea what the problem is.
//Create Pdf
function exportCurrentSheetAsPDF_() {
var ss = SpreadsheetApp.openById(MAIN_SPREADSHEET_ID);
var currentSheet = ss.getSheetByName(ASAKAWA_HOLIDAY_SHEET);
var blob = getAsBlob(ss.getUrl(), currentSheet);
var date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'YYYYMMddhhmmss');
var pdfName = mergePdfName("休日", date, "浅川Only", "H");
//Export pdf to google drive 008.2 Entertainment folder
exportPdfToDrive(blob, pdfName);
return pdfName;
}
function exportPdfToDrive(blob, fileName) {
blob = blob.setName(fileName);
var folder = DriveApp.getFolderById(GOOGLE_DRIVE_FOLDER_ID); <--- This gives error
var pdfFile = folder.createFile(blob);
}
//Get spreadsheet as blob
function getAsBlob(url, sheet, range) {
var exportUrl = url.replace(/\/edit.*$/, '')
+ "/export?exportFormat=pdf"
+ "&format=pdf"
+ "&size=A4"
+ "&portrait=true"
+ "&fitw=true"
+ "&sheetnames=false"
+ "&printtitle=false"
+ "&pagenum=false"
+ "&gridlines=false"
+ "&fzr=FALSE"
+ "&gid=" + sheet.getSheetId();
var response = UrlFetchApp.fetch(exportUrl, {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
})
return response.getBlob();
}
Related
Software: Google Sheets & Google App Script
Hi all,
I have been sending test emails to myself with attachments from my google sheet. They have been going great. Then I hop on one day and start receiving authentication errors. I have tried several different fixes but I'm still stuck. I'm not sure why it broke if I didn't change anything. Anyways, I'm changing stuff now to try and fix it.
It will let me send plain emails, but when I try to attach pdf's or xsls files, it fails. This was working great until it stopped working... Setting 'muteHttpExceptions' : true, allows the email to send, but the attachments are empty / corrupt.
Do you know of a better way to send specific sheets via email as pdf's or perhaps a way to fix this?
Code:
function SampleEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetName = ss.getName();
var email = "test#gmail.com";
var subject = "Important Info!";
var body = "Test email.";
var url = "https://docs.google.com/spreadsheets/d/" + ssID + "/export?" + "format=pdf" + "&gid=" + sheetgId + "&portrait=true" + "&exportFormat=pdf";
var token = ScriptApp.getOAuthToken();
var result = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
},
'muteHttpExceptions': false
});
var contents = result.getContent();
GmailApp.sendEmail(email, subject, body, { attachments: [{ fileName: sheetName + ".pdf", content: contents, mimeType: "application//pdf" }] });
}
Error message:
5:58:33 AM Error
Exception: Request failed for https://docs.google.com returned code 401. Truncated server response: <HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
(use muteHttpExceptions option to examine full response)
SampleEmail # code.gs:108
SOLUTION: (Thank you #Amit_Singh for the advice.)
Try running this function to send your google sheet as a pdf to your google drive. This cleared the cache or something with the getOAuthToken() for me and allowed the original script to authenticate and send email attachments properly. Here is the function:
function convertSheetToPDF() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetId = sheetgId; // "2SqIXLiic6-gjI2KwQ6OIgb-erbl3xqzohRgE06bfj2c";
var spreadsheetName = "My Spreadsheet";
var destination = DriveApp.createFolder('new folder');
//var destination = DriveApp.getFolderById("1vFL98cgKdMHLNLSc542pUt4FMRTthUvL");
//var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + sheetId + "&exportFormat=xlsx";
var url = "https://docs.google.com/spreadsheets/d/" + ssID + "/export?" + "format=pdf" + "&gid=" + sheetgId + "&portrait=true" + "&exportFormat=pdf";
var params = {
method: "get",
headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() },
muteHttpExceptions: false
};
var blob = UrlFetchApp.fetch(url, params).getBlob();
blob.setName(spreadsheetName + ".xlsx");
destination.createFile(blob);
}
I am currently new to the google sheet script. I'm doing a simple report generator in google sheet using script. I already have a script that saves a generated pdf file to the google drive. In my google sheet there is a cell referenced to the main data source with dropdown data validation selecting the email of the person and will generate the other details (it a reference also based from that email in the same sheet). what I want is, when I run the script to save pdf file, it should automatically generate pdf file for each item in the dropdown validation list. Is this possible? Anyone who know this please.
this is my code that generate pdf file to the drive (i got this also from the net and made some changes)... thank you so much in advance.
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet2 = ss.getSheetByName('ID');
var gdid1 = sheet2.getRange('B1').getValue();
var gdid2 = sheet2.getRange('B4').getValue();
function onOpen() {
var ui = SpreadsheetApp.getUi()
ui.createMenu('ExportGDrive')
.addItem('Export BasicED', 'exportBasicED')
.addItem('Export College', 'exportCollege')
.addToUi()
}
function _exportBasic(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid1)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function _exportCollege(blob, fileName, spreadsheet) {
blob = blob.setName(fileName)
var folder = DriveApp.getFolderById(gdid2)
var pdfFile = folder.createFile(blob)
// Display a modal dialog box with custom HtmlService content.
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
function exportAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var blob = _getAsBlob(spreadsheet.getUrl())
_exportBlob(blob, spreadsheet.getName(), spreadsheet)
}
function _getAsBlob(url, sheet, range) {
var rangeParam = ''
var sheetParam = ''
if (range) {
rangeParam =
'&r1=' + (range.getRow() - 1)
+ '&r2=' + range.getLastRow()
+ '&c1=' + (range.getColumn() - 1)
+ '&c2=' + range.getLastColumn()
}
if (sheet) {
sheetParam = '&gid=' + sheet.getSheetId()
}
// A credit to https://gist.github.com/Spencer-Easton/78f9867a691e549c9c70
// these parameters are reverse-engineered (not officially documented by Google)
// they may break overtime.
var exportUrl = url.replace(/\/edit.*$/, '')
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=LETTER'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.75'
+ '&bottom_margin=0.75'
+ '&left_margin=0.7'
+ '&right_margin=0.7'
+ '&sheetnames=false&printtitle=false'
+ '&pagenum=UNDEFINED' // change it to CENTER to print page numbers
+ '&gridlines=FALSE'
+ '&fzr=FALSE'
+ sheetParam
+ rangeParam
Logger.log('exportUrl=' + exportUrl)
var response
var i = 0
for (; i < 5; i += 1) {
response = UrlFetchApp.fetch(exportUrl, {
muteHttpExceptions: true,
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
},
})
if (response.getResponseCode() === 429) {
// printing too fast, retrying
Utilities.sleep(3000)
} else {
break
}
}
if (i === 5) {
throw new Error('Printing failed. Too many sheets to print.')
}
return response.getBlob()
}
function exportCurrentSheetAsPDF() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var currentSheet = SpreadsheetApp.getActiveSheet()
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), currentSheet)
_exportBlob(blob, SpreadsheetApp.getActiveSheet().getRange('B3').getValue(), spreadsheet)
}
function exportBasicED() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-Basic Ed');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportBasic(blob, name, spreadsheet)
}
function exportCollege() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet1 = spreadsheet.getSheetByName('Generate-College');
var name = sheet1.getRange('B3').getValue();
// Change the Cell for the name of the file (example: B3 for current sheet)
var blob = _getAsBlob(spreadsheet.getUrl(), sheet1)
_exportCollege(blob, name, spreadsheet)
}
Try
function nextItem() {
var sh = SpreadsheetApp.getActive();
var data = sh.getRange('myValidationList').getValues();
for (var i = 0; i < data.length; i++) {
sh.getRange('A2').setValue(data[i][0]);
SpreadsheetApp.flush();
// here you can call the script to send pdf
Utilities.sleep(1000);
}
};
assuming that myValidationList is the list of valid data, avd A2 the cell in wich the validation applies.
This question already has answers here:
Export a range as a PDF in Google Apps Script
(3 answers)
Closed 6 months ago.
I'm trying to take a screenshot of a range of cells in Google spreadsheet every time a value changes in that range and save the screenshot in a URL or in my drive as .jpg, .png or pdf
I was able to find something similar for taking screenshots of charts but wasn't able to modify the script successfully for this case, has anyone done something similar
Take this as a reference, modify if needed:
Code:
function exportPdf(e) {
var spreadsheet = e.source;
var sheet = spreadsheet.getActiveSheet();
var range = e.range;
// sample dimension to be checked is B2:E5
var checkDimension = {
startingRow: 2,
startingColumn: 2,
endingRow: 5,
endingColumn: 5
};
// range should be within checkDimension and Sheet1
if(sheet.getSheetName() == 'Sheet1' &&
range.getRow() >= checkDimension.startingRow &&
range.getLastRow() <= checkDimension.endingRow &&
range.getColumn() >= checkDimension.startingColumn &&
range.getLastColumn() <= checkDimension.endingColumn) {
var spreadsheetId = spreadsheet.getId();
var sheetId = sheet.getSheetId();
var exportRange = "B2:E5";
var urlString = 'export?exportFormat=pdf&format=pdf' +
'&gid=' + sheetId + '&id=' + spreadsheetId +
'&range=' + exportRange +
'&size=A4' + // paper size
'&portrait=true'; // orientation, false for landscape
// See https://webapps.stackexchange.com/questions/130654/all-google-docs-url-parameters-functions-commands for more url parameters
var exportUrl = spreadsheet.getUrl().replace(/edit.*$/, urlString);
var options = {
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
},
muteHttpExceptions: true
}
var response = UrlFetchApp.fetch(exportUrl, options);
if (response.getResponseCode() !== 200) {
Logger.log("Error exporting Sheet to PDF! Response Code: " + response.getResponseCode());
return;
}
var blob = response.getBlob();
var timestamp = new Date().toISOString();
// set name to spreadsheet_sheet_range_timestamp.pdf
blob.setName(spreadsheet.getName() + '_' + sheet.getSheetName() + '_' + exportRange + '_' + timestamp + '.pdf');
var folderId = 'enter your folder ID here';
// Create the PDF file in the specific folder
DriveApp.getFolderById(folderId).createFile(blob);
}
}
Note:
For more url parameters, see reference below.
This needs to be an installable trigger, not a simple one.
Output:
References:
Url parameters
Alan Well's answer
I have a script that exports a sheet to a pdf file when function is run. This works fine when I run it from the account in which the script was created but when a shared user runs it returns the following error: Exception: Cannot retrieve the next object: iterator has reached the end. Line 9
The code is as below, i'm not sure what actually is wrong with this so would be glad of help:
function CreatePDF() {
var sourceSpreadsheet = SpreadsheetApp.getActive();
var ui = SpreadsheetApp.getUi();
var sheetName = "Stock List";
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var sh = sourceSpreadsheet.getSheetByName("Product List");
var driveFile = DriveApp.getFileById("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
var parentFolder = driveFile.getParents();
var folderName =parentFolder.next().getId();
var folder = DriveApp.getFolderById(folderName);
var numf = sourceSpreadsheet.getRangeByName("exportrange").getValue();
var anof = numf.split("/",2);
var pdfRange = sh.getRange("F1");
var pdfName = pdfRange.getValue();
// export url
var url = 'https://docs.google.com/spreadsheets/d/'+sourceSpreadsheet.getId()+'/export?exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=A4'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.00'
+ '&bottom_margin=0.00'
+ '&left_margin=0.00'
+ '&right_margin=0.00'
+ '&sheetnames=false&printtitle=false'
+ '&pagenumbers=false&gridlines=false'
+ '&fzr=false'
+ '&gid='+sourceSheet.getSheetId();
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var theBlob = response.getBlob().setName(pdfName+'.pdf');
var files = folder.getFilesByName(pdfName);
while (files.hasNext())
{
files.next().setTrashed(true);
}
}
I'm trying to make this script to work on google sheets app so it sends a pdf copy to my email when I type Send in cell L6
the code work perfect on computer but not on ipads , anyway to do this from app ?
function onEdit2(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var r = sheet.getRange('L6').getValue();
if (r == "Send") {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetName = ss.getName();
var token = ScriptApp.getOAuthToken();
var email = "EMAIL HERE";
var subject = "Daily report ";
var body = "Please find the attached Daily report";
var url = "https://docs.google.com/spreadsheets/d/"+ssID+"/export?"
+ "format=xlsx" + "&gid="+sheetgId+ "&portrait=true" +
"&exportFormat=pdf";
var result = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var contents = result.getContent();
MailApp.sendEmail(email,subject ,body, {
attachments: [{
fileName: sheetName + ".pdf",
content: contents,
mimeType: "application//pdf"
}]
})
}
}
The way it worked for me by " installed Trigger "
from the script editor : Edit - current project Triggers
I added new trigger that will run the code below based on " On edit " and voila it worked , from sheets app if I typed " Send " in Cell L6 it will send a PDF copy of the active sheet to the email listed in the code.
function onEdit2(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var r = sheet.getRange('L6').getValue();
if (r == "Send") {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetName = ss.getName();
var token = ScriptApp.getOAuthToken();
var email = "EMAIL HERE";
var subject = "Daily report ";
var body = "Please find the attached Daily report";
var url = "https://docs.google.com/spreadsheets/d/"+ssID+"/export?"
+ "format=xlsx" + "&gid="+sheetgId+ "&portrait=true" +
"&exportFormat=pdf";
var result = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var contents = result.getContent();
MailApp.sendEmail(email,subject ,body, {
attachments: [{
fileName: sheetName + ".pdf",
content: contents,
mimeType: "application//pdf"
}]
})
}
}
Create a Google Script in the very same Spreadsheet or in another one (Tools / Script editor), add the script you already have, grant the authorizations required, and trigger it with a simple form (Tools / Create a form) (trigger → Edit / Current project's triggers). The long URL to view the form can be easily opened by means of a URL shortener or something by the sort. Forms work in cell phones too and without need to sign in to your account. With this method you can even add a useless conditional password to run the script.
function createPDF(e) {
var input = e.values[1];
if (input == 'my_password'){
// your scripts to create and send the PDF goes here
}
}
It's a simplistic solution, but it works.