Silverlight 4 – Grabbing Emails from the Outlook Inbox

I’ve been using Twitter and one of the things that I followed recently was the Silverlight forums and that caused a question to bob up on my screen just yesterday;

image

I haven’t replied back to the original poster as I don’t imagine that I’ve got the solution to his particular problem but it occurred to me that with Silverlight 4, reaching into an application like Outlook to use a little bit of functionality is exactly the kind of scenario that you can tackle with COM interop so that sparked my interest in experimenting with it.

It feels like there’s a few possibilities around how you might do this with Silverlight 4;

  1. Staying within the sandbox you could try and do drag-and-drop from Outlook to Silverlight.
    1. I don’t think you can do a straight drag-drop because I don’t think Silverlight sees that as a file drop.
    2. I suspect you’d have to drag to desktop and then drag the resultant file to the Silverlight app.
    3. To do (2) and stay in the sandbox, you’d have to unpick the binary Outlook message format yourself which wouldn’t be much fun unless there’s some way to get Outlook to save a message as XML ( I haven’t found that yet ).
  2. Leaving the sandbox, with an out of browser “trusted” application you could;
    1. Attempt to do 1.1 and 1.2 above but ask Outlook to decipher the Outlook .msg file for you
    2. Read the email details from Outlook in the first place – that is, pop up a dialog in Silverlight which shows the user their Outlook email so that they don’t have to drag and drop.

I decided to experiment with 2.2.

I wrote a little app, it’s should be running below if I can figure out where to drop it onto my website. If you’re on the Silverlight 4 beta you can click it to install it locally ( if you’re not on the beta you’ll perhaps get a white rectangle or, hopefully, a Silverlight logo );

 
In the browser, it presents a UI;
 
image
which will change if you install it;
 
image
 
and if you run it from the desktop it presents a “business UI” which is meant to represent some made-up-view of some customer data for a “contract management system” where you have a few fields relating to each Customer;
 
  • FirstName
  • LastName
  • ContractStartDate
  • ContractDuration
  • Correspondence which is a list of Email which is
    • From
    • To
    • Subject
    • Body
 
All the data is hard-coded into the ViewModel that sits behind the View and the UI is a DataGrid;
 
image
clicking on the “email” button in the DataGrid expands out ( using the DataGrid’s RowDetailsTemplate functionality the Correspondence for that particular customer ( again, this is generated data );
 
image
and that’s just shown in another DataGrid ( yes, sorry – I put grids into grids 🙂 ) which is bound to the Correspondence property on the Customer.
 
Clicking on that Attach… button in the UI sparks up another view which is pulling data from Outlook. I made this into a modal dialog style interaction using the Silverlight Toolkit’s ChildWindow class and the code I wrote also seems to take a while so I used a BusyIndicator as well;
 
image
 
that pulls in emails from Outlook with just a few lines of thrown together code which is currently in the wrong place in a ViewModel;
 
    void GetEmails()
    {
      // TODO - this is ugly, especially the reach into the application for its
      // dispatcher but the Outlook code is slow for me so I feel the need to
      // move the whole thing to another thread.
      // TODO - this code needs moving into some email service outside of this VM.
      Dispatcher dispatcher = Application.Current.MainWindow.Dispatcher;

      this.Loading = true;

      ThreadPool.QueueUserWorkItem(o =>
        {
          dynamic outlook = ComAutomationFactory.CreateObject("Outlook.Application");
          dynamic inbox = outlook.GetNamespace("Mapi").GetDefaultFolder(olFolderInbox);
          int itemCount = inbox.Items.Count;

          for (int i = 1; i <= itemCount; i++)
          {
            Email newEmail = new Email()
            {
              Subject = inbox.Items[i].Subject,
              Body = inbox.Items[i].Body,
              From = inbox.Items[i].SenderName,
              To = inbox.Items[i].To
            };
            newEmail.Body = newEmail.Body.Substring(0, 
              Math.Min(30, newEmail.Body.Length));

            dispatcher.BeginInvoke(() =>
              {
                this.Emails.Add(newEmail);
              });
          }
          dispatcher.BeginInvoke(() => this.Loading = false);
        });
    }
 
where Email is my own class used throughout this “app” so, as you can see, there’s not much to the Outlook interaction here.
 
Once the emails have loaded, there are little “Attach” buttons to attach them to the current customer so if I click to attach those 3 emails ( the buttons should perhaps be CheckBoxes ) and then click the Close button as the picture suggests;
 
image
then back in the main view, the Customer now has those 3 extra emails attached and, yes, those are real emails from my Inbox but hopefully I’m not leaking very much sensitive information here;
 
image
 
In playing around with this I hit a few “interesting” areas ( for me at least ) – so just some notes I made along the way;
 
  1. How to try and deal with ChildWindow from an MVVM perspective. I jump through a hoop or two in that;
    1. I want to put up the ChildWindow and then ask it for a list of attached emails when it is dismissed.
    2. Dismissing the ChildWindow is done via the “Close” button click which is handled on the ViewModel.
    3. In order for the ViewModel to close the ChildWindow it needs to call ChildWindow.Close() but then the ViewModel doesn’t know what a ChildWindow is so it’s a bit tricky for it to do that.
    4. In the end;
      1. I defined some interface ICloseableWindow that has a Close member on it and I implemented that on my ChildWindow
      2. I passed the ChildWindow as a command parameter to the bound command on the ViewModel.
      3. In the handler on the ViewModel, I test for ICloseableWindow and ask it to Close itself.
      4. This way I felt that the ViewModel is still reasonably independent because all it knows about is ICloseableWindow.
  2. How to deal with the Outlook email enumeration code taking quite a long time.
    1. I dealt with this by moving it to another thread but that introduced a dependency for my ViewModel to get back to the UI thread.
    2. I haven’t got any IoC container in here but I could have addressed the previous point (2.1) by asking for some “IInvokeUIService” on an IoC container and then using that to get back to the UI thread rather than reaching directly into Application.Current.MainWindow as I do above.

If you want to take a look, here’s the source code for download – note that I spent a couple of hours with it so it’s not very polished but if it helps you with something you’re doing then that’s great.