Google Apps Script - XLSX from E-mail to specific Google Sheet - google-apps-script

I'm getting an e-mail daily with an XLSX file that I need to then export over to a specific Google Sheet.
The code simply searches the GMAIL for a specific query, where it then gets the body (which contains a URL), which it then downloads with the doGet function, that uses the Url.FetchApp.fetch(url).getBlob()
After that, using the variable fileInfo, it defines, the title, mimeType of the file and the "parents" which is the ID of the folder where I need to deposit the converted file.
Then, I insert the file with the Drive.Files.insert(fileInfo, file, {convert: true}) which should convert my Excel file and deposit it in my folder.
The export works (a file is exported). If I append a .xlsx extension manually and try to open in Excel,it opens perfectly with all the required information.
But, the issue is that I don't need to open in an Excel file, so I'm trying to export it to a Google Sheet or even parse it as a CSV, but it doesn't work.
When trying to open this exported file by ID, it says that it is missing or don't have permissions, but it is there and I do have permissions.
When checking the mime type of the file, it says "application/x-zip".
Is there anyway for me to upload the file data to my Google Sheet with the ID "1HMXgJuuRFaGK11sfR38mKh6rk4ta_Qgtlljk6HBjLkE"?
function CostDSP() {
var sheetId="1HMXgJuuRFaGK11sfR38mKh6rk4ta_Qgtlljk6HBjLkE";
var threads = GmailApp.search("from:no-reply#amazon.com subject:Cost - DSP in:inbox newer_than:1d");
var message = threads[0].getMessages()[0];
var attachment = message.getPlainBody();
var regex= new RegExp("\<(.*)\>");
var url=regex.exec(attachment)[1];
Logger.log(url);
var file=doGet(url);
var fileInfo = {
title: "Cost - DSP",
mimeType: "MICROSOFT_EXCEL",
"parents": [{'id': "19jrt0DyfvsDz5WAdKhkekHkJ_wP7qP7f"}],
};
Drive.Files.insert(fileInfo, file, {convert: true});
var sourceFile = DriveApp.getFilesByName("Cost - DSP").next();
Logger.log(sourceFile.getMimeType());
Logger.log(sourceFile);
var source=SpreadsheetApp.openById("1lIVb9YM9IK7f8dKuC1RpXjP7nLnMNXm1");
var sheet = sourceFile.getSheets()[0];
var destination = SpreadsheetApp.openById("1HMXgJuuRFaGK11sfR38mKh6rk4ta_Qgtlljk6HBjLkE").getSheetByName('Data Intake');
sheet.copyTo(destination);
}
function doGet(e) {
// e.parameter["file"] //returns ?file=filelink.com/file.xlsx
var file = UrlFetchApp.fetch(e).getBlob();
return file;
}

It seems you need to use the correct mime type for import
mimeType:
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
The next code works fine for me
var file = UrlFetchApp.fetch(
'https://ec.europa.eu/eurostat/statistics-explained/images/9/9f/Country_Codes_and_Names.xlsx'
);
var fileInfo = {
title: 'Cost - DSP',
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
parents: [{
id: 'root'
}],
};
Drive.Files.insert(fileInfo, file, {
convert: true
})
As #Raserhin said it works without the mimeType parameter.
var fileInfo = {
title: 'Cost - DSP',
// mimeType:
// 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
parents: [{ id: 'root' }],
}
;
Also you can't use doGet as you're using now. doGet is a reserved function.

Turns out I also had to set the mimetype in the doGet function to the xlsx mimetype for it to work.
As an optimization I also removed the mimetype specification in the file info variable.
I'm managing to use this doGet function despite it being reserved, so I guess I'll stick to it for now?
As for calling the drive api directly, I need to use the advanced service to be able to convert the xlsx file.

Related

How can i REPLACE a file with another file (if their name is the same) using 'Trash' ing in Google App Script?

I am accessing a list of folders from a shared drive.
In here, I am converting a few excel files into spreadsheet. My issue is to replace the old converted files with the new file. This is because every time i run the script the new converted file(with same name) keeps on multiplying in the same folder together with the old one.
Here is the code:
function ConvertFiles() {
var sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var r= 2;
for(r= 2;r < sheet.getLastRow(); r++){
// Use getValue instead of getValues
var fileId = sheet.getRange(r,1).getValue();
var folderID = sheet.getRange(r,8).getValue();
var files = DriveApp.getFileById(fileId);
var name = files.getName().split('.')[0];
var blob = files.getBlob();
var newFile = {
// Remove '_converted' from name if existing to avoid duplication of the string before adding '_converted'
// This will allow to have newly converted file "replace" the old converted file properly
title: name.replace('_converted','') + '_converted',
parents: [{
id: folderID
}]
};
var destinationFolderId = DriveApp.getFolderById(folderID);
var existingFiles = destinationFolderId.getFilesByName(newFile.title);
// GOAL #1: To replace/update the old converted file into the latest one everytime the script runs (if it has the same filename)
// Find the file with same name of the file to be converted
while(existingFiles.hasNext()) {
// ID of the file with same converted name
var oldConvertedFileWithSameNameID = existingFiles.next().getId();
// Delete before writing
Drive.Files.remove(oldConvertedFileWithSameNameID);
//DriveApp.getFileById(oldConvertedFileWithSameNameID.getId()).setTrashed(true);
}
// Create new converted file then get ID
var newFileID = Drive.Files.insert(newFile, blob, { convert: true,supportsAllDrives: true }).id;
Logger.log(newFileID);
//var sheetFileID = newFileID.getId();
//var Url = "https://drive.google.com/open?id=" + sheetFileID;
var Url = "https://drive.google.com/open?id=" + newFileID;
// Add the ID of the converted file
sheet.getRange(r,9).setValue(newFileID);
sheet.getRange(r,10).setValue(Url);
}
}
My goal is
To replace the old converted file with the new one(if they have the same name) into the shared drive folder
To get to know how can i implement the setTrashed() inside the above code
I have tried using the Drive.Files.remove(oldConvertedFileWithSameNameID); but I am getting an error message GoogleJsonResponseException: API call to drive.files.delete failed with error: File not found:("fileid"). Then i saw an question on this [https://stackoverflow.com/questions/55150681/delete-files-via-drive-api-failed-with-error-insufficient-permissions-for-this]...so i guess that method is not suitable to implemented in shared folder.
So i how can i use setTrashed() method inside the above code?
I think you need to set the supportsAllDrives parameter:
Drive.Files.remove(oldConvertedFileWithSameNameID, {supportsAllDrives: true});
References:
Files:delete | Google Drive API | Google Developers - Parameters

XLSX from Gmail to Google Sheets: invalid mime type. Content type seems to be application/octet?

I'm trying to import an xlsx file from a Gmail Attachment to Google Drive (as Google Sheet) using Google Apps Script. I've tried using the Advanced Drive API in GAS, but doing this results in this error:
API call to drive.files.insert failed with error: Invalid mime type
provided
I've figured out that the Gmail attachment is imported to Google Apps Script as application/octet instead of application/vnd.ms-excel, which I think is the problem. However, the attachment is an xlsx file and I don't see why that would be recognised as application/octet.
Keep in mind, I want to convert the XLSX to Google Sheets. Therefore I need the MimeType.
Here's the code:
var mail = GmailApp.search("XXXXXXX")[0];
var msg = mail.getMessages()[0]
var attachment = msg.getAttachments()[0];
var blob =attachment
var name = attachment.getName();
var folderId = 'XXXXXX';
var file = {
title: 'Converted Spreadsheet',
parents: [{id: folderId}],
mimeType: MimeType.GOOGLE_SHEETS
};
file = Drive.Files.insert(file, blob, {convert: true})
Does anyone have an idea of how to fix the error or find another way to convert this XLSX to a sheet?
Thanks!
In your situation, the mimeType of blob of the attachment file is application/octet.
blob is actually a XLSX file.
When blob of application/octet is used with Drive.Files.insert(), an error of Invalid mime type provided occurs.
You want to convert the XLSX file of above blob to Google Spreadsheet and create it as a file.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
When the mimeType of blob is application/octet,
When Drive.Files.insert({title: 'Converted Spreadsheet', parents: [{id: "root"}], mimeType: MimeType.GOOGLE_SHEETS}, blob, {convert: true}) is run, the error of Invalid mime type provided occurs.
When Drive.Files.insert({title: 'Converted Spreadsheet', parents: [{id: "root"}]}, blob, {convert: true}) is run, no error occurs. But the mimeType of created file is application/octet. By this, the file cannot be directly opened at Google Drive. In this case, it is required to change the mimeType of created file to XLSX. I think that the reason of this is due to This field can be left blank, and the mimetype will be determined from the uploaded content's MIME type.. Ref
From above situation, in this answer, I would like to propose to set the mimeType of XLSX to blob before Drive.Files.insert is run.
Modified script:
When your script is modified, please modify as follows.
From:
var blob =attachment
To:
var blob = attachment.setContentType(MimeType.MICROSOFT_EXCEL); // MimeType.MICROSOFT_EXCEL or MimeType.MICROSOFT_EXCEL_LEGACY
or
To:
If blob has the filename with the extension, you can also use the following script. In this case, the mimeType is automatically given by the extension of the filename.
var blob = attachment.setContentTypeFromExtension();
Note:
In above modified script, the result is the same with and without mimeType: MimeType.GOOGLE_SHEETS in file.
In your question, you say an xlsx file from a Gmail Attachment. And you say the Gmail attachment is imported to Google Apps Script as application/octet instead of application/vnd.ms-excel.
If the file is XLSX file, the mimeType is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
If the fie is XLS file, the mimeType is application/vnd.ms-excel.
References:
setContentType(contentType)
setContentTypeFromExtension()
Enum MimeType
If this didn't resolve your issue, I apologize.
These
parents: [{id: folderId}],
mimeType: MimeType.GOOGLE_SHEETS
refer to the input file. See docs here. You should skip these.
This snippet worked for me with Google Drive API v2:
function abc() {
var mail = GmailApp.search("SEARCH_TERM")[0];
var msg = mail.getMessages()[0];
var blob = msg.getAttachments()[0];
var file = {
title: 'Converted Spreadsheet'
};
Drive.Files.insert(file, blob, {convert: true});
}

Google Apps Script returns file from drive as application/pdf instead of original filetype

When running my script I get the error Converting from application/pdf to application/vnd.google-apps.spreadsheet is not supported. (line 6, file "Code")
The original file is no PDF but an excel worksheet. I tried different file with different types and every file returned as PDF.
Here is my code:
function sendTimelist() {
var emailAddress = 'some#mail.com';
var mailReplyTo = 'somemore#mail.com';
var subject = 'Timelist';
var message = 'Here is my timelist!';
var timelist = SpreadsheetApp.openById("1v7EShuCrjrEa8BxW2JGCRDUwuIsUk03fnvvYEVntlvM").getAs(MimeType.GOOGLE_SHEETS);
var optAdvancedArgs = {replyTo: mailReplyTo, name: attachmentName, attachments: [timelist] };
var attachmentName = 'Timelist.xlsx';
GmailApp.sendEmail(emailAddress, subject, message, optAdvancedArgs);
}
What am I missing?
I focused on the length of your file ID. Your file ID is 1v7EShuCrjrEa8BxW2JGCRDUwuIsUk03fnvvYEVntlvM. The length is 44. In the case of Excel file in Google Drive, the length of ID is 28. And the case of Google Docs (Spreadsheet, Document, Slide), the length of ID is 44.
When Google Docs files are downloaded without the assignment of export format, the format automatically becomes PDF.
I thought that you might try to send Spreadsheet of Google Docs. In order to confirm this, can you try to run a following script?
var id = "1v7EShuCrjrEa8BxW2JGCRDUwuIsUk03fnvvYEVntlvM";
Logger.log(DriveApp.getFileById(id).getMimeType());
If the log shows application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, the file is Excel file. If the log shows application/vnd.google-apps.spreadsheet, the file is Spreadsheet file.
In the case of Excel file, when the file is sent as an attachment file of gmail, it is not converted. Excel file can be sent. In the case of Spreadsheet file, it is converted to PDF and sent as an attachment file.
If your file was a Spreadsheet file, in order to send it as Excel file, you can use the following sample script.
Sample script :
function sendTimelist() {
var emailAddress = 'some#mail.com';
var mailReplyTo = 'somemore#mail.com';
var subject = 'Timelist';
var message = 'Here is my timelist!';
var attachmentName = 'Timelist.xlsx';
var fileId = "1v7EShuCrjrEa8BxW2JGCRDUwuIsUk03fnvvYEVntlvM";
var timelist = UrlFetchApp.fetch(
"https://docs.google.com/feeds/download/spreadsheets/Export?key=" + fileId + "&exportFormat=xlsx",
{
"headers": {Authorization: "Bearer " + ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
}
).getBlob().setName(attachmentName);
var optAdvancedArgs = {replyTo: mailReplyTo, name: attachmentName, attachments: [timelist] };
GmailApp.sendEmail(emailAddress, subject, message, optAdvancedArgs);
}
If I misunderstand your situation, I'm sorry.
I think the source of the problem is using SpreadsheetApp to open the file. To preserve original data type, open it as DriveApp.getFileById(...) which returns a File object. You shouldn't need getAs either.

Converting from word document to native google doc

So I have some 2000 word documents I can generate with c#, however, I need them uploaded to google docs, in the native google docs format.
I looked at This guide to try to convert them, however, the code fails on the second to last line.
(My code below)
function myFunction() {
var folder = DriveApp.getFoldersByName("test").next();
var contents = folder.getFiles();
while (contents.hasNext()){
var file = contents.next();
var fileName = file.getName();
var officeFile = DriveApp.getFilesByName(fileName).next();
// Use the Advanced Drive API to upload the Excel file to Drive
// convert = true will convert the file to the corresponding Google Docs format
var uploadFile = JSON.parse(UrlFetchApp.fetch(
"https://www.googleapis.com/upload/drive/v2/files?uploadType=media&convert=true",
{
method: "POST",
contentType: officeFile.getMimeType(),
payload: officeFile.getBlob().getBytes(),
headers: {
"Authorization" : "Bearer " + ScriptApp.getOAuthToken()
},
muteHttpExceptions: true
}
).getContentText());
// Remove the file extension from the original file name
var fileName2 = officeFile.getName();
fileName2 = fileName2.substr(0, fileName2.lastIndexOf("."));
// Update the name of the Google Sheet created from the Excel sheet
DriveApp.getFileById(uploadFile.getID()).setName(fileName2); // FAILS HERE
//Logger.log(uploadFile.alternateLink);
}}
TypeError: Cannot find function getID in object [object Object]. (line 33, file "Code")
I understand what kind of error this is, however, I do not necessarily know how to solve it.
You don't need any UrlFetchApp manipulations. The Advanced Drive Service provides conversion as a part of copy method. Takes two lines of code:
var fileId = 'ID_of_Word_file';
Drive.Files.copy({}, fileId, {'convert': true});
You will need to enable this service in the scropt menu: see Resources > Advanced Services.
If iterating through a folder, get each file from file iterator with .next() and use getId() to get its id; the proceed as above.
The empty object in the first argument can be used to name the new file: e.g., it could be {'title': 'Name of new file'}

Apps Script Drive App Service - Create a file of Google Type - Mime Type

I'm using the .createFile method of the DriveApp Folder class. This is the syntax:
createFile(name, content, mimeType)
The documentation is here: createFile Google DriveApp Service
The example shows a mimeType setting of MimeType.HTML.
// Create an HTML file with the content "Hello, world!"
DriveApp.createFile('New HTML File', '<b>Hello, world!</b>', MimeType.HTML);
I can type in MimeType. and get a list of MimeTypes, one of them being GOOGLE_DOCS. So I entered MimeType.GOOGLE_DOCS. But I'm getting an execution error stating that one of the arguments is invalid. If I type in a Mime Type of 'text/plain', I get no error.
How do I create a file with the document type of a Google Type?
If I enter a Mime Type of 'GOOGLE_DOCS' as text, it creates a file, but it creates a file with a file type of application/octet-stream.
If I use a MimeType of MimeType.HTML, I don't get an error, and the file is viewable from my Google Drive.
You can use DocumentApp.create('File_Name') to create a fileType of GOOGLE_DOCS. DocumentApp service allows to create and manipulate Google Documents. For more details, you may check the reference.
References:
https://developers.google.com/apps-script/reference/document/document-app
In order to place the recently create Document in a Folder, you may use DriveApp. Here is a sample code.
function createandPlaceInFolder(){
//Create the document
var doc = DocumentApp.create('My new file');
//get it as a drive file
var file = DriveApp.getFileById(doc.getId());
//get the target folder
var targetFolder = DriveApp.getFolderById('MY_FOLDER_ID');//Change it to the folder_Id
//place the file in target folder
targetFolder.addFile(file);
}
I'm using this modified script for making sheet backups.Maybe it can be useful, it has fixed this same issue for me. It needs to enable Drive API before using it.
function makeCopy(fileSheetId, dstFolderId) {
var fileSheet = DriveApp.getFileById(fileSheetId);
var dstFolder = DriveApp.getFolderById(dstFolderId);
var f = fileSheet.makeCopy(dstFolder);
if (file.getMimeType() == MimeType.GOOGLE_APPS_SCRIPT) {
Drive.Files.update({"parents": [{"id": dstFolderId}]}, f.getId());
}
}
function run() {
var fileSheetId = "<Sheet ID>";
var dstFolderId = "<Destination folder ID>";
makeCopy(fileSheetId, dstFolderId);
}