search Gmail for xls attachments - javascript

with this code I use to save attachment to a shared google drive folder and got notified when a change happen to it by a mail. All is fine as long as I search for pdf attachments. As I set file:xls the messages returned are far more than expected. Not only, the threads returned by the debug are correct, as well as insert the query in the search filed in Gmail, but the getmessages() returned in this case 38 messages (and attachements! And not only xls but also a pdf) of the query parameters. The conversation view is disabled in Gmail, the only match with this attachments is the from: field.
I tried to change the reference data (by adding newer_than), and nothing changed; I changed the for cycle, and nothing changed. Am I missing something really stupid or is this a kind of bug with xls?
function salvataggioTavoloTecnico(){
var folderName = 'tavoloTecnico';
var p = 0;
var f1s= DriveApp.getFoldersByName(folderName).next().getFiles();
while (f1s.hasNext()) {
var f1 = f1s.next();
p++
} Logger.log(p);
var d = new Date();
d.setDate(d.getDate()-1);
var n = d.getFullYear() + "/" + addZero(d.getMonth()+1) + "/" + addZero(d.getDate());
var query = 'in:anywhere has:attachment filename:XLS newer_than:5d (from:mariano.casillo#mit.gov.it OR from:donato.castigliego#mit.gov.it OR from:luciano.aloia#mit.gov.it)';
//var query = 'in:anywhere has:attachment filename:xls '+ 'after:'+n+' (from:mariano.casillo#mit.gov.it OR from:donato.castigliego#mit.gov.it OR from:luciano.aloia#mit.gov.it)';
var elenco = GmailApp.search(query);
var quanteMail = elenco.length; Logger.log(quanteMail);
labelName = GmailApp.createLabel('Movimenti - Tavolo tecnico');
for (var i = 0 ; i < quanteMail; i++) {
//for ( var i in elenco) {
elenco[i].addLabel(labelName);
var thr = elenco[i];
var nn = thr.getMessageCount();
Logger.log(nn);
var mesgs = thr.getMessages();
var www = mesgs.length;
for(var j = 0 ; j < www ; j ++){
var attachments = mesgs[j].getAttachments();
var rrr = attachments.length;
for(var k = 0 ; k < rrr ; k ++) {
var attachment = attachments[k];
var attachmentBlob = attachment.copyBlob();
var file = DriveApp.createFile(attachmentBlob);
DriveApp.getFoldersByName(folderName).next().addFile(file);
}
}
}
var c = 0;
var f2s = DriveApp.getFoldersByName(folderName).next().getFiles();
while (f2s.hasNext()) {
var f2 = f2s.next();
c++
}
if ( c > p) { GmailApp.sendEmail("me#me.com", " avviso "+folderName, "Un nuovo file Γ¨ stato aggiunto")};
}

I still don't know why the search by code return more messages out of the parameters, but I workaround it by search in the "wrong" messages only those I need by parse the date, like this, and now it works:
......
var threads = GmailApp.search(query);
for ( var i in threads) {
threads[i].addLabel(labelName);
var mesgs = threads[i].getMessages();
var www = mesgs.length;
for(var j = 0 ; j < www ; j ++){
if ( mesgs[j].getDate() < d ){} else {
var attachments = mesgs[j].getAttachments();
var rrr = attachments.length;
for(var k = 0 ; k < rrr ; k ++) {
var attachment = attachments[k];
var attachmentBlob = attachment.copyBlob();
var file = DriveApp.createFile(attachmentBlob);
DriveApp.getFoldersByName(folderName).next().addFile(file);
}
}
}
}
.......

Related

How to prevent duplicate emails being added to google sheet - App Script

I am new to App Script. My code is below. I have been trying to take data out of an email and put it into different columns in google sheets. I have managed to achieve this and it works but because labels are applied to threads I get duplicates!
I have tried to figure out how to stop this from happening by using the email ID, date etc but I haven't been successful. Any help would be greatly appreciated.
function email_sheet() {
var ss = SpreadsheetApp.openById("");
var sheet = ss.getSheetByName("Sheet1");
var label = GmailApp.getUserLabelByName("ChosenLabel");
var threads = label.getThreads();
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var date = messages[j].getDate();
var body = messages[j].getPlainBody();
var name = "";
var accnum = "";
var paytype ="";
var amount = "";
var status = "";
/** Break Down the Email */
if(body.indexOf("Recipient : ")>0) {
var end = body.substring(body.indexOf("Recipient : ")+12,body.length);
name = end.substring(0, end.indexOf("\n"));
}
if(body.indexOf("AN")>0) {
var end = body.substring(body.indexOf("AN")+2,body.length);
account = end.substring(0, end.indexOf("\n"));
var [accnum, paytype] = account.split(" ");
}
if(body.indexOf("Amount : ")>0) {
var end = body.substring(body.indexOf("Amount : ")+9,body.length);
amount = end.substring(0, end.indexOf("\n"));
}
if(body.indexOf("Transaction Status : ")>0) {
var end = body.substring(body.indexOf("Transaction Status : ")+21,body.length);
status = end.substring(0, end.indexOf("\n"));
}
sheet.appendRow([date, name, accnum, paytype, amount, status]);
}
threads[i].removeLabel(label);
threads[i].addLabel(GmailApp.getUserLabelByName("All Transactions"))
}
} ```
You can for instance limit to unread mails and at the end mark them as already read, for instance
function mail() {
var requete ="is:unread {label:ChosenLabel label:OtherLabel}"
var ss = SpreadsheetApp.getActive().getSheetByName("Mail");
var threads = GmailApp.search(requete);
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var j = 0; j < messages.length; j++) {
var msg = messages[j].getPlainBody();
var sub = messages[j].getSubject();
var dat = messages[j].getDate();
ss.appendRow([dat, sub, msg])
}
}
GmailApp.markThreadsRead(threads);
}

How can I extract Information in a Google Sheet from a xlsx gmail attachment via google apps script [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 months ago.
Improve this question
I want to extract the content from an xlsx gmail attachment via google apps script. And then put the information into a Google Sheet. It's working fine for CSV files, but I don't get the content of a xlsx file.
Unlike csv files, xlsx file data cannot be directly inserted into a spreadsheet
What you can do instead:
Save the attachment on your disc in its original mimeType
Convert it to a Google Sheets document with e.g. Drive.Files.copy
Delete the excel file from your disc
Sample:
function GmailToDrive() {
var threads = GmailApp.getInboxThreads();
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
var blob = attachment.getAs(attachment.getContentType());
blob.setName(attachment.getName())
var excel = DriveApp.createFile(blob);
Drive.Files.copy({mimeType: MimeType.GOOGLE_SHEETS}, excel.getId());
excel.setTrashed(true)
}
Note that Drive is an advances service that needs to be enabled beforehand.
You can extract data directly from MS Excel files stored in Google Drive or in Gmail attachment without any upload or conversion to Google Spreadsheet. πŸŽ‰πŸΎπŸ₯³
Since xlsx workbooks are zipped XML files you can unzip the xlsx blob, process the XML files and extract data needed like this.
/**
* Parsing MS Excel files and returns values in JSON format.
*
* #param {BlobSource} blob the blob from MS Excel file
* #param {String[]} requiredSheets the array of required sheet names (if omitted returns all)
* #return {Object} Object of sheet names and values (2D arrays)
*/
function parseMSExcelBlob(blob, requiredSheets){
var col_cache = {};
var forbidden_chars = {
"<": "<",
">": ">",
"&": "&",
"&apos;": "'",
""": '"'
};
blob.setContentType("application/zip");
var parts = Utilities.unzip(blob);
var relationships = {};
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/_rels/workbook.xml.rels" ){
var txt = part.getDataAsString();
var rels = breakUpString(txt, '<Relationship ', '/>');
for( var i = 0; i < rels.length; i++ ){
var rId = breakUpString(rels[i], 'Id="', '"')[0];
var path = breakUpString(rels[i], 'Target="', '"')[0];
relationships[rId] = "xl/" + path;
}
}
}
var worksheets = {};
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/workbook.xml" ){
var txt = part.getDataAsString();
var sheets = breakUpString(txt, '<sheet ', '/>');
for( var i = 0; i < sheets.length; i++ ){
var sh_name = breakUpString(sheets[i], 'name="', '"')[0];
sh_name = decodeForbiddenChars(sh_name);
var rId = breakUpString(sheets[i], 'r:id="', '"')[0];
var path = relationships[rId];
if( path.includes("worksheets") ){
worksheets[path] = sh_name;
}
}
}
}
requiredSheets = Array.isArray(requiredSheets) && requiredSheets.length && requiredSheets || [];
var worksheets_needed = [];
for( var path in worksheets ){
if( !requiredSheets.length || requiredSheets.includes(worksheets[path]) ){
worksheets_needed.push(path);
}
}
if( !worksheets_needed.length ) return {"Error": "Requested worksheets not found"};
var sharedStrings = [];
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/sharedStrings.xml" ){
var txt = part.getDataAsString();
txt = txt.replace(/ xml:space="preserve"/g, "");
sharedStrings = breakUpString(txt, '<t>', '</t>');
for( var i = 0; i < sharedStrings.length; i++ ){
sharedStrings[i] = decodeForbiddenChars(sharedStrings[i]);
}
}
}
var result = {};
for( var part of parts ){
var part_name = part.getName();
if( worksheets_needed.includes(part_name) ){
var txt = part.getDataAsString();
var cells = breakUpString(txt, '<c ', '</c>');
var tbl = [[]];
for( var i = 0; i < cells.length; i++ ){
var r = breakUpString(cells[i], 'r="', '"')[0];
var t = breakUpString(cells[i], 't="', '"')[0];
if( t === "inlineStr" ){
var data = breakUpString(cells[i].replace(/ xml:space="preserve"/g, ""), '<t>', '</t>')[0];
data = decodeForbiddenChars(data);
}else if( t === "s" ){
var v = breakUpString(cells[i], '<v>', '</v>')[0];
var data = sharedStrings[v];
}else{
var v = breakUpString(cells[i], '<v>', '</v>')[0];
var data = Number(v);
}
var row = r.replace(/[A-Z]/g, "") - 1;
var col = colNum(r.replace(/[0-9]/g, "")) - 1;
if( tbl[row] ){
tbl[row][col] = data;
}else{
tbl[row] = [];
tbl[row][col] = data;
}
}
var sh_name = worksheets[part_name];
result[sh_name] = squareTbl(tbl);
}
}
function decodeForbiddenChars(txt){
for( var char in forbidden_chars ){
var regex = new RegExp(char,"g");
txt = txt.replace(regex, forbidden_chars[char]);
}
return txt;
}
function breakUpString(str, start_patern, end_patern){
var arr = [], raw = str.split(start_patern), i = 1, len = raw.length;
while( i < len ){ arr[i - 1] = raw[i].split(end_patern, 1)[0]; i++ };
return arr;
}
function colNum(char){
if( col_cache[char] ) return col_cache[char];
var alph = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", i, j, result = 0;
for( i = 0, j = char.length - 1; i < char.length; i++, j-- ){
result += Math.pow(alph.length, j) * (alph.indexOf(char[i]) + 1);
}
col_cache[char] = result;
return result;
}
function squareTbl(arr){
var tbl = [];
var x_max = 0;
var y_max = arr.length;
for( var y = 0; y < y_max; y++ ){
arr[y] = arr[y] || [];
if( arr[y].length > x_max ){ x_max = arr[y].length };
}
for( var y = 0; y < y_max; y++ ){
var row = [];
for( var x = 0; x < x_max; x++ ){
row.push(arr[y][x] || arr[y][x] === 0 ? arr[y][x] : "");
}
tbl.push(row);
}
return tbl.length ? tbl : [[]];
}
return result;
}
Using the function parseMSExcelBlob(blob, requiredSheets) you can put the data in a gsheet.
function getDataFromGmail(){
var threads = GmailApp.getInboxThreads();
var message = threads[0].getMessages()[0];
var attachment = message.getAttachments()[0];
var blob = attachment.copyBlob();
// if second parameter is not provided all sheets will be parsed
var data = parseMSExcelBlob(blob, ["Funny corgi names"]);
// here we have the data in 2D array
var tbl = data["Funny corgi names"];
// putting data into the sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName("Corgi names");
sh.clearContents();
sh.getRange(1, 1, tbl.length, tbl[0].length).setValues(tbl);
}
Also find it in this GitHub repo.

How can I get the all messages in the inbox? (include reply)

i use the following code in Google Apps Script and i wanna get all messages in the inbox. This code gives "Cannot convert Array to number[][]. (line 19, file "Code")" error. How can i fix this code?
var myspreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = myspreadsheet.getSheets()[0];
var start = 0;
var max = 19;
var count = 0;
while (count < 7) {
var threads = GmailApp.getInboxThreads(start, max);
var messages = GmailApp.getMessagesForThreads(threads);
//var froms = [];
messages.get
for (var i = 0; i < threads.length; i++) {
var thisThread = threads[i];
var messages = thisThread.getMessages();
var messageCount = thisThread.getMessageCount();
for ( var m = 0; m<=messageCount; m++) {
var lastMessage = messages[m];
froms = ([lastMessage.getId(), lastMessage.getSubject(), lastMessage.getTo(), lastMessage.getFrom(), lastMessage.getCc(), JSON.stringify(lastMessage.getDate()), lastMessage.getReplyTo()]);
mysheet.getRange(1, 1, froms.length, 7).setValues(froms);
froms = [];
}
}
start = start + 100;
count++;
}
}
Try changing this: froms = ([lastMessage.getId(), lastMessage.getSubject(), lastMessage.getTo(), lastMessage.getFrom(), lastMessage.getCc(), JSON.stringify(lastMessage.getDate()), lastMessage.getReplyTo()]);
to this: froms = ([[lastMessage.getId(), lastMessage.getSubject(), lastMessage.getTo(), lastMessage.getFrom(), lastMessage.getCc(), JSON.stringify(lastMessage.getDate()), lastMessage.getReplyTo()]]);
But really I think you have even bigger problems with your script.
I'd use something like this. But I can't test it very well because I don't keep a lot of junk in my inbox.
function emailsStuff() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheets()[0];
sh.clearContents();
var threads=GmailApp.getInboxThreads()
for(var i=0;i<threads.length;i++) {
var messages=GmailApp.getMessagesForThread(threads[i]);
for(var j=0;j<messages.length;j++) {
var msg=messages[j];
sh.appendRow([msg.getId(), msg.getSubject(), msg.getTo(), msg.getFrom(), msg.getCc(), JSON.stringify(msg.getDate()), msg.getReplyTo()]);
}
}
}

Spliting String and getting appropriate value in JavaScript

I have a string where |||| means next to it is the directory. ||| means the user is allowed to access this directory and || means the files allocated to these users follow.
I need to find allocated file names of a specific user from this string. I have tried to split the string and assign values to an array but I am not able to get the result I'm looking for.
This is the string:
||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx,
And here is my attempt:
function getData() {
var user = 'km11285c';
var value = "||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx,";
var users = null;
var files = null;
var Dir = value.split("||||");
var arrayLength = Dir.length;
for (var i = 0; i < arrayLength; i++) {
users = Dir[i].split("|||");
}
return users;
}
console.log(getData());
and the jsFiddle
I changed your jsfiddle example a bit so maybe you need to change the code here and there, but something like this should work:
function buildTree(data) {
var tree = [];
var dirs = data.split("||||");
// Remove the first entry in the array, since it should be empty.
dirs.splice(0, 1);
for (var i = 0; i < dirs.length; ++i) {
var tempArray = dirs[i].split("|||");
var dirName = tempArray[0];
var usersAndFiles = tempArray[1];
tempArray = usersAndFiles.split("||");
var users = tempArray[0];
var files = tempArray[1];
var treeDir = { name: dirName };
treeDir.users = users.split(",");
treeDir.files = files.split(",");
tree.push(treeDir);
}
return tree;
}
function getData() {
var user = 'km11285c';
var value="||||Root|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,||||1400842226669|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,||||1401191909489|||adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,km11285c,km61052,km61639c,adil001,kl04707c,km47389,km58184,km61052,kq61023c,||LimitTest_20140528164643.xlsx,testTask2_20140528140033.xlsx,testTask1_20140528135944.xlsx,testTask2_20140528140033.xlsx,LimitTest_20140528164643.xlsx,";
var tree = buildTree(value);
for (var i = 0; i < tree.length; ++i) {
var dir = tree[i];
if (dir.users.indexOf(user) >= 0) {
console.log("User '" + user + "' has access to directory '" + dir.name + "', which contains these files: " + dir.files.join(","));
}
}
}
getData();

Getting error while Exporting html table to excel

Im getting the following error while exporting an html table to excel;
SCRIPT429: Automation server can't create object...
This function was working fine but when i restarted my pc and the the application it stopped working not sure whats going on.
function write_to_excel() {
str = "";
var myTable = document.getElementById('myTable');
var rows = myTable.getElementsByTagName('tr');
var rowCount = myTable.rows.length;
var colCount = myTable.getElementsByTagName("tr")[0]
.getElementsByTagName("th").length;
var ExcelApp = new ActiveXObject("Excel.Application"); //Debug shows error at this line
var ExcelWorkbook = ExcelApp.Workbooks.Add();
var ExcelSheet = ExcelWorkbook.ActiveSheet;
ExcelApp.Visible = true;
ExcelSheet.Range("A1", "Z1").Font.Bold = true;
ExcelSheet.Range("A1", "Z1").Font.ColorIndex = 23;
// Format table headers
for ( var i = 0; i < 1; i++) {
for ( var j = 0; j < colCount - 1; j++) {
str = myTable.getElementsByTagName("tr")[i]
.getElementsByTagName("th")[j].innerHTML;
ExcelSheet.Cells(i + 1, j + 1).Value = str;
}
ExcelSheet.Range("A1", "Z1").EntireColumn.AutoFit();
}
for ( var i = 1; i < rowCount; i++) {
for ( var k = 0; k < colCount - 1; k++) {
str = rows[i].getElementsByTagName('td')[k].innerHTML;
ExcelSheet.Cells(i + 1, k + 1).Value = myTable.rows[i].cells[k].innerText;
}
ExcelSheet.Range("A" + i, "Z" + i).WrapText = true;
ExcelSheet.Range("A" + 1, "Z" + i).EntireColumn.AutoFit();
}
return;
}
Automation server can't create object.
Means your ActiveX settings are too high so the code will not run.

Categories