Until the server sends the untagged EXPUNGE, the message is NOT expunged in that session. Consequently, the server MUST NOT send an untagged EXISTS response which reflects the action of an expunge before sending the untagged EXPUNGE, and the server MUST respond to a FETCH of that message with the data for that message.
This is an absolute requirement of the IMAP protocol specification. As you noted, this could result in a "hole", in which a message has been expunged but you can't announce it to the client yet, and the client might try to fetch a message in the "hole". Ideally, you should keep a "ghost" of the expunged message in each session that is in this situation, and use the ghost to supply data to respond to any fetch. This is what most clients will expect. RFC 2180 suggests some other strategies, but they do not work as well. The unix.c driver does not allow shared access, so the issue does not come up. Look at how mbx.c works instead.
