YAEC (Yet Another Email Client) but this one has LINQ to IMAP...

Description

Today's project comes to us via The Code Project, Yet Another Email Client (LINQ to IMAP).

Did the "LINQ to IMAP" reach out and grab your attention too? You've just got to love LINQ and the possibilities and cool code opportunities it has enabled.

"Introduction

Equinox is an email client library targeting .NET 4.0 and Mono 2.8. For now, the plan is to support IMAP and SMTP; POP3 is not planned yet. It is written in C#, consisting of 100% managed code, and can be found on CodePlex. With this article, I want to peek your interest, give you an introduction into the features of this library, and provide a little explanation of why I found it necessary to implement yet another email client.

...

To address this, I implemented a LINQ provider that enables us to fetch messages or parts of messages directly from the server, which has two advantages. First, no matter how complex the query is or how many items we request, it will all be done in a single stroke using one fetch command; although this saves some net traffic, it is not the smoking gun we were hoping for.

The important part is the fact that we don't have to parse or map any responses manually anymore since this will be taken care of by the LINQ provider.

Let's take a look at a simple usage. In the following example, I will fetch the following items from all unread messages for the last week:

  • Envelope
  • Uid
  • Flags
  • Size
var query = client.Messages.Where(x => x.Date > DateTime.Today.AddDays(-7) 
&& !x.Flags.HasFlag(MessageFlags.Read)).Select(x => new MyContainer
{
Envelope = x.Envelope,
Uid = x.Uid,
Flags = x.Flags,
Size = x.Size
});

If we need a different fetch scenario, we just change the query. We can fetch less, like only the Envelope.

var query = client.Messages.Where( ... ).Select(x => x.Envelope);

 

Or we can fetch more:

var query = client.Messages.Where( ... ).Select(x => new SomeClass
{
Envelope = x.Envelope,
Uid = x.Uid,
Flags = x.Flags,
Size = x.Size,
Internal = x.InternalDate,
BodyStructure = x.BodyStructure,
SpecificBodyPart = (Entity) x.Parts("1.2.1.TEXT")
});

 

We can then execute the query by iterating through the results.

foreach(var container in query)
{
Debug.WriteLine(container.Envelope.Subject);
}

The point is that the only thing to change is the query when altering our fetch scenario. As it is with LINQ to SQL, we don't have to worry about parsing the data that comes out of SQL Server anymore, we just map the responses into our object. Without LINQ involved, we would need to either create a different parser for each of those scenarios or create a single parser that would be able to handle different but still only a finite amount of responses, and once we change the query, we would also be forced to change the parser.

As with many LINQ providers, there are limitations and restrictions since we have to work within the boundaries of the IMAP protocol. Multiple or nested Where/Select statements are not permitted; to be more precise, we need exactly one Where and one Select clause. With a few exceptions, none of the other extension methods like Any(), Single(), or SelectMany() are supported. A more detailed list of supported and unsupported methods as well as instructions for common fetch scenarios will be posted on CodePlex soon, but getting into the handling of custom providers is out of the scope for this article.

...

The Code Project article is from February 2011, so is this a "live' project you ask?

Here's a snip of the project's,Crystalbyte Equinox (LINQ to IMAP), source tab. As you can see, there's a nice level of activity (and that POP3 work is in process )

SNAGHTMLc1cc11c

While you're there, make sure you check out the Documentation. There's much more documentation than you'd usually expect from a one person project.

For example;

SNAGHTMLc2cd2f7

So lets look at the latest version. First the solution snap;

image

One thing that always encourages me is when a developer eats their own dog food, i.e. uses their own code in their coding.

For example in the ImapClient.cs they are clearly using the LINQ to IMAP

SNAGHTMLc2508d5

So am I going to drop my mail client today? No. But am I going to be watching this project and consider it in the future if/when I need a IMAP/SMTP/POP3 library? Yep, I sure am... Smiley

 

Page thumbnail, stone henge in space? spacehenge?, curtsey of Torley

The Discussion

  • User profile image
    exoteric

    Looks very cool!

    This could probably pair up nicely with Async as well (and IAsyncEnumerable) for a nice non-blocking fluent asynchronous library.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.