jstedfast / MailKit

A cross-platform .NET library for IMAP, POP3, and SMTP.
http://www.mimekit.net
MIT License
6.15k stars 818 forks source link

IMapFolder.MoveToAsync not returning a UniqueId #1275

Closed DierkDroth closed 2 years ago

DierkDroth commented 2 years ago

Hi,

I got a situation where IMapFolder.MoveToAsync does not return a UniqueId but NULL. The relevant traces show this: 2021-10-18 18:36:35:845 Imap.C: A00000011 UID MOVE 55154 UnusualDONE 2021-10-18 18:36:35:964 Imap.S: * OK [COPYUID 983 ] 2021-10-18 18:36:35:964 Imap.S: A00000011 OK MOVE completed. ... which suggests the move was OK.

However, as I tried the exact same operation again, I get exact same traces again and UniqueId = NULL?!?

1) Was the operation successful? If not, would you have any idea what went wrong? If yes, then why would repeating the exact same operation not fail? 2) In case this operation was successful I needed a new UniqueId, no? How could I get that UniqueId?

Thanks in advance

jstedfast commented 2 years ago

It should not be returning null. That said, null does not mean an error occurred. It just means that the UID is not available.

DierkDroth commented 2 years ago

Thanks @jstedfast

I'm at a loss on that case. Would that mean that the mail with the (old) UniqueId just doesn't exist in the source folder? Or would that be a far fetched assumption? If so, then why would IMAP report "MOVE completed"?

jstedfast commented 2 years ago

A00000011 OK MOVE completed. indicates that the message was moved.

Not all IMAP servers support the UIDPLUS extension, though. If the server does not support UIDPLUS, then it won't return a * OK [COPYUID XXX] message which means MailKit would have no idea what the resulting UID(s) are of the COPY or MOVE methods.

It seems from your log that it is providing that message, so that's why you get it (at least sometimes?).

I'm not sure why it works sometimes and not others unless it doesn't provide the * OK [COPYUID ...] response in some cases.

DierkDroth commented 2 years ago

Thanks for your feedback @jstedfast

FYI I now implemented a logic where - after receiving UniqueId=NULL from .MoveToAsync - would check with .FetchAsync if in fact the message for the UniqueId in question would no longer exist in the source folder. In that case I would ignore UniqueId=null and just assume that a 3rd party moved/deleted that message.

jstedfast commented 2 years ago

If it doesn't throw an exception, then it moved successfully whether it returns null or not.

You don't need to call Fetch().

DierkDroth commented 2 years ago

Hmm ... but how is it then possible that I could call IMapFolder.MoveToAsync as many times as I liked and always would get UniqueId=NULL and the exact same trace above?

jstedfast commented 2 years ago

As I said in my first comment, it should not be returning null with the log that you posted. I don't know why it is... My unit tests test this scenario, so it should be working.

What version are you using?

DierkDroth commented 2 years ago

MailKit 2.15.0

jstedfast commented 2 years ago

Ah, I see the problem...

* OK [COPYUID 983 ]

There should be 3 values in the COPYUID response. Your IMAP server is not responding with a valid COPYUID response.

From the specification (rfc2359):

4.3. COPYUID response code
   Successful COPY and UID COPY commands return a COPYUID response code
   in the tagged OK response whenever at least one message was copied.
   The COPYUID response code contains as an argument the UIDVALIDITY of
   the appended-to mailbox, a message set containing the UIDs of the
   messages copied to the destination mailbox, in the order they were
   copied, and a message containing the UIDs assigned to the copied
   messages, in the order they were assigned.  Neither of the message
   sets may contain extraneous UIDs or the symbol '*'.

   If the server does not support the UIDPLUS capability, the client can
   only discover this information by selecting the destination mailbox
   and issuing FETCH commands.

   Example:    C: A003 COPY 2:4 MEETING
               S: A003 OK [COPYUID 38505 304,319:320 3956:3958] Done
               C: A003 UID COPY 305:310 MEETING
               S: A003 OK Done

5.   Formal Syntax

   The following syntax specification uses the augmented Backus-Naur
   Form (BNF) notation as specified in [RFC-822] as modified by [IMAP4].
   Non-terminals referenced but not defined below are as defined by
   [IMAP4].

   Except as noted otherwise, all alphabetic characters are case-
   insensitive.  The use of upper or lower case characters to define
   token strings is for editorial clarity only.  Implementations MUST
   accept these strings in a case-insensitive fashion.

   resp_code_apnd  ::= "APPENDUID" SPACE nz_number SPACE uniqueid

   resp_code_copy  ::= "COPYUID" SPACE nz_number SPACE set SPACE set
DierkDroth commented 2 years ago

This is a customer's Office 365 server ... oh well ...

jstedfast commented 2 years ago

You can see in the server response that the server added a space after 983, but never added the value(s) after that.

Is the 983 the correct destination UID? Or is it the UIDVALIDITY value for the UnusualDONE folder?

DierkDroth commented 2 years ago

The UniqueId of the mail to move is 55154 (not sure if that's your question though)

jstedfast commented 2 years ago

Right, but what I'm wondering is what is the UID of the message in the folder that it got moved to? Is it 983? Or is 983 the UIDVALIDITY value when you open the folder that you moved the message to?

DierkDroth commented 2 years ago

@jstedfast sorry, I'm not sure I understand your question:

Not sure if this helps...

jstedfast commented 2 years ago

It's not an important question, it's just more me thinking out loud as far as wondering what that numeric value is meant to be.

If you open the targetFolder after moving the message, what is the UidValidity? Is it 983?

If you search for the message in the targetFolder (and by search, I don't necessarily mean via the Search() method), what is the UID of that message? Is it 983?

My guess is that 983 is the UidValidity if the targetFolder if you open it after moving messages into it.

The UidValidity value only becomes known after opening it (just in case you didn't know).

DierkDroth commented 2 years ago

@jstedfast

Yes, in fact targetFolder.UidValidity == 983 after targetFolder.OpenAsync()