I've found that some of the messages downloaded from the Imap server aren't the same size as what the ImapMessageInfo says they're supposed to be. Initially, I was downloading the message to a MailMessage object and then writing it to disk like this:
var message = _imapClient.GetMailMessage(uniqueId);
message.Save(filePath);
Unfortunately, this parses the data returned into a MailMessage object. When you write the MailMessage to disk, the size is virtually always different from what GetMessageInfo says it should be.
Apparently the MailMessage parser automatically compensates for any oddities it runs into and reorders the resulting MimeMessage when you call message.Save. That actually makes sense, but I didn't see that called out in any of the tutorials, nor was it documented anywhere that I could find.
In an effort to save the messages in a way that the local filesize reflects what the server says, I bypassed using MailMessage as an intermediate object and wrote it directly to disk as follows:
var messageInfo = _imapClient.GetMessageInfo(uniqueId, ImapListFields.Envelope);
var fileLength = _imapClient.GetMessage(message.UniqueId, filePath);
Console.WriteLine($"ImapMessageInfo=[{messageInfo.Length}] bytes. Downloaded Message[{fileLength}] bytes");
This worked for the most part, but I found a message in the mailbox that the Imap server says is 2106 bytes via the ImapMessageInfo. When I download that same message using GetMessage, it comes out as 2137 bytes.
The result of the above code is:
ImapMessageInfo=[2106] bytes. Downloaded Message[2137] bytes
I downloaded this message directly from Gmail using the web client and their copy of the message is saved to disk as 2106 bytes so I'm fairly confident the size returned by GetMessageInfo is correct.
I did a diff on the files and found that while all of the headers look fine, the body of the message directly downloaded has \r as the line terminator for everything after the message headers(which is the last 31 lines of the file). In the one downloaded by Rebex, those same lines are \r\n, which identifies the 32 byte difference.
I added additional logging code to the Imap event handlers to see what was happening and Rebex is definitely retrieving 2137 bytes. Here's the output of that:
Command: R0000A UID FETCH 714995 (UID BODY.PEEK[])
Response: * 189271 FETCH (UID 714995 BODY[] {2137} State[Downloading]: Transferred 0 bytes. Progress:0/2137 bytes
State[Downloading]: Transferred 24 bytes. Progress:24/2137 bytes
State[Downloading]: Transferred 154 bytes. Progress:154/2137 bytes
State[Downloading]: Transferred 412 bytes. Progress:412/2137 bytes
State[Downloading]: Transferred 926 bytes. Progress:926/2137 bytes
State[Downloading]: Transferred 1952 bytes. Progress:1952/2137 bytes
State[Downloading]: Transferred 2137 bytes. Progress:2137/2137 bytes
State[None]: Transferred 0 bytes. Progress:0/0 bytes
Response: ...2137 bytes...
Response: )
My best guess based on this is that these carriage-returns are being converted into CR-LF before they're sent from the server. I got the same result when I used GetMessage to write the data to a MemoryStream instead of a file.
I played around with the _imapClient.Encoding, but that didn't seem to make a difference in the number of bytes being downloaded.
Do you have any ideas for how to get the raw message or is this a known issue without a workaround because it's a problem on Google's side? Any other thoughts on how to keep the local file size the same as what's provided via ImapMessageInfo? Or for all practical purposes, does this not matter at all?
I had planned on using the file size to help figure out whether or not I had a complete and accurate copy of each individual message rather than having downloaded just the headers. But if downloading the entire message still results in a situation where the number of bytes doesn't match, that wouldn't work. Any ideas or help would be appreciated.