0
votes

I'm encountering a issue using the GetFolder function of MailKit using multiple threads. The case is them I'm running a thread that will move my emails around (which among other function does use the GetFolder to find my source folder and destionation folder for the email to move), and another thread that will search for an email while the first one is running (the second thread does you GetFolder function too).

Most of the times I'm getting an InvalidOperationException telling me that "The ImapClient is currently busy processing a command."

How can I ensure that this won't happen?? I try'd to change all my GetFolder and other MailKit operations to Async, and wait for the task to complete, but without any luck of doing this more or less simultanous.

I'm using the same ImapClient for both threads.

1
Wouldn't searching be affected by the moving of stuff around? You could make the operations synchronous, is that not an option? - synepis
Yes, the serach might be affected by the move operation. The problem by doing this sync. is, that I got two different services telling me what to do (one tells me to move, and the other one want to read). Otherwise I should consider building a queue oin my own, and process operations through that queue. - grmihel
Well, I think then you have your solution. Implement a concurrent queue (there is one in .NET) which will execute functions, you pass into it, one after the other. - synepis

1 Answers

5
votes

As mentioned in the comments above, using a queue is probably the right solution here.

I figured that I would comment, though, to point out an important piece of the puzzle for anyone wanting to use MailKit in a multithreaded environment which is that ImapClient and ImapFolder have a shared SyncRoot property (ImapClient.SyncRoot and ImapFolder.SyncRoot) that is meant to be used for synchronizing the use of a single IMAP connection among multiple threads.

All of the *Async() methods lock the SyncRoot for you, but the non-Async methods do not.

Another thing to keep in mind when using multiple threads with IMAP is that the way IMAP works is that only 1 folder is allowed to be open at any given time, which means that if you have 1 thread trying to move messages from WorkMail into WorkMailArchive and another thread trying to search PersonalMail, you're likely to run into folder selection state race conditions which is why using a queue is probably a better idea.

Edit: As of the 2.0 release, the Async methods no longer do any locking for you. You will have to do it yourself. This is because all of the Async methods are now true async rather than Task.Run() wrappers around the synchronous API.