Don't be lazy, read the IMAP RFC instead of guessing how things work based on what a couple of servers send you. If you don't fully understand the RFC, ask about it in the IMAP protocol mailing list. When you implement your input parsing, pay special attention to ABNF rules. You might be surprised at some things that server is allowed to send you. For example just because servers usually list mailbox names with quoted strings, it doesn't mean that listing them with literals isn't allowed. Also reply to BODY can be NIL or "hello" just as well as a literal.
IMAP allows simultaneous access for multiple clients to a mailbox. Don't expect that you're the only one accessing it. If you're using multiple clients, it's very annoying when \Seen flags aren't synchronized between the clients. If your client does changes to mailbox state, send them immediately to the server, and also show changes sent by the server immediately to the user.
Don't ignore unexpected untagged replies. Especially EXPUNGE replies must be remembered, and it's not only the EXPUNGE command that can create those replies. UIDVALIDITY changes must also completely invalidate your local mailbox cache, no matter when that happens. You might as well support handling most of the untagged responses, independently on what generated them. For example:
1 NOOP * 1 EXPUNGE * 1 FETCH (FLAGS (\Seen)) * 16 EXISTS * STATUS "imap-list" (MESSAGES 6 UNSEEN 5) * OK [UIDVALIDITY 12345] 1 OK
If you see the following, you should update your internal state:
- The first message was expunged, remove it.
- The new first message (originally the second one) had its flags updated. If the message is visible on screen, update it.
- A new message was added to the mailbox. You'll probably want to add it to your message list.
- "imap-list" mailbox STATUS was changed. If the mailbox is visible and its unseen count is displayed, update the count.
The mailbox's UIDVALIDITY changed. You can no longer trust your cached UIDs. The message sequences haven't changed though, so you can fix your local cache by issuing UID SEARCH 1:* and mapping the messages to the returned new UIDs. Servers rarely send this though, and some servers instead just disconnect the client if this happens. If you don't want to bother implementing the UID SEARCH fix, you can instead just for example disconnect the connection and let your regular UIDVALIDITY-change-on-SELECT handling clear your local cache and redownload everything this.
Commands can fail - deal with it. You may have requested a message that was just expunged from server by another connection. Someone might have deleted the mailbox you just tried to access. In any case, if server replies with NO for a command, you should try to deal with it or show the error message to user. RFC-2180 helps you with figuring out how to handle FETCH and STORE errors. Just don't keep retrying a failed command forever.