Getting Gmail labels using javamail
January 29, 2013
I’ve been working with Gmail using javamail library for a long time now, the standard IMAP/SMTP capabilities were quite enough, even to deal with the labels. But recently I decided to also pull the gmail custom attributes: X-GM-THRID and X-GM-LABELS (see Gmail Imap Extensions).
At first it looked like there was no easy way to fetch those custom attributes using the standard javamail FetchProfile mechanism so I went searching in Google.
I found the java-gmail-imap project which was quite encouraging but after studying it more I figured that I did want to use it:
- It incorporated javamail 1.4.4 and I really needed some new 1.5.x functionality
- A lot of original javamail classes if not all were extended/re-written which seemed like an overkill
- Last release was on Mar 23, 2012
So I went exploring further.
I must say that I really do appreciate that so much code these days is open source. Both java-gmail-imap and javamail sources showed me what was really happening under the hood and I came up with a simpler hack which only requires one extended class.
I’ll explain the hack here and if you want my code let me know.
So, for a list of messages that I am reading from Gmail I now do a standard javamail profile fetch:
folder.fetch(msgs, stdFetchProfile);
followed by my custom fetch using IMAPFolder’s doCommand():
final MessageSet[] mSets = MessageSet.createMessageSets(mns); ((IMAPFolder) folder).doCommand(new IMAPFolder.ProtocolCommand() { @Override public Object doCommand(IMAPProtocol p) throws ProtocolException { try { Response[] r = p.fetch(mSets, "X-GM-LABELS X-GM-THRID"); for (int i = 0; i < r.length; i++) { if (!FetchResponse.class.isInstance(r[i])) continue; // Got a FetchResponse. GmailFetchResponse gfr = new GmailFetchResponse( ((FetchResponse) r[i]).toString()); // Use gfr.getNumber() to get the msg number for (int j = 0; j < gfr.getItemCount(); j++) { Item item = gfr.getItem(j); if (X_GM_LABELS.class.isInstance(item)) // get the labels ((X_GM_LABELS) item).x_gm_labels); } } } catch (ProtocolException e) { logError(e.getMessage(), e); } return null; } });
GmailFetchResponse is the class I had to create by extending Javamail’s Response. It’s aware of the X-GM-* attributes and I make it re-parse the response received in the standard FetchResponse. I used only the required part of the java-gmail-imap’s parse() method:
private void parse() throws ParsingException { skipSpaces(); if (buffer[index] != '(') throw new ParsingException( "error in FETCH parsing, missing '(' at index " + index); Vector v = new Vector(); Item i = null; do { index++; // skip '(', or SPACE if (index >= size) throw new ParsingException( "error in FETCH parsing, ran off end of buffer, size " + size); switch (buffer[index]) { case 'X': if (match(X_GM_MSGID.name)) { index += X_GM_MSGID.name.length; i = new X_GM_MSGID(this); } if (match(X_GM_THRID.name)) { index += X_GM_THRID.name.length; i = new X_GM_THRID(this); } if (match(X_GM_LABELS.name)) { index += X_GM_LABELS.name.length; i = new X_GM_LABELS(this); } break; default: } if (i != null) v.addElement(i); } while (buffer[index] != ')'); index++; // skip ')' items = new Item[v.size()]; v.copyInto(items); }
X_GM_LABELS* classes I copied from java-gmail-imap project, they’re very simple. I only added required UTF-7 conversion:
public class X_GM_LABELS implements Item { static final char[] name = { 'X', '-', 'G', 'M', '-', 'L', 'A', 'B', 'E', 'L', 'S' }; public int seqnum; public String[] x_gm_labels; public X_GM_LABELS(GmailFetchResponse r) throws ParsingException { seqnum = r.getNumber(); r.skipSpaces(); x_gm_labels = r.readAtomStringList(); if (x_gm_labels != null) for (int i = 0; i < x_gm_labels.length; i++) try { x_gm_labels[i] = new String( x_gm_labels[i].getBytes("US-ASCII"), "X-MODIFIED-UTF-7"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); break; } } }
That is all. With one additional custom fetch call (which is not a huge overhead) you have read the Gmail attributes for your messages.
I hope this can be useful for others.
-Alexey
Easy deployment for PHP software
November 16, 2010
I discovered Quercus (PHP in Java) a while back and have become quite a fan of the solution. Of cause, one thing is that I personally have shifted to Java from PHP and prefer Java to any interpreting language these days (and that is after having developed the whole Yoxel open source project in PHP) but aside this bias my main reason is “ease of deployment”.
It is sometimes tricky to install PHP software packages because standard PHP configuration that you have on your system may not be enough. For example, Yoxel, depending on the configuration, may require LDAP (–with-ldap), IMAP (–with-imap), JPEG/FREETYPE/PNG (–with-freetype-dir, –with-jpeg-di, –with-png-dir). All that may require custom compilation of PHP itself (and even additional libraries) and complicates life for the person installing the package. I am actually pretty sure many users simply give up because they did not want to compile their PHP from scratch.
With Quercus/Java this problem would be solved. I, as a producer of the software package, can throw all necessary jars into my WAR (including the quercus.jar) and the WAR is ready to be deployed in your app server. No re-compilation of anything required!
One could go even one step further and embed jetty http server in the package then the end user simply starts the app on a port and it runs. No app server is even required! Isn’t this great?
Of cause I have also discovered that some of the 3rd party modules that we use are not working under Quercus so we would have to throw them away and use JVM’s functionality instead. Some rewriting on our side would have to happen if we wanted to keep the full functionality of our software (not much though). But that is probably only better, the package would be leaner.
Anyways, internally we have an installation of Yoxel under Quercus and it works just fine. I hope to productize it some day and make that “easy to deploy” (php for java) package available for download.
-Cheers
Accessing Windows Registry in Java
November 2, 2010
Just wanted to mention this open source project that makes it possible for Java apps to access Windows Registry: http://code.google.com/p/java-registry/
I have been quite successful in retrieving MS Outlook User Profile related settings using this tool. Definitely recommend it.
Bookmark: Sun “cares” about Java developers
November 5, 2009
Here is an interesting blog post, JavaFX: one year later. For Java developers who hoped to adopt JavaFX and integrate it with their Swing applications, this is still a challenge and Sun is not helping. Why?
The last paragraph mentions their VP of marketing, quite interesting:
Wait a minute, according to Eric’s LinkedIn profile, he joined Sun in February ‘08. How long has he been working on JavaFX? That guy, actually, is also an angel investor in a startup called Zoodles, which uses Adobe AIR as the technology for its rich internet application.
Go figure …