Building Custom Email Client In WPF Using C#

Introduction and Background

Yesterday, I was talking to myself about writing another post for C# programming; I agree I am addicted to programming now. So, I wanted to write a blog post and I found that I had a topic on my “write list.” So that I wasn't just writing about the topic, I added a bit more programming to it to support another feature. So basically what I had on my writing list was an email client in C# programming language. In this blog post, I will share the basics for developing an email client in C# using Windows Presentation Foundation framework. The source code is much shorter and more compact so that  building your own basic client takes no time at all. However, adding a few more features will take some time. I will point out those features later in the post itself, and you may add them later.

You are required to have the basic understanding of Windows Presentation Foundation framework and how C# language can be used. Typically, C# can be used to create an application of any kind. However, WPF is a framework that can be extended to any limit and can be used to create a graphical application of high performance and maximum extensibility. WPF power will be used to build this one SMTP + IMAP application to develop a simple email client.

Understanding the protocols

Before I dig deeper and start to write the source code and explain the methods to build the application. I will try to explain the protocols that will be used in this application. The two of them are:

  1. IMAP: Internet message access protocol.
  2. SMTP: Simple mail transfer protocol.

These protocols are typically used to send and receive email messages. Other than IMAP, POP and POP3 are two protocols used to receive the emails, or to keep the emails on your devices. But, I won’t talk about them.

.NET framework provides native support for SMTP protocol for sending emails through your .NET applications like Console, WinForms or WPF etc. However, .NET framework doesn’t provide any implementation for IMAP protocol. Instead, they provide you with TCP clients and listeners. Since IMAP and SMTP etc. are all protocols running on TCP protocol; or any other transmission layer protocol like UDP, implementing the native protocols like IMAP is very simple  in .NET framework.

For more of such packages and namespaces to manage the networking capabilities of an application, read System.Net namespaces on MSDN.

Instead, I will use a library to get myself started in no time. A very long time ago, I came upon a library, “ImapX,” which is a wonderful tool for implementing the IMAP protocol in C# applications. You can get ImapX from NuGet galleries by executing the following NuGet package manager command:

    Install-Package Imapx

This will add the package. Remember, Imapx works in only selected environments or not all. You should read more about it, on the CodePlex website.

The IMAP protocol is used to fetch the emails, to read, rather than downloading the entire mailbox and storing it on your own device. It is a very flexible protocol because the email is still present on the server, and is accessible on every device that you have. Network latency is not a bad factor here, because you don’t have to download the email entirely. You just download the content that you need right now.

IMAP protocol usage on the network
                                       Figure 1: IMAP protocol usage on the network

Building the application

Now that I have pointed out a few of the things that will be used in this application, I guess it is the time to continue the programming part and develop the application itself. First of all, create a new application of WPF framework. It is always a good approach to write the concerns and different sections of your applications.

Our application will have the following modules:

1. Authentication module

  • Initially we will ask the users for authentication.
  • Due to complexity level, I have only supported Google Mail at the moment.
  • That is why the application only asks for username and password combination.
  • You definitely should leave the maximum fields to the user’s will to be filled out so that they can connect to their own IMAP service; other than Google Mail.

2. Folder view

  • Viewing the folders and their messages.

3. Message view

  • Viewing the messages and its details.

4. Create a new message.

Separating these concerns will help us build the application in a much more agile way so that when we have to update or create a new feature in the application, doing so won’t take any longer. However, if you're hard-code everything in the same page then things get really very difficult. In this post, I will also give you a few tips to ensure that things are not made more difficult than they can be.

Managing the “MainWindow”"

Each WPF application will contain a MainWindow window, which is the default window that gets rendered on the screen. But, my recommendation is that you only create a Frame object in that window. Nothing else. That frame object will be used to navigate to multiple pages and different views of the applications depending on the user and application interactions.

  1. <Grid>  
  2.    <Frame Name="mainFrame" NavigationUIVisibility="Hidden" />  
  3. </Grid>  
One thing to note here is that Frame has a (IMO) really annoying navigation UI. You should keep that hidden. Apply the same setting to frames, or use this in the application resources and apply is application-wide.

This is helpful in changing the views instead of changing the visibilities of the grids and stack panel objects. However, on the runtime exchange, this won’t be available. To be able to use it, you will have to store the frame instance at a location which can be accessed from external objects too. I created the following property in the class, to hold the reference to this frame.

public static Frame MainFrame { get; set; }

Static fields will be accessible from the out objects, without having to require an instance. It will be helpful and you will find it being helpful in the later source samples below. The class itself is like this:
  1. public partial class MainWindow: Window  
  2. {  
  3.     public static Frame MainFrame  
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public static boolLoggedIn  
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.     publicMainWindow()  
  14.     {  
  15.         InitializeComponent();  
  16.         MainFrame = mainFrame;  
  17.         // Chance are, its not logged in.  
  18.         MainFrame.Content = new LoginPage();  
  19.         // Initialize the Imap  
  20.         ImapService.Initialize();  
  21.     }  
  22. }  
Pretty  simple, developing the building block of the application. This will  allow us to have separate UIs for our separate concerns and features. The main things will be done, rendered, and handled by the separate pages that we will have for our application.
 
Before I get started with rendering the later sections of pages, I will need to explain the IMAP base controller that I had developed to provide and serve me with the basic functionality and features of the IMAP protocol.

ImapService object

It is better to keep things allocated at the same place so that when we need to make a change we can make change right from there, instead of having to search, “Where did I write that part of API?” That is why this service object will contain all of the functions that are going to be used in the application.

We need 4 functions and an event handler (for IDLE support; discussed later)

 

  1. Initialization function; which is a requirement by design.
  2. Login and logout functions.
  3. Function to get all folders
  4. Function to fetch the email messages of a function.

The event is used to notify when a new message comes.

The object is defined as below:

  1. using System;  
  2. usingSystem.Collections.Generic;  
  3. usingSystem.Linq;  
  4. usingSystem.Text;  
  5. usingSystem.Threading.Tasks;  
  6. usingImapX;  
  7. usingImapX.Collections;  
  8. usingSystem.Windows;  
  9. namespaceImapPackage  
  10. {  
  11.     classImapService  
  12.     {  
  13.         private static ImapClient client  
  14.         {  
  15.             get;  
  16.             set;  
  17.         }  
  18.         public static void Initialize()  
  19.         {  
  20.             client = new ImapClient("imap.gmail.com"true);  
  21.             if(!client.Connect())  
  22.             {  
  23.                 throw new Exception("Error connecting to the client.");  
  24.             }  
  25.         }  
  26.         public static bool Login(string u, string p)  
  27.         {  
  28.             returnclient.Login(u, p);  
  29.         }  
  30.         public static void Logout()  
  31.         {  
  32.             // Remove the login value from the client.  
  33.             if(client.IsAuthenticated)  
  34.             {  
  35.                 client.Logout();  
  36.             }  
  37.             // Clear the logged in value.  
  38.             MainWindow.LoggedIn = false;  
  39.         }  
  40.         public static List < EmailFolder > GetFolders()  
  41.         {  
  42.             var folders = new List < EmailFolder > ();  
  43.             foreach(var folder in client.Folders)  
  44.                 {  
  45.                     folders.Add(new EmailFolder  
  46.                     {  
  47.                         Title = folder.Name  
  48.                     });  
  49.                 }  
  50.                 // Before returning start the idling  
  51.             client.Folders.Inbox.StartIdling(); // And continue to listen for more.  
  52.             client.Folders.Inbox.OnNewMessagesArrived += Inbox_OnNewMessagesArrived;  
  53.             return folders;  
  54.         }  
  55.         private static void Inbox_OnNewMessagesArrived(object sender, IdleEventArgs e)  
  56.         {  
  57.             // Show a dialog  
  58.             MessageBox.Show($ "A new message was downloaded in {e.Folder.Name} folder.");  
  59.         }  
  60.         public static MessageCollectionGetMessagesForFolder(string name)  
  61.         {  
  62.             client.Folders[name].Messages.Download(); // Start the download process;  
  63.             returnclient.Folders[name].Messages;  
  64.         }  
  65.     }  
  66. }  
This basic class will be used throughout the application to load the resources and messages. I won’t go into the depth of this library because I will just explain a few points and how to use the basic functions and features. However, the library is very strong and powerful and provides you with every tool and service required to build a full-featured email client.

Login page

The first step will be to authenticate users by asking them for their username and passwords. Typically, your application will cache the user authentication details; in most cases username, and in some cases if user allows, then the password too.
 
In a real application you are going to have a full authentication page, which will provide the fields such as input for username, port, IMAP hosts and passwords etc. But however in my application I have not used any such fields because I wanted to keep things really simple. I just asked user for username and password, and used other settings hard coded in the application’s source code.

The XAML of the page looks like this:
  1. <StackPanel Width="500" Height="300">  
  2.     <TextBlock Text="Login to continue" FontSize="25" />  
  3.     <TextBlock Text="We support Google Mail at the moment, only." />  
  4.     <Grid Height="150" Margin="0, 30, 0, 0">  
  5.         <Grid.ColumnDefinitions>  
  6.             <ColumnDefinition />  
  7.             <ColumnDefinition Width="3*" />   
  8.         </Grid.ColumnDefinitions>  
  9.         <StackPanelGrid.Column="0">  
  10.             <TextBlock Text="Username" Margin="0, 5, 0, 15" />  
  11.             <TextBlock Text="Password" />   
  12.        </StackPanel>  
  13.         <StackPanelGrid.Column="1">  
  14.             <TextBox Name="username" Margin="0, 0, 0, 5" Padding="4" />  
  15.             <PasswordBox Name="password" Padding="4" />   
  16.        </StackPanel>  
  17.     </Grid>  
  18.     <Button Width="150" Name="loginBtn" Click="loginBtn_Click">Login</Button>  
  19.     <TextBlock Name="error" Margin="10" Foreground="Red" />   
  20. </StackPanel>  
This content will be loaded and since in the constructor for the MainWindow we had loaded this page, we will see this page initially.

Authentication page for the application
                                    Figure 2: Authentication page for the application

Definitely, you are going to provide extra sections and fields for the users to configure the way your application is going to connect to their IMAP service provider. However, this will also work. Mozilla’s Thunderbird does the same, they just ask for the username and password and find the correct settings and configurations themselves. But, however you want, you can write the application in your own way.

We just need to handle the event of the button,
  1. private void loginBtn_Click(object sender, RoutedEventArgs e)  
  2. {  
  3.     MainWindow.LoggedIn = ImapService.Login(username.Text, password.Password);  
  4.     // Also navigate the user  
  5.     if(MainWindow.LoggedIn)  
  6.     {  
  7.         // Logged in  
  8.         MainWindow.MainFrame.Content = new HomePage();  
  9.     }  
  10.     else  
  11.     {  
  12.         // Problem  
  13.         error.Text = "There was a problem logging you in to Google Mail.";  
  14.     }  
  15. }  
Clearly, this will just make the calls to the service that we created previously. The benefit is that we just need to add the validation and verification code here. We don’t need to write anything new here because we have done all of that in the previously set up service named, “ImapService”. At the end, if everything went correctly, it wouldill navigate the user to the home page.

Note: There is no asynchrony in the application and that is why, it may “freeze” sometimes. To overcome this problem you may want to rewrite the entire service provided to develop it with async/await.

Home page

In this application the major component is the home page, the home page is where the folders and messages will be loaded. There is no difficulty in loading those, because we have already created the function to execute to get the folders and messages in those folders (read the ImapService class once again).

The basic XAML controls that are being used here, are the following ones:
  1. <ListView Name="foldersList" SelectionChanged="foldersList_SelectionChanged">  
  2.     <ListView.ItemTemplate>  
  3.         <DataTemplate>  
  4.             <TextBlock Margin="10" Cursor="Hand" Text="{Binding Title}" Name="folderTitle" />   
  5.         </DataTemplate>  
  6.     </ListView.ItemTemplate>  
  7. </ListView>  
  8. <Frame Grid.Column="1" Name="contentFrame" NavigationUIVisibility="Hidden" />  
A list view that will render the folders and another frame that will be used to load multiple pages. I used the same method to hold a reference to this frame, in my class object and I loaded it using the contructor itself.
  1. publicHomePage()  
  2. {  
  3.     InitializeComponent();  
  4.     ContentFrame = contentFrame;  
  5.     foldersList.ItemsSource = ImapService.GetFolders();  
  6.     ClearRoom();  
  7. }  
Just using the same small steps, I created the page. Which wwill then have its own functionality and will allow the features to handle their interaction with users.

Folders listed in the application
                                       Figure 3: Folders listed in the application

We can load the folder messages by selecting a folder. That will show the messages in the right side and we can then read a message. The code  is provided in the application itself.
  1. private void foldersList_SelectionChanged(object sender, SelectionChangedEventArgs e)  
  2. {  
  3.     var item = foldersList.SelectedItem as EmailFolder;  
  4.     if(item != null)  
  5.     {  
  6.         // Load the folder for its messages.  
  7.         loadFolder(item.Title);  
  8.     }  
  9. }  
  10. private void loadFolder(string name)  
  11. {  
  12.     ContentFrame.Content = new FolderMessagesPage(name);  
  13. }  
This way, we load the folder in the content frame that we are having in the application’s home page.

Sending the emails

We have talked a lot about the IMAP protocol and I guess I should also share a few points about the SMTP protocol support in this application. SMTP protocol support is provided natively in .NET framework.

I have written an article for SMTP protocol support in .NET framework, which you may be interested in, Sending emails over .NET framework, and general problems – using C# code. That article discusses a lot about doing so, and guess what, I used the same code from that article and wrote the entire feature for sending the emails on it.

I created the “send email” form as follows:
  1. <Grid>  
  2.     <Grid.ColumnDefinitions>  
  3.         <ColumnDefinition />  
  4.         <ColumnDefinition Width="3*" />   
  5.     </Grid.ColumnDefinitions>  
  6.     <StackPanelGrid.Column="0">  
  7.         <TextBlock Text="To" Margin="0, 5" />  
  8.         <TextBlock Text="Subject" Margin="0, 5" />  
  9.         <TextBlock Text="Body" Margin="0, 5" />   
  10.     </StackPanel>  
  11.     <StackPanelGrid.Column="1">  
  12.         <TextBox Margin="0, 3" Padding="1" Name="to" />  
  13.         <TextBox Margin="0, 3" Padding="1" Name="subject" />  
  14.         <TextBox Margin="0, 3" Padding="1" Height="130" Name="body" AcceptsReturn="True" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" />  
  15.         <Button Width="50" Name="sendBtn" Click="sendBtn_Click">Send</Button>  
  16.         <Button Width="50" Name="cancelBtn" Click="cancelBtn_Click" Margin="130, -20, 0, 0">Cancel</Button>   
  17.     </StackPanel>  
  18. </Grid>  
Although I understand that is not the best of what I could have made, but, for the sake of this post, that would (should!) suffice. This wouldill allow the user to enter the details for a very basic email.

Mail
                                          Figure 4: SMTP protocol test, email form

Upon clicking the send button, the email wouldill be sent. The code to do so is really straight-forward and (as mentioned before) available on that article I wrote about sending the emails in C#.

Bonus: IDLE support for folders

Before I wind things up, I wanted to enlighten you to the topic of IDLE support. In IMAP, IDLE support means that your application don’t need to send the request to the server in order to fetch new messages. Instead, the server will itself send the data to the client, whenever a new email is received.

What I did was,  I wrote that code to support IDLE feature in the ImapService because that was a service of IMAP and not the application itself. I updated the folder fetching code and added the following statements, (or since I haven’t shared the code at all, the code is like the following),
  1. public static List < EmailFolder > GetFolders()  
  2. {  
  3.     var folders = new List < EmailFolder > ();  
  4.     foreach(var folder in client.Folders)  
  5.     {  
  6.         folders.Add(new EmailFolder  
  7.         {  
  8.             Title = folder.Name  
  9.         });  
  10.     }  
  11.     // Before returning start the idling  
  12.     client.Folders.Inbox.StartIdling(); // And continue to listen for more.  
  13.     client.Folders.Inbox.OnNewMessagesArrived += Inbox_OnNewMessagesArrived;  
  14.     return folders;  
  15. }  
  16. private static void Inbox_OnNewMessagesArrived(object sender, IdleEventArgs e)  
  17. {  
  18.     // Show a dialog  
  19.     MessageBox.Show($ "A new message was downloaded in {e.Folder.Name} folder.");  
  20. }  
The handler and the event will then work as a counter-part and will provide us with a very beautiful service in which our application will be able to fetch the messages when a message is received!

We can use a folder to start IDLE. In my case, I used Inbox folder. Inbox folder will let us know for any new email message that we may receive and we can then use the properties of the event arguments to find out which folder received which message.

Points of Interest

In .NET framework, SMTP protocol is supported natively, implementing the IMAP protocol is a bit of a task. For that, developers may use ImapX, which is a free and open source package and library for C# applications that may want to support email messages.

In this blog, I have explained the methods used to build the applications that can receive and send email messages on the internet to the clients. IMAP protocol is a much preferred and loved protocol because it doesn’t need you to download the emails, you can just download the stuff that you need.

If I write something extra, I will update the post or create a new one. Do leave me a message if you find something missing.

Read more articles on WPF: