Search code examples
javagmailjakarta-mailimapgmail-imap

Javax.Mail trying to use gmail's imap extension to access X-GM-MSGID


I'm trying to use the X-GM-EXT-1 IMAP extension created by google for gmail in javax.mail. Doc here https://developers.google.com/gmail/imap/imap-extensions

I'm specifically trying to fetch a sequence of X-GM-MSGID headers using the UID FETCH syntax extension.

The java code I'm using: (I'm using real uids in my command, but for the sake of example, I'm pasting the same range from the doc's example)

Response[] r = (Response[]) folder.doCommand(protocol -> protocol.command("UID FETCH 1:4 (X-GM-MSGID)", null));

This way of declaring an imap command has worked for me for other extensions (ESEARCH specifically)

This is a snippet from the docs which is the source material I'm basing my experiment on.

a008 FETCH 1:4 (X-GM-THRID)
* 1 FETCH (X-GM-THRID 1278455344230334865)
* 2 FETCH (X-GM-THRID 1266894439832287888) 
* 3 FETCH (X-GM-THRID 1266894439832287888)
* 4 FETCH (X-GM-THRID 1266894439832287888)
a008 OK FETCH (Success)

I'm expecting my Response[] object to contain multiple response lines, one for each of the fetched messages, and then the tagged OK FETCH (Success) line. However, I'm only getting one line in my response that is A57 OK Success. I'm unsure what this means, maybe javax.mail isn't doing something as I expect under the hood, or maybe something specific needs to be done to access the full response.

Is there a better way, or more correct way to go about using this extension?

Edit:

Here is an executable example, this printed to the console the output I described. One requirement is that the gmail inbox that is authenticated with the imap store that needs to be passed in must have at least 1 message in the folder so that ESEARCH is able to identify a MIN uid to use.

private void MCVE(IMAPStore store) throws MessagingException {
    IMAPFolder inbox = (IMAPFolder) store.getFolder("Inbox");
    inbox.open(Folder.READ_ONLY, ResyncData.CONDSTORE);

    Response[] minUidResponse = (Response[]) inbox.doCommand(
            protocol -> protocol.command("UID SEARCH RETURN (min max count all) 1:*", null)
    );

    String minUid = "";
    for (Response aLine : minUidResponse) {
        String str = aLine.toString();
        if (str.startsWith("* ESEARCH")) {
            List<String> tokens = Arrays.asList(str.split(" "));
            minUid = tokens.get(tokens.indexOf("MIN") + 1);
        }
    }

    final String finalMinUid = minUid; // lambas need effectively final stuff
    Response[] gidResponse = (Response[]) inbox.doCommand(
            protocol -> protocol.command("UID FETCH " + finalMinUid + " (X-GM-MSGID)", null)
    );

    System.out.println("Printing result of X-GM-MSGID uid fetch");
    for (Response r : gidResponse) {
        System.out.println(r.toString());
    }
}

Edit 2:

After enabling debug mode in the mail session, I see that an exception is being thrown and hidden from regular output.

 DEBUG IMAP: connection available -- size: 1
 A4 ENABLE CONDSTORE
 * ENABLED
 A4 OK Success
 A5 EXAMINE Inbox (CONDSTORE)
 * FLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing)
 * OK [PERMANENTFLAGS ()] Flags permitted.
 * OK [UIDVALIDITY 1] UIDs valid.
 * 7 EXISTS
 * 0 RECENT
 * OK [UIDNEXT 23071] Predicted next UID.
 * OK [HIGHESTMODSEQ 1327692]
 A5 OK [READ-ONLY] Inbox selected. (Success)
 A6 UID SEARCH RETURN (min max count all) 1:*
 * ESEARCH (TAG "A6") UID COUNT 7 MIN 23064 MAX 23070 ALL 23064:23070
 A6 OK SEARCH completed (Success)
 A7 UID FETCH 23064 (X-GM-MSGID)
 * 1 FETCH (X-GM-MSGID 1594485864262816838 UID 23064 MODSEQ (1327330))
 DEBUG IMAP: ignoring bad response, THROW:
 com.sun.mail.iap.ParsingException: error in FETCH parsing, unrecognized item at index 11, starts with "X-GM-MSGID 159448586..."
     at com.sun.mail.imap.protocol.FetchResponse.parse(FetchResponse.java:219)
     at com.sun.mail.imap.protocol.FetchResponse.<init>(FetchResponse.java:96)
     at com.sun.mail.imap.protocol.IMAPProtocol.readResponse(IMAPProtocol.java:392)
     at com.sun.mail.iap.Protocol.command(Protocol.java:354)
     at my.package.ImapSync.lambda$MCVE$5(ImapSync.java:85)
     at com.sun.mail.imap.IMAPFolder.doProtocolCommand(IMAPFolder.java:3784)
     at com.sun.mail.imap.IMAPFolder.doCommand(IMAPFolder.java:3734)
     at my.package.ImapSync.MCVE(ImapSync.java:84)
     ...
 A7 OK Success


 Printing result of X-GM-MSGID uid fetch
 A7 OK Success

Edit 3:

The version of javamail I'm using is 1.5.5. I'm going to attempt to upgrade to 1.6.1 to see if that changes anything with how the server response is parsed.

A quick test of the same example code after upgrading to 1.6.1 still had the same result. So this isn't something that has been "fixed" with time. (Quotes because I don't know if javamail has a bug, or if I'm misusing it)


Solution

  • You're doing it the hard way. Just use the "gimap" protocol provider for JavaMail.