OK I managed to make something work. The problem relies in the Command, because fetch command doesn't check the data it received : if your fetch a SUBJECT, you should raise an error if your receive a BODY, or add the result in the unuse list (to handle FLAGS messages).

Attached a quick and dirty patch that handles the problem for FETCH that raises FLAGS messages. Also patch the test for not using defferedResult.

Test looks really nice, and the patch to imap4.py 'almost' looks cool. Help me refresh my memory though... It's possible for responses other than FLAGS to come back unsolicited, isn't it? So to be really correct, the patch needs to account for any response that wasn't explicitly requested? Or am I imagining things?

The already-applied patch is not sufficient. It only recognizes unsolicited FETCH responses which contain only FLAGS, like this (for explanatory purposes the entire RFC822 body of the email is just 0123456789 followed by a CRLF):

With the already-applied patch, such responses cause message data to be dropped from the fetch results, or cause an IllegalServerResponse exception.

I have attached a patch which add tests for FLAGS anywhere inside FETCH responses; I have attached a patch which removes the partial fix to Command from the applied patch and fixes the fetch callbacks to handle FLAGS anywhere inside FETCH responses; and I am reopening this ticket.

The fix to fetchSpecific is a bit ugly, but I don't see how to cleanly fix it without redefining its interface to return a more-fully-parsed result instead of the raw results of parseNestedParens.

I have to agree with exarkun that the IMAP spec requires the client to accept any responses at any time, and to take note of any that it needs to care about. Unfortunately the twisted IMAP4 code in general is not structured to do this.

Fixed in r26486. Since the general parser is used now, there can't be random extra whitespace lying around unless the server tries really hard to put it there. I'm happy for such a case to not be handled by this code (if the server says FETCH foo instead of FETCH foo that's one thing, probably some moron fat fingered it. If the server says FETCH " foo" though, then something fishy is going on).

Handle more unsolicited data received from the server instead of
printing it out and otherwise ignoring it.

In particular, now if unsolicited data is received on the same
line as solicited data, it is separated from the solicited data
and delivered to the appropriate callback. Previously, this case
could cause the entire line to be ignored or it could cause the
unsolicited data to be delivered to the application callback with
the solicited data.