Tuesday, 17 June 2014

Reading mails using IMAP and MailSystem.NET

In this article I will describe how you can use C# and MailSystem.NET to read mails from any IMAP source, including GMail.
MailSystem.NET is a Open SourceGNU Library General Public Licensed library for managing emails using SMTP, POP3, IMAP and many more protocols.
I needed a component that will read mails from an IMAP source and import them intoSitecore. So I built this simple repository to get me all mails from a certain mailbox. Here is how I did it.
First you need to copy ActiveUp.Net.Common.dll and ActiveUp.Net.Imap4.dllfrom the MailSystem.NET package to your /bin/ folder.
Reading from MailSystem.NET is pretty straight forward:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ActiveUp.Net.Mail;
 
namespace PT.MailIntegration.IMAP
{
  public class MailRepository
  {
    private Imap4Client _client = null;
 
    public MailRepository(string mailServer, int port, bool ssl, string login, string password)
    {
      if (ssl)
        Client.ConnectSsl(mailServer, port);
      else
        Client.Connect(mailServer, port);
      Client.Login(login, password);
    }
 
    public IEnumerable<Message> GetAllMails(string mailBox)
    {
      return GetMails(mailBox, "ALL").Cast<Message>();
    }
 
    public IEnumerable<Message> GetUnreadMails(string mailBox)
    {
      return GetMails(mailBox, "UNSEEN").Cast<Message>();
    }
 
    protected Imap4Client Client
    {
      get
      {
        if (_client == null)
          _client = new Imap4Client();
        return _client;
      }
    }
 
    private MessageCollection GetMails(string mailBox, string searchPhrase)
    {
      Mailbox mails = Client.SelectMailbox(mailBox);
      MessageCollection messages = mails.SearchParse(searchPhrase);
      return messages;
    }
  }
}
This repository can now be used to read all mails or all unread mails from a mailbox. The constructor takes the mail server name, port and SSL information, as well as the email address and password of the account to read from. GetAllMails() read all mails from the specified mailbox, while GetUnreadMails() reads all unread mails. Both functions returns a list of Message objects. A Message is the complete email in one object.
To read from a GMail mailbox you need to connect using SSL on port 993:
using ActiveUp.Net.Mail;
using PT.MailIntegration.IMAP;
 
protected void TestMail()
{
  MailRepository rep = new MailRepository("imap.gmail.com", 993, true, @"mailaddress@gmail.com", "password");
  foreach (Message email in rep.GetUnreadMails("Inbox"))
  {
    Response.Write(string.Format("<p>{0}: {1}</p><p>{2}</p>", email.From, email.Subject, email.BodyHtml.Text));
    if (email.Attachments.Count > 0)
    {
      foreach (MimePart attachment in email.Attachments)
      {
        Response.Write(string.Format("<p>Attachment: {0} {1}</p>", attachment.ContentName, attachment.ContentType.MimeType));
      }
    }
  }
}

Other IMAP mail servers might not need SSL, or requires another port number.
When calling GetUnreadMails(), mails will be marked as read afterwards.
Please note that reading using IMAP (at lest from GMail accounts) is very slow. Don’t be surprised if it takes up to a minute to get 30 mails from a mailbox.

Friday, 23 May 2014

Delegate And Async Programming C# (AsyncCallback And Object State)

we discussed the use of delegates to call methods asynchronously then we talked about Synchronization of threads in a Multithreading environment. In the code example we used the BeginInvoke() method to make the Async call.

   //Simple delegate declaration        public delegate int BinaryOp(int x, int y);
       
//An Add() method that do some simple arithamtic operation        public int Add(int a, int b)
        {
            Console.WriteLine("Add() running on thread {0}",Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(500);
            return (a + b);
        }
            BinaryOp bp = new BinaryOp(Add);
            IAsyncResult iftAr = bp.BeginInvoke(5, 5, nullnull);


Just as a reminder, bp is the instance of a BinaryOP delegate that points to a simple Add() method that performs some basic arithmetic operations. We passed the arguments to BeginInvoke() with some null values. Now instead of using null in the parameters you'll use objects which are part of the signature of the BeginInvoke() method of dynamic class of delegate BinaryOp.

BeginInvoke(int x, int y, AsyncCallback cb, Object state);

Let's discuss what the last two parameters are for.

The AsyncCallback Delegate

Rather than polling the delegate to determine whether an asynchronous call is completed using the properties of IAsyncResult object, it would be more efficient to have the secondary inform the calling thread when the task is finished. When you wish to enable this behavior you need to pass an instance of System.AsyncCallback delegate as a parameter to BeginInvoke(), which up until this point has been NULL.

Note: The Callback method will be called on the secondary thread not on the primary Main() thread.

The method that has to be passed into the AsyncCallback delegate should have a void return type and IAsyncResult as a parameter to match the delegate signature.

//Target of AsyncCallback delegate should match the following pattern        public void AddComplete(IAsyncResult iftAr) 
Note: In the previous example we used a Boolean variable in two different threads which is not thread safe. However to use such a shared variable the very good rule of thumb is to ensure that data that can be shared among multiple threads is locked down.

Now when the secondary thread completes the Add() operation, the question should be where am I gonna call the EndInvoke()? Well you can call the EndInvoke in two places.

  1. Inside the main just after the condition where you're waiting for the secondary thread to complete. But this does not satisfy the purpose of passing AsyncCallback.
    public delegate int BinaryOp(int x, int y);
            static void Main(string[] args)
            {
                Console.WriteLine("Main() running on thread {0}",Thread.CurrentThread.ManagedThreadId); 
                Program p=new Program();
                BinaryOp bp = new BinaryOp(p.Add);
                IAsyncResult iftAr = bp.BeginInvoke(5, 5, new AsyncCallback(p.AddComplete)null);
                while (!iftAr.AsyncWaitHandle.WaitOne(100,true))
                {
                    Console.WriteLine("Doing some work in Main()!");
                }
                int result = bp.EndInvoke(iftAr);
                Console.WriteLine("5 + 5 ={0}", result);
                Console.Read();
            }
    //An Add() method that do some simple arithamtic operation        public int Add(int a, int b)
            {
                Console.WriteLine("Add() running on thread {0}",Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                return (a + b);
            }
     
            
    //Target of AsyncCallback delegate should match the following pattern        public void AddComplete(IAsyncResult iftAr)        {
                Console.WriteLine("AddComplete() running on thread {0}",Thread.CurrentThread.ManagedThreadId); 
                Console.WriteLine("Operation completed.");
            }
    Output:

  1. Here you can see the AddComplete() is called after the Main() completed its execution. If you are looking deep into the code and find iftAr.AsyncWaitHandle.WaitOne(100,true)) as something alien statement then you should look at the Delegate and Async Programming Part I - C#.
     
  2. The second and more interesting approach is showing the result by calling EndInovke() inside the AddComplete(). Now you should have a question here. The instance of the BinaryOp delegate is running on the primary thread in the Main(). How can we access it to secondary thread to call the EndInvoke()? The answer is the System.Runtime.Remoting.Messaging.AsyncResult class.

    The AsyncResult class

    The AddComplete() method of AsyncCallback takes the AsyncResult class object compatible to IAsyncResult as an argument. The static AsyncDelegate property of the AsyncResult class returns a reference to the original asynchronous delegate that was created elsewhere, and which is accessible through the IAsyncResult. Simply just cast the returned object by the AsyncDelegate to BinaryOp.
    Update the code in the example; remove the lines of EndInvoke from the Main() and let's call it from the AddComplete() method.
    //Target of AsyncCallback delegate should match the following pattern        public void AddComplete(IAsyncResult iftAr)
            {
                Console.WriteLine("AddComplete() running on thread {0}",Thread.CurrentThread.ManagedThreadId);
     
                Console.WriteLine("Operation completed.");
     
                
    //Getting result            AsyncResult ar = (AsyncResult)iftAr;
                BinaryOp bp = (BinaryOp)ar.AsyncDelegate;
                int result = bp.EndInvoke(iftAr);
     
                Console.WriteLine("5 + 5 ={0}", result);
                Console.WriteLine("Message recieved on thread {0}",Thread.CurrentThread.ManagedThreadId);
            }
     

Now the output will be:

AsyncResult class in C#

Hope you can see the difference in the output of both the approaches here.

Passing and Receiving Custom State Data using the final argument of BeginInvoke()

Now let's address the final argument of BeginInvoke() which has been null up to this point. This parameter allows you to pass additional state information from the primary thread to the secondary thread.
Because the prototype is System.Object you can pass any object as a parameter, as long as the callback knows what type of object to expect.
Now let us demonstrate passing a simple string message form the primary thread in the BeginInvoke() and receiving it in the callback on the secondary thread using the AsyncState property of the IAsyncResult incoming parameter.

Now here's the complete code:
class Program    {
        
//Simple delegate declaration        public delegate int BinaryOp(int x, int y);
        static void Main(string[] args)
        {
            Console.WriteLine("Main() running on thread {0}",Thread.CurrentThread.ManagedThreadId);
 
            Program p=new Program();
            BinaryOp bp = new BinaryOp(p.Add);
            IAsyncResult iftAr = bp.BeginInvoke(5, 5, new AsyncCallback(p.AddComplete), "This message is from Main() thread "+Thread.CurrentThread.ManagedThreadId;
            while (!iftAr.AsyncWaitHandle.WaitOne(100,true))
            {
                Console.WriteLine("Doing some work in Main()!");
            } 
            Console.Read();
        }
 
        
//An Add() method that do some simple arithamtic operation        public int Add(int a, int b)
        {
            Console.WriteLine("Add() running on thread {0}",Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(500);
            return (a + b);
        }
 
        
//Target of AsyncCallback delegate should match the following pattern        public void AddComplete(IAsyncResult iftAr)
        {
            Console.WriteLine("AddComplete() running on thread {0}",Thread.CurrentThread.ManagedThreadId); 
            Console.WriteLine("Operation completed.");
 
            
//Getting result            AsyncResult ar = (AsyncResult)iftAr;
            BinaryOp bp = (BinaryOp)ar.AsyncDelegate;
            int result = bp.EndInvoke(iftAr); 

            
//Recieving the message from Main() thread.            string msg = (string)iftAr.AsyncState;            Console.WriteLine("5 + 5 ={0}", result);
            Console.WriteLine("Message recieved on thread {0}: {1}",Thread.CurrentThread.ManagedThreadId, msg);
        } 
    }

Output:
argument of BeginInvoke in C#

I hope you enjoyed this.. I'm expecting that the next time you call BeginInvoke() you won't pass NULL values to some useful arguments.
MultiThreading is what your multicore processor is for! 
So Cheers