Google Sheets, how to send email with attachment to every customer - google-apps-script

I have a sheet, with some tabs, in one tab i make statement for my clients, there i select a customer in B2 and using a query formula i get the desired data, after that i have a script to first hide blank rows and then send that email with the pdf as attachment, and i do thins only when need send that email.
this is my script:
function HideEdoCta() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Edo Cta');
var lastRow = sheet.getLastRow();
var range = sheet.getRange(1, 4, lastRow, 1);
var data = range.getValues();
//Rows
for (var i = 0; i < data.length; i++) {
if (data[i][0] == 1) {
sheet.hideRows(i + 1)
}
}
sheet.hideColumns(4, 1)
}
function UnHideEdoCta() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Edo Cta');
sheet.unhideRow(sheet.getDataRange());
}
function MailEdoCta(email, subject, body, sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Edo Cta');
var valueToCheck = sheet.getRange('C1').getValue();
if (valueToCheck == true && casa != '') {
HideEdoCta()
SpreadsheetApp.flush()
var email = sheet.getRange('D1').getValue(); // Enter the required email address here
var casa = sheet.getRange('B2').getValue();
var subject = 'Estado de Cuenta Sky';
var body =
"Hola, <strong>" + casa + "</strong><br><br>" +
"xxx.<br>" +
"-- <br>" +
"<strong>xxx</strong><br>"
;
// Base URL
var url = "https://docs.google.com/spreadsheets/d/SS_ID/export?".replace("SS_ID", ss.getId());
var url_ext = 'exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=letter' // paper size legal / letter / A4
+ '&portrait=true' // orientation, false for landscape
+ '&scale=1' // 1= Normal 100% / 2= Fit to width / 3= Fit to height / 4= Fit to Page
+ '&fitw=true&source=labnol' // fit to page width, false for actual size
+ '&sheetnames=false&printtitle=false' // hide optional headers and footers
+ '&pagenumbers=true&gridlines=false' // hide page numbers and gridlines
+ '&fzr=false' // do not repeat row headers (frozen rows) on each page
+ '&gid='; // the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext + sheet.getSheetId(), {
headers: {
'Authorization': 'Bearer ' + token
}
}).getBlob().setName(sheet.getName() + ".pdf");
// Uncomment the line below to save the PDF to the root of your drive.
// var newFile = DriveApp.createFile(response).setName(sheet.getName() + ".pdf")
GmailApp.sendEmail(email, subject, "",
{ name: 'xxx', htmlBody: body, attachments: [response] }
);
SpreadsheetApp.flush()
UnHideEdoCta()
sheet.getRange('C1').setValue(false)
sheet.getRange('B2').clearContent()
}
else {
sheet.getRange('C1').setValue(false)
}
}
in this script i have a validation that if there is a customer selected in B2 and C1 is true, send the email, because the trigger is set to run every minute.
now what i need is send the same email, every 5th of the month to all my customers automatically (i only have 24 customers)
how can i make this possible without selecting one by one ?
any help please ?
here is a sample sheet with sample data

Try this
function mailing() {
var doc = SpreadsheetApp.getActive();
var sh = SpreadsheetApp.getActiveSheet();
var data = doc.getRange('listOfCustomers').getValues();
for (var i = 0; i < data.length; i++) {
if (data[i][1]) {
sh.getRange('B2').setValue(data[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(1000);
}
}
};
a copy of your spreadsheet would have been appreciated for testing.

In response to your comment from above:
This is the basic script that reads the information spreadsheet and calls the email function along with an object that identifies the template and other important information.
function sendEmails() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Emails');
const [hA, ...dt] = sh.getDataRange().getValues();
const vs = dt.filter(r => r[0] && r[1] && r[2] && r[3] && r[4] == 'Send' && r[5]);
const idx = {};
hA.forEach((h, i) => { idx[h] = i; });
vs.forEach(function (r) {
let obj = { index: idx, row: r }
this[r[5]](obj);//This executes the function named in r[5] and passes it obj
});
}
This is one of the functions that sends emails or creates a draft:
function sendEmails103(obj) {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('libImages');
const [hA, ...dt] = sh.getDataRange().getValues();
let idx = {};
hA.forEach((h, i) => idx[h] = i);
let imgObj = {};
vs = dt.filter(r => r[idx['filename']] == obj.row[obj.index['htmlFile']])
vs.forEach((r, i) => {
let params = { muteHttpExceptions: true, headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };
let aurl = "https://photoslibrary.googleapis.com/v1/mediaItems/" + r[idx['mediaItemId']]
let resp = JSON.parse(UrlFetchApp.fetch(aurl, params).getContentText());
let burl = `${resp.baseUrl}=w${r[idx['maxwidth']]}-h${r[idx['maxheight']]}`
imgObj[r[idx['Key']]] = UrlFetchApp.fetch(burl).getBlob();
});
let htmlTemplate = HtmlService.createTemplateFromFile(obj.row[obj.index['htmlFile']]);
let html = htmlTemplate.evaluate().getContent();
if (html) {
if (obj.row[obj.index['operation']] == 'Create Draft') {
GmailApp.createDraft(obj.row[obj.index['Recipients']], obj.row[obj.index['Subject']], '', { htmlBody: html, inlineImages: imgObj, replyTo: obj.row[obj.index['replyTo']] });
} else {
GmailApp.sendEmail(obj.row[obj.index['Recipients']],obj.row[obj.index['Subject']],'',{htmlBody:html,inlineImages:imgObj,replyTo: obj.row[obj.index['replyTo']]});
}
}
}
This probably not for everyone, but I like having more room to customize my letters and having been a web developer for a long time I'm quite comfortable composing letters in html which is probably not true of everyone.

Related

Script to email inactive sheets of a sheet workbook

I have a script to send the active sheet of a workbook sheet in excel to a mailing list
function SendaMailOK(){
var DateName1 = SpreadsheetApp.getActiveSheet( ).getRange("B4").getValue();
var newdate = new Date(SpreadsheetApp.getActiveSheet( ).getRange("B4").getValue());
var d = Utilities.formatDate(newdate, Session.getScriptTimeZone(), "dd-MM-yyyy");
var f = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Adresses Mail');
//Send active sheet as email attachment
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ssID = ss.getId();
var sheetgId = ss.getActiveSheet().getSheetId();
var sheetName = ss.getSheetName();
var token = ScriptApp.getOAuthToken();
var url = "https://docs.google.com/spreadsheets/d/"+ssID+"/export?" + "format=xlsx" + "&gid="+sheetgId+ "&portrait=false" + "&exportFormat=xlsx";
var result = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var contents = result.getContent();
var subject = "Rapport du " + d;
var body = "Bonjour, \n\nCi-joint le rapport, \n \nCdlt";
var n=f.getLastRow();
for (var i = 1; i < n+1 ; i++ ) {
var emailAddress = f.getRange(i,1).getValue();
MailApp.sendEmail(emailAddress,subject ,body, {attachments:[{fileName:sheetName+".xlsx", content:contents, mimeType:"application//xlsx"}]});
}
};
After modifying my file, I need to send 2 sheets of the workbook as attachments and no longer the active sheet.
Problem, I can't adapt the script.
Thanks for your help.
Sending multiple files
I played around with your code a little and found a way to do it taking from some of the work that Tanaike has done in this area. If you don't know where to look for stuff like this then always check out Tanaikes work because I've always found it to be well done.
function SendaMailOK() {
const ss = SpreadsheetApp.getActive();
let esh = ss.getSheetByName('Sheet3');
let ssID = ss.getId();
let token = ScriptApp.getOAuthToken();
let emails = esh.getRange(1, 1, esh.getLastRow()).getValues().flat().join(',');
const names = ['Sheet0', 'Sheet1'];
const shts = ss.getSheets().filter(sh => ~names.indexOf(sh.getName()));
let files = [];
shts.forEach((sh, i) => {
let d = Utilities.formatDate(new Date(sh.getRange("B4").getValue()), Session.getScriptTimeZone(), "dd-MM-yyyy");
let sheetgId = sh.getSheetId();
let url = "https://docs.google.com/spreadsheets/d/" + ssID + "/export?" + "format=xlsx" + "&gid=" + sheetgId + "&portrait=false" + "&exportFormat=xlsx";
let contents = UrlFetchApp.fetch(url, { headers: { 'Authorization': 'Bearer ' + token } }).getBlob().setName(`${sh.getName()}.xlsx`);
files.push(contents);
});
var subject = `Files: ${names.join(', ')}`;
var body = "Hello, here are your files";
MailApp.sendEmail(emails, subject, body, { attachments: files });
}

Is there a way to auto next ( to the next item) the in cell data validation dropdown list after running a script in google sheet?

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.

Export PDf while iterating over a set of values

I'm fairly new to the world of aumating sheets with scripts and ma still firmly in the 'cobble other peoples code together' phase of writing scripts.
I have a schedule in Google Sheets that display's different department overviews based on the contents of a cell ('B1'). I'm attempting to iterate a list of values through that cell and in each instance export the resulting sheet to pdf.
So far I've got it working, my next hurdle is getting it to export the pdf in landscape rather than portrait. I can see implementations using url export but I'm not confident enough (read keep breaking everything) to implement that in to the script below.
Any help greatly appreciated!
function PrintPDF(){
var df = DriveApp.getFolderById("folderID");
var arr = new Array();
var files = df.getFiles();
while( files.hasNext() ) {
var f = files.next();
arr.push( [ [ f.getId() ] , [ f.getLastUpdated() ] ] );
}
arr.sort( sortFunction );
function sortFunction( a , b ) {
var aDate = new Date(a[1]);
var bDate = new Date(b[1]);
if ( aDate === bDate ) return 0;
else if ( aDate < bDate ) return 1;
else return -1;
};
for( var i=0 ; i<arr.length ; i++ )
DriveApp.getFileById( arr[i][0] ).setTrashed( true );
//Create array of show codes
var Dss = SpreadsheetApp.getActive().getSheetByName('Value Lists')
var Tss = SpreadsheetApp.getActive().getSheetByName('PrintSheet')
var Shows = Dss.getRange('K3:K11').getValues()
var Count = Shows.length
var Code = Tss.getRange('B1')
Logger.log(Count)
Logger.log(Shows)
for (i=0;i<Count;i++){
Code.setValue(Shows[i])
HideBlankRows ()
const folderName = `foldername`;
var ss =SpreadsheetApp.getActiveSpreadsheet()
var name = "Department - "+ss.getRange('B1').getValue()
Logger.log(name)
DriveApp.getFoldersByName(folderName)
.next()
.createFile(ss
.getBlob()
.getAs(`application/pdf`)
.setName(name)
);
}
Code.setValue('')
}
function HideBlankRows() {
var ss = SpreadsheetApp.getActive();
var sheets = ss.getSheets(); // array of all sheet objects in ss
var numSheets = ss.getNumSheets(); // count of sheets
for(sheet in sheets) {
if(sheets[sheet].getSheetName() == "AA") continue;
//show all the rows
sheets[sheet].showRows(1, sheets[sheet].getMaxRows());
//get data from column A
var data = sheets[sheet].getRange('A:A').getValues();
Logger.log(data)
//iterate over all rows
for(var i=0; i< data.length; i++){
//compare column, if no, then hide row
if(data[i][0] == 'Yes'){
sheets[sheet].hideRows(i+1);
}
}
}
}
Your code looks a bit cryptic to me. I don't understand why do you need the arr array if you nowhere use it. Etc.
But whatever. Suppose the code works fine and all you need is to save a PDF file with landscape orientation. In this case you need to replace these lines in your code:
DriveApp.getFoldersByName(folderName)
.next()
.createFile(ss
.getBlob()
.getAs(`application/pdf`)
.setName(name)
);
With this:
savePDFs(name);
And add at the end of your script the function savePDFs():
function savePDFs(name) {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var url = ss.getUrl();
//remove the trailing 'edit' from the url
url = url.replace(/edit$/, '');
//additional parameters for exporting the sheet as a pdf
var url_ext = 'export?exportFormat=pdf&format=pdf' + //export as pdf
//below parameters are optional...
'&size=a4' + //paper size
'&portrait=false' + //orientation, false for landscape, true for portrait
'&fitw=true' + //fit to width, false for actual size
'&sheetnames=false&printtitle=false&pagenumbers=false' + //hide optional headers and footers
'&gridlines=false' + //hide gridlines
'&fzr=false' + //do not repeat row headers (frozen rows) on each page
'&gid=' + sheet.getSheetId(); //the sheet's Id
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url + url_ext, {
headers: { 'Authorization': 'Bearer ' + token }
});
var blob = response.getBlob().setName(name + '.pdf');
DriveApp.createFile(blob);
}
This function was taken from here: Change document orientation when exporting to PDF

Trigger based email send on google sheets giving some random results i dont understand

I have been trying to make a script that will send email of a range of cells over email. While the sending email part works perfectly, when i add time based trigger to it, its sending out a random email i dont understand.
I am trying to send out a range of cells in my sheet that gets updated live to my boss automatically at 9:30Am everyday.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getDataRange();
var recipient = 'aaaabalamurali1996#gmail.com'
var subject = 'NRV Tracker'
var date = Utilities.formatDate(new Date(), "GMT+1", "dd/MM/yyyy")
var schedRange = sheet.getRange("A1:Y6");
//var schedRange = sheet.getRange(Col == 3 && compare == date);
var body = '<div style="text-align:center;display: inline-block;font-family: arial,sans,sans-serif">'
body += '<H1>'+ 'NRV Tracker ' +'</H1>';
body += '<H2>'
body += getHtmlTable(schedRange);//change this line
body += '</div>';
debugger;
recipient = 'abc#abc.com'; // For debugging, send only to self
GmailApp.sendEmail(recipient, subject, "Requires HTML", {htmlBody:body})
var ts = ss.getSheetByName("D-1 Day");
var srange = sheet.getRange("A1:Y6");
var trange = ts.getRange("A1:Y6");
srange.copyTo(trange, {contentsOnly: true});
}
function getHtmlTable(range){
var ss = range.getSheet().getParent();
var sheet = range.getSheet();
startRow = range.getRow();
startCol = range.getColumn();
lastRow = range.getLastRow();
lastCol = range.getLastColumn();
// Read table contents
var data = range.getValues();
// Get css style attributes from range
var fontColors = range.getFontColors();
var backgrounds = range.getBackgrounds();
var fontFamilies = range.getFontFamilies();
var fontSizes = range.getFontSizes();
var fontLines = range.getFontLines();
var fontWeights = range.getFontWeights();
var horizontalAlignments = range.getHorizontalAlignments();
var verticalAlignments = range.getVerticalAlignments();
var colWidths = [];
for (var col=startCol; col<=lastCol; col++) {
colWidths.push(sheet.getColumnWidth(col));
}
var rowHeights = [];
for (var row=startRow; row<=lastRow; row++) {
rowHeights.push(sheet.getRowHeight(row));
}
var tableFormat = 'style="font-size: 10px; border:1px solid black;border-collapse:collapse;text-align:center" border = 1 cellpadding = 1';
var html = ['<table '+tableFormat+'>'];
// Column widths appear outside of table rows
for (col=0;col<colWidths.length;col++) {
html.push('<col width="'+colWidths[col]+'">')
}
for (row=0;row<data.length;row++) {
html.push('<tr height="'+rowHeights[row]+'">');
for (col=0;col<data[row].length;col++) {
// Get formatted data
var cellText = data[row][col];
if (cellText instanceof Date) {
cellText = Utilities.formatDate(
cellText,
ss.getSpreadsheetTimeZone(),
'M/d');
}
var style = 'style="'
+ 'color: ' + fontColors[row][col]+'; '
+ 'font-family: ' + fontFamilies[row][col]+'; '
+ 'font-size: ' + fontSizes[row][col]+'; '
+ 'font-weight: ' + fontWeights[row][col]+'; '
+ 'background-color: ' + backgrounds[row][col]+'; '
+ 'text-align: ' + horizontalAlignments[row][col]+'; '
+ 'vertical-align: ' + verticalAlignments[row][col]+'; '
+'"';
html.push('<td ' + style + '>'
+cellText
+'</td>');
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
}
When i use the trigger i am getting this email.
enter image description here
Try referencing the range of cells that you wish to send to a new sheet and use the code below to send that sheet as a PDF. It is very easy to implement.
// Generate a PDF file from a Google spreadsheet and send it to a specified email address
function emailSpreadsheetAsPDF() {
const sheetToPrint = "SPREADSHEET NAME"; // name of the sheet to print
const ss = SpreadsheetApp.getActiveSpreadsheet(); // the sheets to use
const email = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('SHEET NAME').getRange('E3').getValue().toString(); // grab the email address from the specified cell
const subject = `SUBJECT - ${ss.getName()}`; // the subject of the email
const body = "BODY"; // body of the email
const shID = ss.getSheetByName(sheetToPrint).getSheetId(); // the ID of the sheet
const url = 'https://docs.google.com/spreadsheets/d/SS_ID/export?'.replace('SS_ID', ss.getId()); // url of the spreadsheet
const exportOptions =
'exportFormat=pdf&format=pdf' + // export as pdf / csv / xls / xlsx
'&size=A4'+ // size of the PDF (legal / A4 / letter)
'&portrait=true'+ // orientation of the PDF (false for landscape)
'&fitw=true'+ // fit to page width (false for actual size)
'&sheetnames=false&printtitle=false'+ // hide optional headers and footers
'&pagenumbers=false&gridlines=false'+ // hide page numbers and gridlines
'&fzr=false'+ // do not repeat row headers (frozen rows) on each page
'&gid='+shID; // the sheet's Id
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
// generate the PDF file
var response = UrlFetchApp.fetch(url+exportOptions, params).getBlob();
// send the email to the specified address with the specified body text and attached PDF file
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments: [{
fileName: `FILE NAME - ${ss.getName()}` + ".pdf",
content: response.getBytes(),
mimeType: "application/pdf"
}]
});
}
All you have to do is change the SPREADSHEET NAME, SHEET NAME, SUBJECT, BODY, and FILE NAME. Changing around the ExportOptions could also potentially help you.
Once you have this implemented, just set up a trigger for it to run every morning at 9AM.
If you have any questions, do not hesitate to contact me.

Google Script: Failed request and returned code 500

I'm experiencing an error called code 500. The script works fine if I'm using it in the owner account, but if I'm going to open the file as a user/editor, the code 500 error shows. Here is the link to the sample spreadsheet that I'm working on. I tried asking here but seems like it is a little complicated so I created a new single spreadsheet so that it can be easily identified the error.
Here's the code
function doGet(e) {
this[e.parameter.run](e.parameter.sheetName || null);
return ContentService.createTextOutput('It worked!');
}
function HideRows() {
const activeSheet = SpreadsheetApp.getActiveSheet();
const url = ScriptApp.getService().getUrl();
UrlFetchApp.fetch(url + "?run=script_HideRows&sheetName=" + activeSheet.getSheetName(), {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
// DriveApp.getFiles() // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive.readonly". This scope is used for the access token.
}
function showRows() {
const url = ScriptApp.getService().getUrl();
UrlFetchApp.fetch(url + "?run=script_showRows", {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}});
Browser.msgBox(url + "?run=script_showRows");
}
var startRow = 6;
var colToCheck = 2;
// This script is the same with your "HideRows".
function script_HideRows() {
var sheetNames = ["MS_Q1", "MS_Q2", "MS_Q3", "MS_Q4", "SUMMARY"]; // Please set the sheet names here. In this case, 4 sheets are used.
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.getSheets().forEach(sheet => {
var sheetName = sheet.getSheetName();
if (sheetNames.includes(sheetName)) {
if (sheetName == "SUMMARY") { // When the sheet is "SUMMARY", the start row is changed.
startRow = 7;
}
var numRows = sheet.getLastRow();
var elements = sheet.getRange(startRow, colToCheck, numRows).getValues();
for (var i=0; i < elements.length; i++) {
if (shouldHideRow(sheet, i, elements[i][0])) {
sheet.hideRows(startRow + i);
}
}
// Hide the rest of the rows
var totalNumRows = sheet.getMaxRows();
if (totalNumRows > numRows)
sheet.hideRows(numRows+1, totalNumRows - numRows);
}
});
}
// This script is the same with your "showRows".
function script_showRows() {
// set up spreadsheet and sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// var ss = SpreadsheetApp.getActiveSpreadsheet(),
var sheets = ss.getSheets();
for(var i = 0, iLen = sheets.length; i < iLen; i++) {
// get sheet
var sh = sheets[i];
// unhide columns
var rCols = sh.getRange("1:1");
sh.unhideColumn(rCols);
// unhide rows
var rRows = sh.getRange("A:A");
sh.unhideRow(rRows);
}
};
function shouldHideRow(ss, rowIndex, rowValue) {
if (rowValue != '') return false;
if (ss.getRange(startRow + rowIndex, colToCheck, 1, 1).isPartOfMerge()) return false;
if (ss.getRange(startRow + rowIndex + 1, colToCheck, 1, 1).isPartOfMerge()) return false;
return true;
}
First, comment out this
// this [e.parameter.run] (e.parameter.sheetName || null);
Second, avoid this
const url = ScriptApp.getService().getUrl();
replace to
const url = 'https://script.google.com/macros/s/ABCD1234/exec';
Third, publish the web app for all user accessing every time you change code
The next code works for me fine
function doGet(e) {
return ContentService.createTextOutput('It worked!');
}
function HideRows() {
const activeSheet = SpreadsheetApp.getActiveSheet();
const url =
'https://script.google.com/macros/s/ABCD1234/exec';
var response = UrlFetchApp.fetch(
url + '?run=script_HideRows&sheetName=' + activeSheet.getSheetName(),
{
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
muteHttpExceptions: true,
}
);
Browser.msgBox(response);
}