3

I've been using RSS2Email to turn Gmail into Google Reader.

I'd like to create a Google Apps Script to do this instead, to get two advantages:

  1. The scheduling would be handled by Google Apps Script. (No need to have a dedicated computer to run the script.)

  2. The resulting emails would be labeled per-feed, nicely organizing things.

Using Google Apps Script would be the same implementation spirit as e.g. Gmail Snooze.


I understand how to fetch the feeds. Where I'm stuck is how to create the emails using a specific label. The approaches I've investigated so far:

  1. The Gmail Service for Google Apps Scripts doesn't allow this, at least not obviously.
    • GmailApp.sendEmail doesn't let you specify a label. Which makes sense since this is for generic email sending. But ...
    • GmailApp.sendEmail returns GmailApp, not something you could use to ID the message and change its label later.
    • The service also doesn't appear to let you create Gmail filters programatically, ruling out another possible way to tackle this.
  2. The Gmail Migration API would be perfect to do this -- but it doesn't work for normal, consumer Gmail accounts. Gah.
  3. Google's IMAP extensions might allow this, but it's unclear to me.

I suppose I could use 1, putting some UID in the Subject that I could use to look up the delivered message, to add the label (and hopefully un-uglify the Subject by removing the UID). But that seems a bit kludgy.

Using 3, IMAP extensions, seems possibly less kludgy, although probably much more work to code and test.

Any recommendations among these? Is there some other API or strategy?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Greg Hendershott
  • 16,100
  • 6
  • 36
  • 53
  • I was thinking of the UID-in-the-Subject trick too. And I agree: ugly . Last resort only. – offby1 Apr 22 '13 at 23:03
  • Aside from ugly, I'm worried about the delay after calling `GmailApp.sendEmail` and it being available in the mailbox to find. – Greg Hendershott Apr 23 '13 at 01:30
  • The more I think about it, the more I think IMAP is the _correct_ way to go. It's just "heavier" than I'd hoped to do in the Google Apps Script environment. – Greg Hendershott Apr 23 '13 at 01:31
  • By the way, I'm _really_ curious to see what you come up with. – offby1 Apr 23 '13 at 05:21
  • @offby1 I have a prototype working in Racket. Because I can do IMAP in Racket. It seems like that's simply not possible in the [Google Apps Script environment](https://developers.google.com/apps-script/overview). As a result, it looks like I can't do this with the process running as a Google Apps Script. – Greg Hendershott Apr 26 '13 at 02:03
  • @offby1 I ran with the Racket approach: http://www.greghendershott.com/2013/05/feeds2gmail.html – Greg Hendershott May 06 '13 at 14:08

3 Answers3

5

The Google Apps Script GmailApp API does not give a way to add a label to a message as you send it, something you can do from the UI. This appears as Issue 1859 in the issue tracker, visit and star it for updates.

A work-around would be to take advantage of the thread apis. If the message is blind-copied (bcc'd) to the sender, it will also appear as a new message in their inbox, where we can use getInboxThreads() to find it. Add the label to this thread, and optionally mark it read then archive it.

Code also available as a gist.

/**
 * An alternative to GmailApp.sendEmail(), which applies a
 * label to the message thread in the sender's account.
 *
 * Sends an email message with optional arguments. The email can
 * contain plain text or an HTML body. The size of the email
 * (including headers, but excluding attachments) may not
 * exceed 20KB.
 *
 * @param {String} recipient    the addresses of the recipient
 * @param {String} subject      the subject line
 * @param {String} body         the body of the email
 * @param {Object} options      a JavaScript object that specifies
 *                              advanced parameters, as documented
 *                              for GmailApp.sendEmail()
 * @param {String} label        the label to be applied
 */
function sendAndLabel(recipient, subject, body, options, label) {
  var sender = Session.getActiveUser().getEmail();

  // Add sender to bcc list
  if (options.bcc) {
    options.bcc = options.bcc.split(',').concat(sender).join(',');
  }
  else {
    options.bcc = sender;
  }

  GmailApp.sendEmail( recipient, subject, body, options )

  // Check if label already exists, create if it doesn't
  var newLabel = GmailApp.getUserLabelByName(label);
  if (!newLabel) newLabel = GmailApp.createLabel(label);

  // Look for our new message in inbox threads
  Utilities.sleep(2000); // Wait for message to be received
  var inboxThreads = GmailApp.getInboxThreads();
  for (var t = 0; t < inboxThreads.length; t++) {
    var foundSubject = inboxThreads[t].getFirstMessageSubject();
    var numLabels = inboxThreads[t].getLabels().length;  // Could add more criteria
    if (foundSubject === subject && numLabels === 0) {
      // Found our thread - label it
      inboxThreads[t].addLabel(newLabel)
                     .markRead()
                     .moveToArchive();
      break;
    }
  }
}

Example of use:

function test_sendAndLabel() {
  var recipient = Session.getActiveUser().getEmail();
  var subject = "Test Labelling";
  var body = "This email is testing message labelling.";
//  var options = {bcc:"someone@example.com"};
  var options = {};
  var label = "LabelTest";
  sendAndLabel(recipient, subject, body, options, label);
}
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
1

yes, IMAP is the right way to go. You can find some third party IMAP lib to easy your job.

the command to add lable is : STORE 123 +X-GM-LABELS (yourLabel)

The official docs about Gmail label :

https://developers.google.com/google-apps/gmail/imap_extensions#access_to_gmail_labels_x-gm-labels

skyfree
  • 867
  • 2
  • 10
  • 29
  • We have made a gmail client based on IMAP, including label manipulation. So, I am sure IMAP can solve your problem. – skyfree Apr 25 '13 at 14:59
  • Agreed. Unfortunately, I don't see how to talk to IMAP from the Google Apps Script environment. AFAICT not only isn't there any IMAP service, there's no TCP service for me to roll it low-level. `UrlFetchApp` is as generic as it gets, and that's only for HTTP. – Greg Hendershott Apr 25 '13 at 15:07
  • You can use the standard [IMAP protocol](http://tools.ietf.org/html/rfc3501) to manipulate your gmail, plus the GMail IMAP extensions. The IMAP protocol do not rely on HTTP, demo code like this: imapClient.ConnectSsl("imap.gmail.com", 993); the tricky part of IMAP is XOAUTH authentication. – skyfree Apr 26 '13 at 00:53
  • So forget the HTTP RESTful API service (which is used for most Google APIs), and turn to IMAP : http://tools.ietf.org/html/rfc3501 Accessing the mailbox does not require any HTTP service, that's why you cannot find a Gmail API, because it is not necessary at all! – skyfree Apr 26 '13 at 01:01
  • Google "IMAP client source code" or search open source projects related IMAP mail client, you will find all you need – skyfree Apr 26 '13 at 01:09
  • Thank you for your comments, but: I do know how to use IMAP, *in general*. But I don't see how to do so *in the Google Apps Script environment*. I don't see any high-level IMAP service, nor do I see any lower-level TCP connection ability with which I could roll my own -- again *in the Google Apps Script environment*. – Greg Hendershott Apr 26 '13 at 01:56
  • [Google Apps Script environment](https://developers.google.com/apps-script/overview). – Greg Hendershott Apr 26 '13 at 01:59
  • Sorry, I cann't figure out how to call IMAP command in Javascript environment. just a suggestion: you can use HTTPWatch or other snipping tool to find out what HTTP package is sent when adding labels on the gmail web page, then you can code script to simulate this operation (send the same package ). This process can be trickey -especially you might need to simulate the authentication process. – skyfree Apr 27 '13 at 07:38
0

It would be convenient for GmailApp.sendEmail() to return a GmailMessage object so we can get its id and then assign a label. It doesn't, but you can use this workaround:

  1. Create the message as a draft using GmailApp.createDraft()

  2. Send the draft message using GmailDraft.send(). This method does return a GmailMessage object.

  3. Assign the label (either assign it to the whole thread with GmailMessage.getThread().addLabel() or if you want to assign it to the individual message, you'll have to use the Advanced Gmail service as described here).

Aaron Dunigan AtLee
  • 1,860
  • 7
  • 18