How to Attach a Google Spreadsheet to an Email - google-apps-script

I am trying to attach an already created spreadsheet and email it. I have found out that, if I try
opts.fileIds.forEach(function(fileId) {
console.log('fileId ' + fileId);
var file = DriveApp.getFileById(fileId);
var blob = file.getAs(file.getMimeType());
console.log('blob length' + blob.getDataAsString().length);
console.log('file retrieved size ' + file.getSize());
console.log('file mime type ' + file.getMimeType());
attachmentList.push(blob);
});
I do not get a blob object, file.getAs returns a null however, file.getBlob works fine but turns it into a pdf which is not what I want. Is there any way to attach this a spreadsheet?

The attachments option for MailApp requires an array of BlobSource objects. If you take a look at the link you can see that Google Files can just be attached without additional work. This includes Spreadsheets, Documents, PDFs, and more.
Try just passing back a reference to the file!
opts.fileIds.forEach(function(fileId) {
console.log('fileId ' + fileId);
var file = DriveApp.getFileById(fileId);
//logging
attachmentList.push(file);
});
Edit: The reason for this behaviour by MailApp, I think is because MIMEType and getAs() ContentType are different. Take a look at what the Google Scripts site says about https://developers.google.com/apps-script/reference/base/blob#getAs(String):
For most blobs, 'application/pdf' is the only valid option.
Can someone confirm this?

Related

How to update file contents from gdoc to docx

I am trying to create an Apps Script that will auto-convert all gdoc files to docx files (and all gsheet files to xlsx files). Some parts of the puzzle are addressed here: Batch convert Google Docs files to Microsoft Word, however this creates a new file. I need to keep the URL/ID of the original file. I tried using "setContent" on the File API but that doesn't seem to handle blobs. So thats why I resorted to the advanced Drive API. However, I can't seem to get it to work properly. The filename is replaced, the contents are replaced, but the file stays Google Doc, even though I supply a Mime Type. Any ideas?
This is my code:
function convertGoogleDocsToMicrosoftWord() {
var folderId = "MY_FOLDER_ID"; // Note, eventually I would like to get this from the trigger event somehow so I would welcome ideas on this, too
var files = DriveApp.getFolderById(srcfolderId).getFilesByType(MimeType.GOOGLE_DOCS);
while (files.hasNext()) {
var file = files.next();
var contents = UrlFetchApp.fetch(
"https://docs.google.com/document/d/" + file.getId() + "/export?format=docx",
{
"headers": {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
}
).getBlob();
Drive.Files.update({
mimeType: MimeType.MICROSOFT_WORD,
title: file.getName() + '.docx'
}, file.getId(), contents);
}
}
Some further questions:
assuming I can make this to work, can it update while the file is open?
I would like to be able to launch this on trigger events... however standalone scripts can't seem to be able to get a ref to the current folder they are executed in and then recourse. Is this possible?

Exception: Blob object must have non-null data for this operation. (line 19)

Hi I'm trying to attach multiple Google Doc files from a folder to send to an Email. However, the above exception arises.
The code is as follows
function email() {
// Get attachments folder
var attachementFolderId = "xyz";
Logger.log("Attachement Folder ID: " + attachementFolderId)
var getAttachementFolder = DriveApp.getFolderById(attachementFolderId);
// Get all files from the folder
var files = DriveApp.getFolderById(attachementFolderId).getFiles();
//Get All attachments
var attachements = [];
while (files.hasNext()) {
var file = files.next();
attachements.push(file.getAs(MimeType.GOOGLE_DOCS));
}
MailApp.sendEmail({
to: email,
subject: subject,
attachments: attachements
})
}
This code works fine if the file is either a pdf or a Microsoft Word doc but causes an issue for a Google Doc.
Modification points:
When the official document of getAs(contentType)
) is seen, it says as follows.
The MIME type to convert to. For most blobs, 'application/pdf' is the only valid option. For images in BMP, GIF, JPEG, or PNG format, any of 'image/bmp', 'image/gif', 'image/jpeg', or 'image/png' are also valid.
In this case, unfortunately, MimeType.GOOGLE_DOCS cannot be used for this.
When you want to retrieve the blob from Google Document. It is required to convert it to other mimeType.
When you want to convert it to PDF format, please modify file.getAs(MimeType.GOOGLE_DOCS) to file.getBlob().
When you want to convert it to DOCX format, I think that this thread might be useful.
References:
getAs(contentType)
Related question
Convert Google Doc to Docx using Google Script

Google Apps Script - get URL of File in Drive with File Name

I am attempting to create a form in Google Spreadsheets which will pull an image file from my Drive based on the name of the file and insert it into a cell. I've read that you can't currently do this directly through Google Scripts, so I'm using setFormula() adn the =IMAGE() function in the target cell to insert the image. However, I need the URL of the image in order to do this. I need to use the name of the file to get the URL, since the form concatenates a unique numerical ID into a string to use the standardized naming convention for these files. My issue is that, when I use getFilesByName, it returns a File Iteration, and I need a File in order to use getUrl(). Below is an snippet of my code which currently returns the error "Cannot find function getUrl in object FileIterator."
var poNumber = entryFormSheet.getRange(2, 2);
var proofHorizontal = drive.getFilesByName('PO ' + poNumber + ' Proof Horizontal.png').getUrl();
packingInstructionsSheet.getRange(7, 1).setFormula('IMAGE(' + proofHorizontal + ')');
If you know the file name exactly, You can use DriveApp to search the file and getUrl()
function getFile(name) {
var files = DriveApp.getFilesByName(name);
while (files.hasNext()) {
var file = files.next();
//Logs all the files with the given name
Logger.log('Name:'+file.getName()+'\nUrl'+ file.getUrl());
}
}
If you don't know the name exactly, You can use DriveApp.searchFiles() method.
You're close - once you have the FileIterator, you need to advance it to obtain a File, i.e. call FileIterator.next().
If multiple files can have the same name, the file you want may not be the first one. I recommend checking this in your script, just in case:
var searchName = "PO + .....";
var results = DriveApp.getFilesByName(searchName);
var result = "No matching files";
while (results.hasNext()) {
var file = results.next();
if (file.getMimeType() == MimeType. /* pick your image type here */ ) {
result = "=IMAGE( .... " + file.getUrl() + ")");
if (results.hasNext()) console.warn("Multiple files found for search '%s'", searchName);
break;
}
}
sheet.getRange( ... ).setFormula(result);
You can view the available MimeTypes in documentation

Share issue with script

I have this script I am using to make a copy of a sheet and then send me that copy thru email as a xslx file, if I have the sheet set for share to anyone with a link the script works great, but if I have it set to specific people it runs but gives a Value# instead of the data on the page. the page I am trying to send is a query importrange formula pulling the data on to the sheet. any help would be greatly appreciated.
enter code herefunction emailExcel() {
var mailTo, subject, body, id, sheetNum, sh, sourceSS, copySS, file, url,token, response;
mailTo = 'elder1104#gmail.com';
subject = 'subject';
body = 'text_in_body';
id = '1eI-p0nodA4zqP3fsxP5P6iR6gyvSIGRZDMaQSGkb2ds';
sheetNum = 2;
sourceSS = SpreadsheetApp.openById(id);
copySS = sourceSS.copy('copy of ' + sourceSS.getName());
sh = copySS.getSheets()[sheetNum];
sh.getDataRange().setValues(sh.getDataRange().getDisplayValues())
copySS.getSheets()
.forEach(function (sh, i) {
if(i != sheetNum) copySS.deleteSheet(sh);
})
file = Drive.Files.get(copySS.getId());
url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
token = ScriptApp.getOAuthToken();
response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
MailApp.sendEmail(mailTo, subject, body, {
attachments: [response.getBlob()
.setName('TESTING.xlsx')]
});
DriveApp.getFileById(copySS.getId()).setTrashed(true);
}
To share Drive file to specific people, try to add setSharing(accessType, permissionType) method given in Class File.
As mentioned in Working with enums,
the Drive service uses the enums Access and Permission to determine which users have access to a file or folder.
So to access file or folder in DriveApp, you should add the following enumerated types to determine users who can access a file or folder, besides any individual users who have been explicitly given access
Access
Permission
It will really be helpful to try going through the given documentations.
I took the easy way out and made a new spreadsheet and I am importing to that spreadsheet using a script, so now the new document just has data on it and is working perfectly now.

Google app scripts: email a spreadsheet as excel

How do you make an app script which attaches a spreadsheet as an excel file and emails it to a certain email address?
There are some older posts on Stackoverflow on how to do this however they seem to be outdated now and do not seem to work.
Thank you.
It looks like #Christiaan Westerbeek's answer is spot on but its been a year now since his post and I think there needs to be a bit of a modification in the script he has given above.
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
There is something wrong with this line of code, maybe that exportLinks has now depreciated. When I executed his code it gave an error to the following effect:
TypeError: Cannot read property "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" from undefined.
The workaround is as follows:
The URL in the above line of code is basically the "download as xlsx" URL that can be used to directly download the spreadsheet as an xlsx file that you get from File> Download as > Microsoft Excel (.xlsx)
This is the format:
https://docs.google.com/spreadsheets/d/<<<ID>>>/export?format=xlsx&id=<<<ID>>>
where <<>> should be replaced by the ID of your file.
Check here to easily understand how to extract the ID from the URL of your google sheet.
Here's an up-to-date and working version. One prerequisite for this Google Apps script to work is that the Drive API v2 Advanced Google Service must be enabled. Enable it in your Google Apps script via Resources -> Advanced Google Services... -> Drive API v2 -> on. Then, that window will tell you that you must also enabled this service in the Google Developers Console. Follow the link and enable the service there too! When you're done, just use this script.
/**
* Thanks to a few answers that helped me build this script
* Explaining the Advanced Drive Service must be enabled: http://stackoverflow.com/a/27281729/1385429
* Explaining how to convert to a blob: http://ctrlq.org/code/20009-convert-google-documents
* Explaining how to convert to zip and to send the email: http://ctrlq.org/code/19869-email-google-spreadsheets-pdf
* New way to set the url to download from by #tera
*/
function emailAsExcel(config) {
if (!config || !config.to || !config.subject || !config.body) {
throw new Error('Configure "to", "subject" and "body" in an object as the first parameter');
}
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = spreadsheet.getId()
var file = Drive.Files.get(spreadsheetId);
var url = 'https://docs.google.com/spreadsheets/d/'+spreadsheetId+'/export?format=xlsx';
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var fileName = (config.fileName || spreadsheet.getName()) + '.xlsx';
var blobs = [response.getBlob().setName(fileName)];
if (config.zip) {
blobs = [Utilities.zip(blobs).setName(fileName + '.zip')];
}
GmailApp.sendEmail(
config.to,
config.subject,
config.body,
{
attachments: blobs
}
);
}
Update: I updated the way to set the url to download from. Doing it through the file.exportLinks collection is not working anymore. Thanks to #tera for pointing that out in his answer.