1

I have 9 separate scripts setup to import CSV attachments from GMAIL to Google Sheets every 5 minutes. I prefer to do this more often, but received a temp ban when trying to execute these every minute. I would also like to eliminate this error if possible: TypeError: Cannot call method "getMessages" of undefined. which is returned when there is no email present to process.

Is there a way to execute each script together with one GMAIL API call as opposed to 9 separate? Same email address, different labels per script. Here's 2 of the 9 scripts executed every 5 minutes:

function STSalesImportFromGmail() { 
  //gets first(latest) message with set label
  var threads = GmailApp.getUserLabelByName('Streeterville Sales').getThreads(0,1);     
  var message = threads[0].getMessages()[0];
  var attachment = message.getAttachments()[0];

  // Is the attachment a CSV file
  attachment.setContentTypeFromExtension();
  if (attachment.getContentType() === "text/csv") {                            
    var ss = SpreadsheetApp.getActive();
    var sh = ss.getSheetByName("Streeterville Sales");
    //parses content of csv to array
    var dataString = attachment.getDataAsString();
    var csvData = CSVToArray(dataString);
    // Remember to clear the content of the sheet before importing new data
    sh.clearContents().clearFormats();                                         
    //pastes array to sheet
    var lastRowValue = sh.getLastRow();
    for (var i = 0; i < csvData.length; i++) {
       sh.getRange(i+lastRowValue+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
    } 
    if( message.getSubject().indexOf('END OF DAY SALES DETAILS') !== -1) {
    STlogTodaysSales()
    }
  //marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
  message.markRead();
  message.unstar();
  Gmail.Users.Messages.remove("me", message.getId()); // Added
    }
}
//The code formats the code so it can be entered into the Google Script

function CSVToArray( strData, strDelimiter ){ 
  // Check to see if the delimiter is defined. If not,
  // then default to comma.
  strDelimiter = (strDelimiter || ",");

  // Create a regular expression to parse the CSV values.
  var objPattern = new RegExp(
    (
      // Delimiters.
      "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +


      // Quoted fields.
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +


      // Standard fields.
      "([^\"\\" + strDelimiter + "\\r\\n]*))"
    ),
    "gi"
  );


  // Create an array to hold our data. Give the array
  // a default empty first row.
  var arrData = [[]];

  // Create an array to hold our individual pattern
  // matching groups.
  var arrMatches = null;

  // Keep looping over the regular expression matches
  // until we can no longer find a match.
  while (arrMatches = objPattern.exec( strData )){

    // Get the delimiter that was found.
    var strMatchedDelimiter = arrMatches[ 1 ];

    // Check to see if the given delimiter has a length
    // (is not the start of string) and if it matches
    // field delimiter. If id does not, then we know
    // that this delimiter is a row delimiter.
    if (
      strMatchedDelimiter.length &&
      (strMatchedDelimiter != strDelimiter)
    ){

      // Since we have reached a new row of data,
      // add an empty row to our data array.
      arrData.push( [] );

    }

    // Now that we have our delimiter out of the way,
    // let's check to see which kind of value we
    // captured (quoted or unquoted).
    if (arrMatches[ 2 ]){

      // We found a quoted value. When we capture
      // this value, unescape any double quotes.
      var strMatchedValue = arrMatches[ 2 ].replace(
        new RegExp( "\"\"", "g" ),
        "\""
      );

    } else {

      // We found a non-quoted value.
      var strMatchedValue = arrMatches[ 3 ];

    }

    // Now that we have our value string, let's add
    // it to the data array.
    arrData[ arrData.length - 1 ].push( strMatchedValue );
  }

  // Return the parsed data.
  return( arrData );
  var label = GmailApp.getUserLabelByName("Streeterville Sales");
  label.deleteLabel();
}
function STLaborImportFromGmail() { 
  //gets first(latest) message with set label
  var threads = GmailApp.getUserLabelByName('Streeterville Labor').getThreads(0,1);     
  var message = threads[0].getMessages()[0];
  var attachment = message.getAttachments()[0];

  // Is the attachment a CSV file
  attachment.setContentTypeFromExtension();
  if (attachment.getContentType() === "text/csv") {                            
    var ss = SpreadsheetApp.getActive();
    var sh = ss.getSheetByName("Streeterville Labor");
    //parses content of csv to array
    var dataString = attachment.getDataAsString();
    var csvData = CSVToArray(dataString);
    var range = sh.getRange("A:K");
    // Remember to clear the content of the sheet before importing new data
  range.clear();
    //pastes array to sheet
    var lastRowValue = sh.getLastRow();
    for (var i = 0; i < csvData.length; i++) {
       sh.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
    } 
    if( message.getSubject().indexOf('END OF WEEK LABOR DETAILS') !== -1) {
    STlogWeeksLabor()
    }
  }

  //marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
  message.markRead();
  message.unstar();
  Gmail.Users.Messages.remove("me", message.getId()); // Added

}
function STlogTodaysSales() {
  var todaysSales = SpreadsheetApp.getActive().getRange('Streeterville Sales Log!STSalesImport');
  var logSheet = todaysSales.getSheet();
  logSheet.appendRow(
    todaysSales.getValues()
    .reduce(function(a, b) { return a.concat(b); }) // flatten the 2D array to 1D
  );
}
function STlogWeeksLabor() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName('Streeterville Labor Log');
  var rg=sh.getRange('STLaborImport');
  var vA=rg.getValues();
  sh.getRange(sh.getLastRow()+1,1,vA.length,vA[0].length).setValues(vA);
}
function SLSalesImportFromGmail() { 
  //gets first(latest) message with set label
  var threads = GmailApp.getUserLabelByName('South Loop Sales').getThreads(0,1);     
  var message = threads[0].getMessages()[0];
  var attachment = message.getAttachments()[0];

  // Is the attachment a CSV file
  attachment.setContentTypeFromExtension();
  if (attachment.getContentType() === "text/csv") {                            
    var ss = SpreadsheetApp.getActive();
    var sh = ss.getSheetByName("South Loop Sales");
    //parses content of csv to array
    var dataString = attachment.getDataAsString();
    var csvData = CSVToArray(dataString);
    // Remember to clear the content of the sheet before importing new data
    sh.clearContents().clearFormats();                                         
    //pastes array to sheet
    var lastRowValue = sh.getLastRow();
    for (var i = 0; i < csvData.length; i++) {
       sh.getRange(i+lastRowValue+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
    } 
    if( message.getSubject().indexOf('END OF DAY SALES DETAILS') !== -1) {
    SLlogTodaysSales()
    }
  //marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
  message.markRead();
  message.unstar();
  Gmail.Users.Messages.remove("me", message.getId()); // Added
    }
}
//The code formats the code so it can be entered into the Google Script

function CSVToArray( strData, strDelimiter ){ 
  // Check to see if the delimiter is defined. If not,
  // then default to comma.
  strDelimiter = (strDelimiter || ",");

  // Create a regular expression to parse the CSV values.
  var objPattern = new RegExp(
    (
      // Delimiters.
      "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +


      // Quoted fields.
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +


      // Standard fields.
      "([^\"\\" + strDelimiter + "\\r\\n]*))"
    ),
    "gi"
  );


  // Create an array to hold our data. Give the array
  // a default empty first row.
  var arrData = [[]];

  // Create an array to hold our individual pattern
  // matching groups.
  var arrMatches = null;

  // Keep looping over the regular expression matches
  // until we can no longer find a match.
  while (arrMatches = objPattern.exec( strData )){

    // Get the delimiter that was found.
    var strMatchedDelimiter = arrMatches[ 1 ];

    // Check to see if the given delimiter has a length
    // (is not the start of string) and if it matches
    // field delimiter. If id does not, then we know
    // that this delimiter is a row delimiter.
    if (
      strMatchedDelimiter.length &&
      (strMatchedDelimiter != strDelimiter)
    ){

      // Since we have reached a new row of data,
      // add an empty row to our data array.
      arrData.push( [] );

    }

    // Now that we have our delimiter out of the way,
    // let's check to see which kind of value we
    // captured (quoted or unquoted).
    if (arrMatches[ 2 ]){

      // We found a quoted value. When we capture
      // this value, unescape any double quotes.
      var strMatchedValue = arrMatches[ 2 ].replace(
        new RegExp( "\"\"", "g" ),
        "\""
      );

    } else {

      // We found a non-quoted value.
      var strMatchedValue = arrMatches[ 3 ];

    }

    // Now that we have our value string, let's add
    // it to the data array.
    arrData[ arrData.length - 1 ].push( strMatchedValue );
  }

  // Return the parsed data.
  return( arrData );
  var label = GmailApp.getUserLabelByName("South Loop Sales");
  label.deleteLabel();
}
function SLLaborImportFromGmail() { 
  //gets first(latest) message with set label
  var threads = GmailApp.getUserLabelByName('South Loop Labor').getThreads(0,1);     
  var message = threads[0].getMessages()[0];
  var attachment = message.getAttachments()[0];

  // Is the attachment a CSV file
  attachment.setContentTypeFromExtension();
  if (attachment.getContentType() === "text/csv") {                            
    var ss = SpreadsheetApp.getActive();
    var sh = ss.getSheetByName("South Loop Labor");
    //parses content of csv to array
    var dataString = attachment.getDataAsString();
    var csvData = CSVToArray(dataString);
    var range = sh.getRange("A:K");
    // Remember to clear the content of the sheet before importing new data
  range.clear();
    //pastes array to sheet
    var lastRowValue = sh.getLastRow();
    for (var i = 0; i < csvData.length; i++) {
       sh.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
    } 
    if( message.getSubject().indexOf('END OF WEEK LABOR DETAILS') !== -1) {
    SLlogWeeksLabor()
    }
  }

  //marks the Gmail message as read, unstars it and deletes it using Gmail API (Filter sets a star)
  message.markRead();
  message.unstar();
  Gmail.Users.Messages.remove("me", message.getId()); // Added

}
function SLlogTodaysSales() {
  var todaysSales = SpreadsheetApp.getActive().getRange('South Loop Sales Log!SLSalesImport');
  var logSheet = todaysSales.getSheet();
  logSheet.appendRow(
    todaysSales.getValues()
    .reduce(function(a, b) { return a.concat(b); }) // flatten the 2D array to 1D
  );
}
function SLlogWeeksLabor() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName('South Loop Labor Log');
  var rg=sh.getRange('SLLaborImport');
  var vA=rg.getValues();
  sh.getRange(sh.getLastRow()+1,1,vA.length,vA[0].length).setValues(vA);
}
Peter Chabot
  • 139
  • 1
  • 9
  • 3
    Please read [Batching Requests | Gmail API](https://developers.google.com/gmail/api/guides/batch) – Rubén Nov 30 '19 at 22:52

2 Answers2

2

You say: I would also like to eliminate this error if possible: TypeError: Cannot call method "getMessages" of undefined.

How about this:

var threads = GmailApp.getUserLabelByName('Streeterville Sales').getThreads(0,1);
if(threads) {
   var message = threads[0].getMessages()[0];
   ...

As for the rest. I think that's a bit too much to ask.

Cooper
  • 59,616
  • 6
  • 23
  • 54
  • Tried using this but still receiving the same error. ``` function STSalesImportFromGmail() { //gets first(latest) message with set label var threads = GmailApp.getUserLabelByName('Streeterville Sales').getThreads(0,1); if(threads) { var message = threads[0].getMessages()[0]; var attachment = message.getAttachments()[0]; } ``` – Peter Chabot Dec 01 '19 at 19:33
  • Well when I get an error like that I start looking closely at what the error says is undefined. I think that's where you should look. – Cooper Dec 01 '19 at 19:40
2

Your problem

I would also like to eliminate this error if possible: TypeError: Cannot call method "getMessages" of undefined. which is returned when there is no email present to process.

Is due to threads being empty.

What you can do to avoid this error is, before trying to use a property of threadscheck if it's !=null.

Add a check like this: if (threads && threads.length>0) before continuing.


In regards to your request to unify all the Gmail API calls, this is a very broad question and unfit for Stack Overflow. Please read How to Ask and this discussion topic on Meta.

ZektorH
  • 2,680
  • 1
  • 7
  • 20