1
votes

Background: I get an email every 6 hours that has hourly logs in the body and I want to put each hourly log into the same spreadsheet so I can scan hour to hour quickly over long periods. I also get random "alarm" emails, which I want to add to that spreadsheet. What I've done: When those emails come in, I apply one of two filters in my work gmail account. One for the alarms, and one for the logs. The filters archive and adds one of two labels to the emails. I have a spreadsheet saved in my team drive, which has a couple of scripts embedded in it. One script runs every minute, looking for the emails with the alarm label. The other script runs every 6 hours, looking for the emails with the log label. Both scripts take any found emails, processes them, removes the label and adds a "processed" label.

PROBLEM: Both scripts seem to be randomly processing the emails between 2 and 4 times. They never do this when I run them manually.

QUESTION: Why is it behaving this way?
(EDIT): I think it's behaving this way because when a new email comes in, it matches the filter and it applies the label to the entire thread, which then causes the script to process the entire thread, instead of just the newest email.

NEW QUESTION: How do I stop this without having to delete the old email messages?

My problem is different than this one: Google apps script Gmail get message without previous conversation In that question, they are talking about bodies of previous messages in the bodies of current messages. In mine, there is no repeat. Each email message is completely new from all previous messages, with no part of previous messages included. They just all have the same sender, subject, and therefor label.

Here's my code:

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName ="Current Month";
var s = ss.getSheetByName(sheetName);
var myLabel = "tower123"; 
var newLabel = "Processed"; 
var regExp = new RegExp(/(Snapshot taken[\S\s]*?Probe: \d+ \*F)/gmi); 
var keys = ["Snapshot taken at: ","Meters: Power Output","Status: Generator ",": ATS to ",": Tower Lights ","Chassis Temperature: ","Temperature: Rack Probe: "]; 

function myFunction() {
  var label = GmailApp.getUserLabelByName(myLabel);
  var label2 = GmailApp.getUserLabelByName(newLabel);
  var threads = label.getThreads();

  // get all the email threads matching myLabel
  for (var i = 0; i < threads.length; i++) {
    var messages = GmailApp.getMessagesForThread(threads[i]);

    // move thread from label to label2
    label2.addToThread(threads[i]);
    label.removeFromThread(threads[i]);

    // get each individual email from the threads
    for (var j = 0; j < messages.length; j++) {
      var bodyText = messages[j].getPlainBody();

      //"move thread" code was here before the noon 2/16 email, moved above for the noon email.  email threads were still processed when they shouldn't have been

      // split the email body into individual "paragraph" strings based on the regExp variable
      while (matches = regExp.exec( bodyText )){
        var logdata = matches[1];        
        for (k in keys){logdata = logdata.replace(keys[k],"");}

        // split out each "paragraph" string into an array
        var lines = logdata.split(/[\r\n]+/);
        for (l in lines){lines[l] = lines[l].trim();}
        for (l in lines){lines[l] = lines[l].replace(/^(\:\s)/,"");}

        // Turn the first element in the array into a date element, format it, and put it back
        lines[0] = Utilities.formatDate(new Date(lines[0]), "MST", "M/d/yy HH:mm");

        // Write the created array to a new row at the end of the 's' sheet
        Logger.log(lines);
        s.appendRow(lines);
      }
    }
  }
  var sheet = ss.getSheets()[0];
  var range = sheet.getRange("A2:Z");
  range.sort(1);
  // Set the date format of column A, from A2 onward
  // This forces the edge case of hour 00:00 to display
  // var column = s.getRange("A2:A");
  // column.setNumberFormat("M/d/yy HH:mm");
}

function alarmFunction(){
  var label = GmailApp.getUserLabelByName("toweralarms123");
  //Logger.log(label);
  var label2 = GmailApp.getUserLabelByName("Processed");
  if(label) {
    Logger.log("Yes label: "+label);
    var threads = label.getThreads();
    var a=[];

    for (var i = 0; i < threads.length; i++) {
      var messages = GmailApp.getMessagesForThread(threads[i]);
      for (var j = 0; j < messages.length; j++) {
        label2.addToThread(threads[i]);
        label.removeFromThread(threads[i]); 
        var date = [messages[j].getDate()]; // date/time
        a[j]=parseMail(messages[j].getPlainBody(),date);
      }
    }
  }
  else{Logger.log("No label: "+label);}
}

function parseMail(body,date) {
 if(body == "" || body == undefined){
  var body = document.getElementById("input").value
  }
  var a=[];
  var alarmKeys = "This is an email alarm";
  var keys=alarmKeys.split(",");
  var i,p,r;
  for (i in keys)  {
    p=alarmKeys+"[\r\n]*([^\r^\n]*)[\r\n]";
    r=new RegExp(p,"m");
    a[i]=body.match(p)[1];
  }
  date.push(a.toString());
  s.appendRow(date);
}
1

1 Answers

1
votes

Answer: There is no really simple way to do this due to the way that gmail labels are applied to messages when using "Conversation View". The work-around I came up with involves creating an array of the data from the new email messages (which also unfortunately includes the data from the rest of the thread, upwards of 99 other messages). Then a second array is created containing all of the data from the spreadsheet. These two arrays are compared to each other and only the unique items are retained and ultimately added to the spreadsheet.

var ss = SpreadsheetApp.getActiveSpreadsheet();
// var s = ss.getActiveSheet();
var sheetName ="Current Month";
var s = ss.getSheetByName(sheetName);
var myLabel = "To Process"; // Name of current label being processed, this label is set via a filter in Gmail
var newLabel = "Processed"; // Name of "New" filter, this label needs to be created in Gmail first
var regExp = new RegExp(/(Snapshot taken[\S\s]*?Probe: \d+ \*F)/gmi); // regular expression used to find each "paragraph"
var keys = ["Snapshot taken at: ","Status: Generator ",": ATS to ",": Tower Lights ","Chassis Temperature: ","Temperature: Rack Probe: "]; // array keys to match on inside paragraphs

function myFunction() {
  var label = GmailApp.getUserLabelByName(myLabel);
  var label2 = GmailApp.getUserLabelByName(newLabel);
  var threads = label.getThreads();
  var data2 = [];
  var newData = [];

  // get all the email threads matching myLabel
  for (var i = 0; i < threads.length; i++) {
    var messages = GmailApp.getMessagesForThread(threads[i]);

    // move thread from label to label2
    label2.addToThread(threads[i]);
    label.removeFromThread(threads[i]);

    // get each individual email from the threads
    for (var j = 0; j < messages.length; j++) {
      var bodyText = messages[j].getPlainBody();

      // split the email body into individual "paragraph" strings based on the regExp variable
      while (matches = regExp.exec( bodyText )){
        var logdata = matches[1];        
        for (k in keys){logdata = logdata.replace(keys[k],"");}

        // split out each "paragraph" string into an array
        var lines = logdata.split(/[\r\n]+/);
        for (l in lines){lines[l] = lines[l].trim();}
        for (l in lines){lines[l] = lines[l].replace(/^(\:\s)/,"");}

        // Turn the first element in the array into a date element, format it, and put it back
        lines[0] = Utilities.formatDate(new Date(lines[0]), "MST", "M/d/yy HH:mm");

        // Put the array to a new item in the data2 array for further processing
        data2.push(lines);
      }
    }
  }
  // Compare the information in the data2 array to existing information in the sheet
  var data = s.getRange("A2:G").getValues(); //Change this to fit your data ranges
  for(i in data2){
    var row = data2[i];
    var duplicate = false;
    for(j in data){
      data[j][0] = Utilities.formatDate(new Date(data[j][0]), "MST", "M/d/yy HH:mm");
      if(row.join() == data[j].join()){
       duplicate = true;
      }
    }
    if(!duplicate){
      newData.push(row);
    }
  }
  if (newData.length){  // runs the below code only if there is newData, this stops an error when newData is empty
    s.getRange(s.getLastRow()+1, 1, newData.length, newData[0].length).setValues(newData); //writes newData to end of sheet
    s.getRange("A2:Z").sort(1); //sorts the sheet
  }
}

And included below is a snippet of the emails that would be processed:

This is an email update

Snapshot taken at: 7:00:00 2/6/2018
        Status: Generator OFF
              : ATS to SRP
              : Tower Lights ON
        Chassis Temperature: 73.77 *F
        Temperature: Rack Probe: 78 *F

Snapshot taken at: 8:00:00 2/6/2018
        Status: Generator OFF
              : ATS to SRP
              : Tower Lights OFF
        Chassis Temperature: 71.32 *F
        Temperature: Rack Probe: 78 *F