I'm writing a prototype for an application that uses MailKit and imap to connect to gmail. It's the first time I've used MailKit and I'm a bit stumped around the best way to do this.
Essentially, I want to write an async method hosted in a class library that downloads emails based on a simple header text search and invokes a callback each time so I can update the GUI. My attempt to do this is given in the following method.
public async Task<IList<IEmail>> EmailQueryAsync(string query, Action<IEmail> callBack)
{
IList<IEmail> result = new List<IEmail>();
using (ImapClient client = new ImapClient())
{
await client.ConnectAsync("imap.gmail.com", 993, true);
client.AuthenticationMechanisms.Remove("XOAUTH2");
await client.AuthenticateAsync(this.userName, this.password);
IMailFolder folder = client.Inbox;
await folder.OpenAsync(FolderAccess.ReadOnly);
IList<UniqueId> uniqueIds = await client.Inbox.SearchAsync(SearchQuery.FromContains(query));
IList<Task<MimeMessage>> messageTasks = uniqueIds.Select(m => client.Inbox.GetMessageAsync(m)).ToList();
while (messageTasks.Count > 0)
{
Task<MimeMessage> messageTask = await Task.WhenAny(messageTasks);
messageTasks.Remove(messageTask);
MimeMessage message = await messageTask;
IEmail email = new Email(date: message.Date, id: message.MessageId, messageBody: message.TextBody, references: message.References);
callBack(email);
result.Add(email);
}
return result;
}
}
However, I feel there is a lot of code for what I want to do - do I really need to call so many async methods to get the messages, is it essential to have everything inside the using statement, or are there any obvious objects that I can cache. Is there a way that I can rewrite this method so I do not have to include the callBack action? Also, I'm a bit unsure about the types of exceptions I can sensibly expect to handle, timeouts etc...