I brought this up with Apple and Mirapoint (the providers of our mail server infrastructure) a year and a half ago when I was running 10.3.4. The discussions ended up to a difference of opinion between the two companies concerning the IMAP spec. This has always been a issue with Mail.app ever since I can remember from back in the 10.0 days up until at least 10.4.4.
I will post the tail end of the discussion with the names removed to protect the innocent. I will admit that alot of this stuff is over my head. I also don't know how this applies to other mail servers. I don't think any other IMAP clients that I know of exhibit this read/unread state issue.
FROM APPLE:
Thanks for your patience on this escalation. A Mail.app engineer has reviewed the logs you sent in and determined that the Mirapoint server is returning the wrong response.
Specifically, in return to SELECT their server is returning:
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen NotJunk Junk Forwarded JunkRecorded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen NotJunk Junk Forwarded JunkRecorded \*)]
* 11 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 1057775569]
3 OK [READ-WRITE] Completed
They are using the PERMANENTFLAGS response for session-based IMAP flags, which unfortunately does not abide by the IMAP spec. The engineer has agreed that Mail.app could likely do a better job handling session-based flags but concurrently Mirapoint needs to rev their software to return the appropriate response as per the IMAP spec.
MIRAPOINT'S RESPONSE:
I went through the spec (RFC 2060) and found the following...
IMAP server can allow a client to create permanent flags that can be stored:
Under Section 2.3.2. Flags Message Attribute
A keyword is defined by the server implementation. Keywords do not begin with "\". Servers MAY permit the client to define new keywords in the mailbox (see the description of the PERMANENTFLAGS response code for more information).
Also,
Under Section 6.3.1. SELECT Command
If the client can not change the permanent state of one or more of the flags listed in the FLAGS untagged response, the server SHOULD send a PERMANENTFLAGS response code in an OK untagged response, listing the flags that the client can change permanently.
Also,
Under Section 7.1 Server Responses - Status Responses....
PERMANENTFLAGS Followed by a parenthesized list of flags, indicates which of the known flags that the client can change permanently. Any flags that are in the FLAGS untagged response, but not the PERMANENTFLAGS list, can not be set permanently. If the client attempts to STORE a flag that is not in the PERMANENTFLAGS list, the server will either reject it with a NO reply or store the state for the remainder of the current session only. The PERMANENTFLAGS list can also include the special flag \*, which indicates that it is possible to create new keywords by attempting to store those flags in the mailbox.
Now, referring to the earlier IMAP session (over telnet ) that I had you do:
. select inbox
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen NotJunk Junk JunkRecorded Forwarded)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen NotJunk Junk JunkRecorded Forwarded \*)]
* 12 EXISTS
* 2 RECENT
* OK [UNSEEN 11]
* OK [UIDVALIDITY 1056569562]
. OK [READ-WRITE] Completed
. fetch 1:* flags
* 1 FETCH (FLAGS (\Seen))
* 2 FETCH (FLAGS (\Seen NotJunk))
* 3 FETCH (FLAGS (\Answered \Seen NotJunk))
* 4 FETCH (FLAGS (\Answered \Seen Forwarded))
* 5 FETCH (FLAGS (\Seen))
* 6 FETCH (FLAGS (\Seen))
* 7 FETCH (FLAGS (\Seen))
* 8 FETCH (FLAGS (\Seen))
* 9 FETCH (FLAGS (\Seen))
* 10 FETCH (FLAGS (\Seen))
* 11 FETCH (FLAGS (\Recent))
* 12 FETCH (FLAGS (\Recent))
. OK Completed
As you can see above, "NotJunk", "Forwarded" are the PERMANENTFLAGS defined and stored by Mail.App client, not the session specific flags. According to the snippets that quoted above from the IMAP specs, I think Mirapoint is correct in its PERMANENTFLAGS response.