google apps script to create new pdf document of updated cells after form submission and email this pdf error message: - forms

Please bear with me as I am very much a beginner at this. I am trying to write a Google script which creates a new spreadsheet of the relevant data after a form is submitted, converts this to a PDF, and sends it as an email attachment to an email address which is submitted to the form. I am writing the code in a script which is bound to the sheet which performs some calculations on the data once it is submitted. The form is also bound to the sheet. I will paste my code below and here is a link to the sheet:
https://docs.google.com/spreadsheets/d/1oQTeQFwl7IfWF8D17oK1Mutp4TXidQXUT4lv46ktuwM/edit?usp=sharing
I am trying to email the small green summary section on the sheet named INPUTS/OUTPUTS as a pdf.
The Template file "MyCalculations" is just an empty spreadsheet apart from one line saying "here are your calculation results".
The summary section updates itself well and correctly after a form is submitted I am just having real trouble accessing the sheet because I can't code!
Here is the code so far:
function onFormSubmit(e){
//Variables
var userEmail = SpreadsheetApp.getActiveSheet().getRange("H24").getValue();
var totalOutstandingPrincipalDebt = SpreadsheetApp.getActiveSheet().getRange("G22").getValue();
var totalOutstandingInterest = SpreadsheetApp.getActiveSheet().getRange("H22").getValue();
var totalOutstandingCompensation = SpreadsheetApp.getActiveSheet().getRange("I22").getValue();
var dailyInterestRate = SpreadsheetApp.getActiveSheet().getRange("J22").getValue();
var grandTotal = SpreadsheetApp.getActiveSheet().getRange("G23").getValue();
var docTemplate = DriveApp.getFilesByName("MyCalculations");
//Template Info
var docName="Calculations";
var copyDoc= docTemplate.makeCopy();
var copyId = copyDoc.getId();
var copyBody = docTemplate.getActiveSection();
copyBody.getRange(2, 1).setValue("Total Outstanding Principal Debt");
copyBody.getRange(2, 2).setValue("Total Outstanding Interest");
copyBody.getRange(2, 3).setValue("Total Outstanding Compensation");
copyBody.getRange(2, 4).setValue("Grand Total");
copyBody.getRange(2, 5).setValue("Daily Interest Rate");
copyBody.getRange(3, 1).setValue(totalOutstandingPrincipalDebt);
copyBody.getRange(3, 2).setValue(totalOutstandingInterest);
copyBody.getRange(3, 3).setValue(totalOutstandingCompensation);
copyBody.getRange(3, 4).setValue(grandTotal);
copyBody.getRange(3, 5).setValue(dailyInterestRate);
//Save as PDF and send e-mail
var pdf = getFileById(copyId).getAs("application/pdf");
var subject = "Calculations";
var body = "Thank you very much for using our online calculator. Please find your results attached.";
MailApp.sendEmail(userEmail, subject, body, {htmlBody: body, attachments: pdf});
//Deletes temporary Document
DriveApp.getFileById(copyId).setTrashed(true);
}
I also don't think that in this code, I have specified which sheet on my spreadsheet I am wanting to get the data from, but I don't know how to do that either!
Any help would be so so appreciated!

var docTemplate = DriveApp.getFilesByName("MyCalculations");
getFilesByName returns a FileIterator not a Spreadsheet so you have to change that to:
var docTemplate = DriveApp.getFilesByName("MyCalculations").next().getAs(MimeType.GOOGLE_SHEETS);
Next, in var copyBody = docTemplate.getActiveSection(); there is no such method called getActiveSection change that to:
var copyBody = docTemplate.getActiveSheet();
Lastly, the line var pdf = getFileById(copyId).getAs("application/pdf");
should be
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
Implement those changes and let me know how it works. =)
Update
I fiddled around and as far as I can tell, DriveApp automatically converts almost all files to a PDF. So, as I understand it, you are using the MyCalculations spreadsheet as a template so that you can convert it into a PDF and send it.
We can accomplish this with a little bit of a roundabout way.
First, we create a new sheet in our original spreadsheet, and hide it from view so that the user can't see it.
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var myCalculations = spreadsheet.insertSheet("MyCalculations",spreadsheet.getNumSheets());
myCalculations.hideSheet();
Secondly, we set all the values that you want. So change
copyBody.setRange ...
to
myCalculations.setRange ...
Thirdly, once we have all our data set. We are going create a temporary Spreadsheet to copy all our data into so that we may export it as a PDF and send it in an email
var tempSpreadsheet = SpreadsheetApp.create('Temporary');
Fourth, we copy our calculations page into the temporary spreadsheet.
myCalculations.copyTo(tempSpreadsheet);
Perfect! Now we just convert the temporary spreadsheet into a PDF and do a little clean-up. Be sure to note the change to the line where we delete the temporary spreadsheet. I get the id by just calling the getId() method
var pdf = tempSpreadsheet.getAs(MimeType.PDF);
var subject = "Calculations";
var body = "Thank you very much for using our online calculator. Please find your results attached.";
MailApp.sendEmail(userEmail, subject, body, {htmlBody: body, attachments: pdf});
//Deletes temporary Document
DriveApp.getFileById(tempSpreadsheet.getId()).setTrashed(true);
That should do the trick. Comment how it works for you. =)

I managed to get this code working:
//Set out global variables
var docTemplate = ("1Ff3SfcXQyGeCe8-Y24l4EUMU7P9TsgREsAYO9W6RE2o");
var docName=("Calculations");
function onFormSubmit(e){
//Variables
var userEmail = SpreadsheetApp.getActiveSheet().getRange("H24").getValue();
var totalOutstandingPrincipalDebt =SpreadsheetApp.getActiveSheet().getRange("G22").getValue();
var totalOutstandingInterest = SpreadsheetApp.getActiveSheet().getRange("H22").getValue();
var totalOutstandingCompensation = SpreadsheetApp.getActiveSheet().getRange("I22").getValue();
var dailyInterestRate = SpreadsheetApp.getActiveSheet().getRange("J22").getValue();
var grandTotal = SpreadsheetApp.getActiveSheet().getRange("G23").getValue();
//Template Info
var copyId=DriveApp.getFileById(docTemplate).makeCopy(docName+' for '+userEmail).getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
//Putting the data into the file
copyBody.insertParagraph(0,'Total Outstanding Principal Debt: ' + totalOutstandingPrincipalDebt);
copyBody.insertParagraph(1,'Total Outstanding Interest: '+ totalOutstandingInterest );
copyBody.insertParagraph(2,'Total Outstanding Compensation: '+ totalOutstandingCompensation);
copyBody.insertParagraph(3,'Grand Total: ' + grandTotal);
copyBody.insertParagraph(4,'Daily Interest Rate: '+ dailyInterestRate);
copyDoc.saveAndClose();
//email pdf document as attachment
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
var subject = "Calculations";
var body = "Thank you very much for using our online calculator. Please find your results attached.";
MailApp.sendEmail(userEmail, subject, body, {htmlBody: body, attachments: pdf});
//Deletes temporary Document
DriveApp.getFileById(copyId).setTrashed(true);
}

Related

How to attach a google doc file as Microsoft Word doc

My first time here in Stack overflow. I'm just an amateur programmer trying to learn Google Apps script. I created a google form to get answers from users. I have transferred the answers to a google doc formatted according to our use in the office. I need to email the google doc back to the for user in microsoft word format. Sending as pdf is not a problem, but msword is a bit tricky.
I tried copying the recommendations i found here but I can't seem to get it to run. I hope someone can tell me what i'm doing wrong and what i need to doe. here's the relevant portion of the code:
`doc.saveAndClose(); // end of the transfer from google sheet to google doc. now to email...
var filename= ts+"-"+c_name1;
var compfile = DriveApp.getFilesByName(filename);
if (!compfile.hasNext())
{
console.error("Could not open file "+filename);
return;
}
var template = HtmlService.createTemplateFromFile('email_message');
var message = template.evaluate().getContent();
MailApp.sendEmail({
to:em,
subject: "Automated Complaint Assistant",
htmlBody: message,
attachments: compfile.next()}) // attachment is pdf file type. HOW TO SEND AS WORD?
`
I tried this function i found here:
`function EmailCompAsWordDoc(email, name, newCopyID) {
var subject = "Word version of Complaint";
var body = "\n\nHere is the Microsoft Word version of the draft Complaint";
var url = 'https://docs.google.com/feeds/download/documents/export/Export?id=' + newCopyID + '&exportFormat=docx';
var options = {
headers: {
Authorization: "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true
}
var response = UrlFetchApp.fetch(url, options);
var doc = response.getBlob();
//Create the docx file in my TEMP folder in Google Drive and send
var file = DriveApp.createFile(doc).setName('Draft Complaint '+ name + '.docx');
DriveApp.getFolderById('<ID of my TEMP folder in Google Drive>').addFile(file);
var blob = DriveApp.getFileById(file.getId());
if (MailApp.getRemainingDailyQuota() > 0)
GmailApp.sendEmail(email, subject, body, {
Body: body,
attachments:[blob]
});
//Remove the docx file from the TEMP folder
DriveApp.getFileById(file.getId()).setTrashed(true);
}
var compid = DriveApp.getFileById(filename.getId()) // error here. How to get the file ID for use by this custom function??
EmailCompAsWordDoc(em, c_name1, compid)
`
From your provided script, I understood that the value of filename is the string value of var filename = ts + "-" + c_name1;. I thought that this is the reason for your current issue of filename.getId is not a function.
In this case, how about the following modification?
From:
var compid = DriveApp.getFileById(filename.getId())
To:
var compid = DriveApp.getFilesByName(filename).next().getId();
In this case, it supposes that the values of filename and em and c_name1 of EmailCompAsWordDoc(em, c_name1, compid) are valid values. Please be careful about this.

How to send a conditional email based on the value of a cell from a form response?

I have a formula that calculates a number based on the response from a google form. Depending on what this number I want to send an email using details from the from as well as a pre typed email in another cell.
In Col1 is a time stamp, in col14 is an employee start date. My formula in Col33 works out how many days they have been employed at the time of submitting the form.
I want to send an email to the person if the number of days is less than 182.
I have an email pre typed out and can place this anywhere. At the moment I have it in all cells in col36. The email address will be in column32.
I have tried a number of different codes and none of them are sending the email no matter what the trigger I have set up is. I have very basic knowledge on apps script so my current code might be completely wrong, but it should show roughly what I'm getting at.
function sendEmail() {
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues()
for (i in values.length) {
var data = values[i][33];
var emailAddress = values[i][32];
var message = values[i][36];
if (data < 182); {
MailApp.sendEmail(emailAddress, "Flexible Working Request", message);
}
}
}
The current results have just been deleting the data in col33, Col34 & Col36 on the new form response row only.
Sorry if this question has been answered elsewhere, any other answer I found to similar issues I could not get to work.
I got someone who is much better at google apps script at work to give me a hand
It is to do with google forms pushing down formulas to the side
So we had to move the formula calculating the number of days to another sheet and then used this formula which worked
function sendEmailv2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form responses
1');
var scrip = Session.getScriptTimeZone();
var date = sheet.getRange(sheet.getLastRow(),14).getValue();
var sub = sheet.getRange(sheet.getLastRow(),1).getValue();
Logger.log(date);
var fortmat = Utilities.formatDate(new Date(date), scrip, "dd/MM/yyyy");
var Subfortmat = Utilities.formatDate(new Date(sub), scrip, "dd/MM/yyyy");
var emailAddress = sheet.getRange(sheet.getLastRow(),32).getValue();
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet4');
var message = sheet2.getRange(1,1).getValue();
var days = sheet2.getRange(sheet2.getLastRow(),2).getValue();
if (days<182){
MailApp.sendEmail(emailAddress, "Flexible Working Request", message,{noReply:true});
}
}
Thanks!
You don’t need to go over all the columns to get a single cell value, so there is no need for a for loop. You can do it directly with:
var sheet = SpreadsheetApp.getActiveSheet().getSheets[0];
var cell = ["A33"];
var days_value = sheet.getRange(cell).getValue();
Then you can just make an if condition to send the email:
if (days_value < 182){
MailApp.sendEmail(emailAddress, "Flexible Working Request", message);
}
Hope this helps

Name email attachment in Google Apps Script

I have the following G.A.S script to email a google sheet as a pdf attachment.
var spreadsheet = SpreadsheetApp.getActive();
var subject = spreadsheet.getRange("U1:U1").getValues();
var emailTo = spreadsheet.getRange("V1:V1").getValues();
var message = spreadsheet.getRange("W1:W1").getValues();
var pdf = DriveApp.getFileById(spreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:subject,content:pdf, mimeType:'application/pdf'};
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
The above code works well except that the file attached to the email message has a bizarre name like "[Ljava.lang.Object_#4e63998c" with no ".pdf" extension!
I am looking for a way to set a name for the pdf file before being attached to the email. The file name should equal the "subject" variable.
Thanks in advance.
Omid
Values retrieved by getValues() is 2 dimensional array. I think that the filename becomes such string because the array is used as the filename. Please retrieve the element from the array and try again. So could you please modify as follows?
From :
var attach = {fileName:subject,content:pdf, mimeType:'application/pdf'};
To :
var attach = {fileName:subject[0][0],content:pdf, mimeType:'application/pdf'};
You can also use the following modification. In this case, getValue() can retrieve the value as a string from the cell "U1".
From :
var subject = spreadsheet.getRange("U1:U1").getValues();
To :
var subject = spreadsheet.getRange("U1:U1").getValue();
Reference :
getValue()
getValues()
If this was not what you want, please tell me. I would like to think of other solutions.
I'm a bit late, but another way to solve this problem might be:
var spreadsheet = SpreadsheetApp.getActive();
var subject = spreadsheet.getRange("U1:U1").getValues();
var emailTo = spreadsheet.getRange("V1:V1").getValues();
var message = spreadsheet.getRange("W1:W1").getValues();
var pdf = DriveApp.getFileById(spreadsheet.getId())
.getAs('application/pdf')
.getBlob()
.setName(subject);
MailApp.sendEmail(emailTo, subject, message, {attachments:[pdf]});
The Blob class has a setName method https://developers.google.com/apps-script/reference/base/blob#setName(String), that can be chained into a Blob object (which is the result of getBlob())
After that you just need to add the Blob object inside attachments array of function MailApp.sendEmail

Generate and send pdf through Google Forms to my email address - doesn't send, debugging to no assitance

I'm trying to send myself a form-based report as a pdf. The problem is, I don't receive any emails. Debugging doesn't help much, since that only tells me which values are "undefined" (they are being defined the instant one fills out the form and triggers the email by clicking send; in theory). My coding experience stems from the days of TurboPascal and .bat-files, and I have lately realised I need to shape up. Trying to figure out Android, and this is a little experiment at work. But I had forgotten the lost feeling of "what now?"...
Here's the code:
// Samfunnsutvikling kursrapport
var docTemplate = "TemplateIDinGoogleDoks";
var docName = "Kursrapport";
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from form and set as variables
var email = "worker#work.no";
var namn = e.namedvalues.namn;
var arrangement = e.namedvalues.arrangement;
var dato = e.namedvalues.dato;
var referat = e.namedvalues.referat;
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+namn)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keynamn', namn);
copyBody.replaceText('keyarrangement', arrangement);
copyBody.replaceText('keydato', dato);
copyBody.replaceText('keyreferat', referat);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "Kursrapport";
var body = "Kursrapporten frå " + namn + "";
GmailApp.sendEmail(email, subject, body, {htmlBody: body, attachments: pdf});
// Delete temp file
DocsList.getFileById(copyId).setTrashed(true);
}
The script/document is authorized to send emails, but, oddly, I had to authorize it twice. It is saved.
In general, you can add Logger.log() to print variable values or just messages to see how far does it reach.
It looks as attachments parameter expects Blob[] type, however you are passing just Blob. So, it should be:
GmailApp.sendEmail(email, subject, body, {htmlBody: body, attachments: [pdf]});
You may also want to replace DocsList with DriveApp class as-is since the first one is depricated.
Update
It turned out also that getActiveSection() was renamed to getBody().

How to copy paste a google spreadsheet table into gmail using google script?

I have a google spreadsheet with a pivot table, which i want to be emailed automatically based on certain criteria using my gmail. I am quite happy with the email script and the cinditions however I cannot find anywhere a script that can effectively replicate a "copy - paste" of the table into the email.
I would appreciate any help you could offer with this.
Thanks
Agi
I managed to get it to work using advice from this community. Thank you!
I am trying to get it to display values horizontally i.e. each line a new customer record. However, i get something different. I am attaching a file with what I get and the code. I would appreciate any advice. I am so sure that the solution is just there but after many hours I cannot get it :( I am showing the code below and I am attaching a photo with the current and desired outcome.
Many thanks
Agi
function testMail(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var responses = ss.getSheetByName("Monitoreo de Pedidos");
// var lastRow = responses.getLastRow();
// var values = responses.getRange("A2"+(lastRow)+":R2"+(lastRow)).getValues();
var values = responses.getRange("A3:R12").getValues();
var headers = responses.getRange("A2:R2").getValues(); //The headers. A1 TO R1 does not contain relevant data
var message = composeMessage (headers,values);
var messageHTML = composeHtmlMsg(headers,values);
Logger.log(messageHTML);
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'test html', message,{'htmlBody':messageHTML});
}
function composeMessage(headers,values){
var message = 'Here are the data you submitted :\n'
for (var j=0;j<5;++j){ //NUMBER OF ROWS
for(var c=0;c<values[0].length;++c){ //NUMBER OF COLUMNS, in the future this will be dynamic
message+='\n'+headers[0][c]+' : '+values[j][c]
}
}
return message;
}
function composeHtmlMsg(headers,values){
var message = 'Here are the data you submitted :<br><br><table style="background- color:yellow;border-collapse:collapse;" border = 1 cellpadding = 5><th>Title</th> <th>Customer Info</th><tr>'
for (var j=0;j<5;++j){
for(var c=0;c<values[0].length;++c){
message+='<tr><td>'+headers[0][c]+'</td><td>'+values[j][c]+'</td></tr>'
}
}
return message+'</table>';
![Desired outcome][1]}
You need to write the email body as html and insert the in there. More work if you want to mimic formatting. Try if and write back if you get stuck.