Create Google Tasks by sending email to Google GMail

From Ittichai Chammavanijakul's Wiki
Revision as of 13:18, 22 March 2014 by Ittichai (talk | contribs)
Jump to navigation Jump to search

Goals:

  • Send email to a specified address - in this case to Gmail address named yourgmail+task@gmail.com. (If Gmail ID is ittichai, the email address to send to will be ittichai+task@gmail.com.) Read more about the hidden feature with Gmail - http://gmailblog.blogspot.com/2008/03/2-hidden-ways-to-get-more-from-your.html
  • Script will parse that email based on a Gmail label assigned by filter, and grab the email's subject to create a new Google task.

Instructions:

  • Create two new Gmail labels - newtask and newtaskdone.

create_new_label1.jpg create_new_label2.jpg


  • Create a Gmail filter to apply "newtask" label to all incoming yourgmail+task@gmail.com.

filter1.jpg filter2.jpg


  • Create a new Google Sheet. Enter Processed tasks in cell A1. It will be used to display how many tasks have been processed. Start the Script Editor from Tools menu.

GDoc_Script.jpg

  • Create a new blank project.

create_blank_proj.jpg


  • Copy and paste the whole script here. Note below will walk through the codes.
// Original Source: http://www.pipetree.com/qmacro/blog/2011/10/automated-email-to-task-mechanism-with-google-apps-script/
    // -----------------------------------------------------  
    // Globals, constants  
    // -----------------------------------------------------  
    TASKLIST = "Ittichai's list";  
    LABEL_PENDING = "newtask";  
    LABEL_DONE = "newtaskdone";  
      
    // -----------------------------------------------------  
    // getTasklistId_(tasklistName)  
    // Returns the id of the tasklist specified  
    // Oddly, we should be able to use:  
    // Tasks.Tasklists.get(tasklistName)  
    // but it always gives an error "Invalid Value".  
    // -----------------------------------------------------  
    function getTasklistId_(tasklistName) {  
      var tasklistsList = Tasks.Tasklists.list();  
      var taskLists = tasklistsList.getItems();  
      for (tl in taskLists) {  
        var title = taskLists[tl].getTitle();  
        if (title == tasklistName) {  
          return taskLists[tl].getId();  
        }  
      }  
    }  
      
    // -----------------------------------------------------  
    // processPending(sheet)  
    // Process any pending emails and then move them to done  
    // -----------------------------------------------------  
    function processPending_(sheet) {  
      
      var label_pending = GmailApp.getUserLabelByName(LABEL_PENDING);  
      var label_done = GmailApp.getUserLabelByName(LABEL_DONE);  
      
      // The threads currently assigned to the 'pending' label  
      var threads = label_pending.getThreads();  
      
      // Process each one in turn, assuming there's only a single  
      // message in each thread  
      for (var t in threads) {  
        var thread = threads[t];  
      
        // Grab the task data  
        // This email's subject will be task's title.
        var taskTitle = thread.getFirstMessageSubject();  
        
        // This email's body will be task's body. Most email message now is HTML-based.
        // It is desirable to remove all HTML tags so that only actual content will be populated.
        // Use a custom function getTextFromHtml to strip out all HTML tags.
        // In addition, the string size will be limited to 3000 characters in case an email is very long.
        var taskNote = getTextFromHtml((thread.getMessages()[0]).getBody()).substring(0,3000);
      
        // Insert the task  
        //addTask_(taskTitle, TASKLIST);  
        addTask_(taskTitle, taskNote, TASKLIST);  

        // Set to 'done' by exchanging labels  
        thread.removeLabel(label_pending);  
        thread.addLabel(label_done);  
      }  
      
      // Increment the processed tasks count  
      var processedRange = sheet.getRange("B1");  
      processedRange.setValue(processedRange.getValue() + threads.length)  
    }  
      
    // -----------------------------------------------------  
    // addTask_(title, taskListId)  
    // Create new task and insert into given tasklist  
    // -----------------------------------------------------  
    function addTask_(title, message, tasklistId) {  
      //var newTask = Tasks.newTask().setTitle(title);  
      var newTask = Tasks.newTask();
      newTask.setTitle(title);
      newTask.setNotes(message);  
      Tasks.Tasks.insert(newTask, getTasklistId_(tasklistId));  
    }  
      
    // -----------------------------------------------------  
    // main()  
    // Starter function; to be scheduled regularly  
    // -----------------------------------------------------  
    function main_taskconverter() {  
      
      // Get the active spreadsheet and make sure the first  
      // sheet is the active one  
      var ss = SpreadsheetApp.getActiveSpreadsheet();  
      var sh = ss.setActiveSheet(ss.getSheets()[0]);  
      
      // Process the pending task emails  
      processPending_(sh);  
      
    }  

// Strip out all HTML tags.
// Source: http://stackoverflow.com/questions/8936092/remove-formatting-tags-from-string-body-of-email
function getTextFromHtml(html) {
  return getTextFromNode(Xml.parse(html, true).getElement());
}

function getTextFromNode(x) {
  switch(x.toString()) {
    case 'XmlText': return x.toXmlString();
    case 'XmlElement': return x.getNodes().map(getTextFromNode).join('');
    default: return '';
  }
}

Notes

  • Make sure that the name of the task list in TASKLIST variable is changed to your primary task list name.
    TASKLIST = "Ittichai's list";  
    LABEL_PENDING = "newtask";  
    LABEL_DONE = "newtaskdone";  
  • Integrate the script with Google API.
  • Schedule it via the time-driven even trigger.

Pay attention to the *Integrate the script with Google API* in the *Script Code* section especially if this is your first time coding this. You will have to enable Google API service to allow access the Task API - https://developers.google.com/apps-script/articles/google_apis_reading_list. If not doing so, you will receive an error message saying "Tasks - not defined" when running the script.

In addition to above sample, I'd like to add the email's body into the G! task's note.

Here is what I do:

  • Add a new variable to grab the email's body
        // Grab the task data  
        // This email's subject will be task's title.
        var taskTitle = thread.getFirstMessageSubject();  

        // This email's body will be task's body. Most email message now is HTML-based.
        // It is desirable to remove all HTML tags so that only actual content will be populated.
        // Use a custom function getTextFromHtml to strip out all HTML tags.
        // In addition, the string size will be limited to 3000 characters in case an email is very long.
        var taskNote = getTextFromHtml((thread.getMessages()[0]).getBody()).substring(0,3000);

Most email message now is HTML-based. Without stripping out the HTML tags, the task's note will be populated with many useless tags. I use functions mentioned on this web site http://stackoverflow.com/questions/8936092/remove-formatting-tags-from-string-body-of-email to get only text message. Basically, add these two functions in the script.

function getTextFromHtml(html) {
  return getTextFromNode(Xml.parse(html, true).getElement());
}

function getTextFromNode(x) {
  switch(x.toString()) {
    case 'XmlText': return x.toXmlString();
    case 'XmlElement': return x.getNodes().map(getTextFromNode).join('');
    default: return '';
  }
}
  • Add new parameter of task's note to addTask_
        // Insert the task  
        //addTask_(taskTitle, TASKLIST);  
        addTask_(taskTitle, taskNote, TASKLIST);  
  • Update the addTask_ to include setNotes

Thanks Bernard Goldberger (http://www.linkedin.com/profile/view?id=204142846) for updating script to fix some recent setNotes issue by separating setTitle and setNotes into separate lines.

    function addTask_(title, message, tasklistId) {  
      //var newTask = Tasks.newTask().setTitle(title);  
      //var newTask = Tasks.newTask().setTitle(title).setNotes(message); // 2013-06 Failed at setNotes
      var newTask = Tasks.newTask();
      newTask.setTitle(title);
      newTask.setNotes(message);  
      Tasks.Tasks.insert(newTask, getTasklistId_(tasklistId));  
    }  


Reference: http://www.pipetree.com/qmacro/blog/2011/10/automated-email-to-task-mechanism-with-google-apps-script/