Providing client's certificate required by server

This topic explains how to authenticate the client using a certificate. IMAP servers might be configured to request the client to authenticate using its certificate during SSL negotiation. The client can either process, or inform the server that it has no suitable certificate.

The example below demonstrates how to use ComponentSoft IMAP library and handle the CertificateRequired event of the ImapClient to find a suitable certificate for the client authentication:

C#:

public void HandleCertificateRequiredEvent()
{
   // Create a new instance.
   ImapClient client = new ImapClient();
   client.CertificateRequired += client_CertificateRequired;
   // Connect to the IMAP server.
   client.Connect("myserver", 143, SecurityMode.Explicit);
   // Authenticate.
   client.Authenticate("userName", "password");
   // Do something here...
   // ...
   // Disconnect.
   client.Disconnect();
}
void client_CertificateRequired(object sender, ComponentSoft.Security.CertificateRequiredEventArgs e)
{
   // Load certificates from the local machine.
   X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
   my.Open(OpenFlags.ReadOnly);
   // Retrieve a list of available certificates.
   X509Certificate2Collection certs = my.Certificates;
   // If no certificate found, return.
   if (certs.Count == 0)
   {
       e.Certificate = null;
       return;
   }
   // Show all certificates.
   Console.WriteLine("Select certificate:");
   for (int i = 0; i <= certs.Count; i++)
   {
       if (i == 0)
       {
           Console.WriteLine(string.Format("{0}. [Nothing, skip this step]", i));
           continue;
       }
       Console.WriteLine(string.Format("{0}. {1}", i, certs[i - 1].SubjectName.Name));
   }
   // And ask user to choose an appropriate certificate.
   while (true)
   {
       Console.Write(string.Format("Select certificate [0 - {0}]: ", certs.Count));
       int certIndex;
       try
       {
           certIndex = int.Parse(Console.ReadLine());
       }
       catch
       {
           Console.WriteLine("ERROR: Wrong certificate index input!");
           continue;
       }
       if (certIndex > 0 && certIndex <= certs.Count)
       {
           e.Certificate = certs[certIndex];
           return;
       }
       if (certIndex == 0)
           break;
       Console.WriteLine(string.Format("ERROR: You must enter number between 0 and {0}.", certs.Count));
   }
}

VB.NET

Public Sub HandleCertificateRequiredEvent()
    ' Create a new instance.
    Dim client As New ImapClient()
    AddHandler client.CertificateRequired, AddressOf client_CertificateRequired
    ' Connect to the IMAP server.
    client.Connect("myserver", 143, SecurityMode.Explicit)
    ' Authenticate.
    client.Authenticate("userName", "password")
    ' Do something here...
    ' ...
    ' Disconnect.
    client.Disconnect()
End Sub
Private Sub client_CertificateRequired(ByVal sender As Object, ByVal e As ComponentSoft.Security.CertificateRequiredEventArgs)
    ' Load certificates from the local machine.
    Dim my As New X509Store(StoreName.My, StoreLocation.CurrentUser)
    my.Open(OpenFlags.ReadOnly)
    ' Retrieve a list of available certificates.
    Dim certs As X509Certificate2Collection = my.Certificates
    ' If no certificate found, return.
    If certs.Count = 0 Then
        e.Certificate = Nothing
        Return
    End If
    ' Show all certificates.
    Console.WriteLine("Select certificate:")
    For i As Integer = 0 To certs.Count
        If i = 0 Then
            Console.WriteLine(String.Format("{0}. [Nothing, skip this step]", i))
            Continue For
        End If
        Console.WriteLine(String.Format("{0}. {1}", i, certs(i - 1).SubjectName.Name))
    Next i
    ' And ask user to choose an appropriate certificate.
    Do
        Console.Write(String.Format("Select certificate [0 - {0}]: ", certs.Count))
        Dim certIndex As Integer
        Try
            certIndex = Integer.Parse(Console.ReadLine())
        Catch
            Console.WriteLine("ERROR: Wrong certificate index input!")
            Continue Do
        End Try
        If certIndex > 0 AndAlso certIndex <= certs.Count Then
            e.Certificate = certs(certIndex)
            Return
        End If
        If certIndex = 0 Then
            Exit Do
        End If
        Console.WriteLine(String.Format("ERROR: You must enter number between 0 and {0}.", certs.Count))
    Loop
End Sub

Sending a custom command to an IMAP server

Explicitly sending commands to an IMAP server is usually not necessary. Almost all commands that could conceivably be sent to an IMAP server are encapsulated by high-level methods. However, to send a command to an IMAP server, simply call the SendCommand method, and to get the response from the IMAP server, call the ReadResponse method.

The example below sends the "STAT" command to an IMAP server and print out the response:

C#:

// IMAP server information.
const string serverName = "myserver";
const string user = "name@domain.com";
const string password = "mytestpassword";
const int port = 993;
const SecurityMode securityMode = SecurityMode.Implicit;
// Create a new instance of the ImapClient class.
ImapClient client = new ImapClient();
// Connect to the server.
client.Connect(serverName, port, securityMode);
// Login to the server.
client.Authenticate(user, password);
// Select 'INBOX' mailbox.
client.Select("INBOX");
// Send a command.
client.SendCommand("STAT");
// Read response from the server.
ImapResponse response = client.ReadResponse();
// Print out the response.
Console.WriteLine(response.RawResponse);
// Close the connection.
client.Disconnect();

VB.NET:

' IMAP server information.
Const serverName As String = "myserver"
Const user As String = "name@domain.com"
Const password As String = "mytestpassword"
Const port As Integer = 993
Const securityMode As SecurityMode = securityMode.Implicit
' Create a new instance of the ImapClient class.
Dim client As New ImapClient()
' Connect to the server.
client.Connect(serverName, port, securityMode)
' Login to the server.
client.Authenticate(user, password)
' Select 'INBOX' mailbox.
client.Select("INBOX")
' Send a command.
client.SendCommand("STAT")
' Read response from the server.
Dim response As ImapResponse = client.ReadResponse()
' Print out the response.
Console.WriteLine(response.RawResponse)
' Close the connection.
client.Disconnect()

Downloading Unread Mail Messages

To list and download unread mail messages with the Ultimate IMAP Mail component, you just need to pass the ImapCriterion.DontHaveFlags(ImapMessageFlags.Seen) search condition to the ListMessages method. The following code illustrates how to do so:

// IMAP server information.
const string serverName = "myserver";
const string user = "name@domain.com";
const string password = "mytestpassword";
const int port = 993;
const SecurityMode securityMode = SecurityMode.Implicit;

// Create a new instance of the ImapClient class.
ImapClient client = new ImapClient();

// Connect to the server.
client.Connect(serverName, port, securityMode);

// Login to the server.
client.Authenticate(user, password);

// Select 'INBOX' mailbox
client.Select("INBOX");

// Get the message list.
Console.WriteLine("Getting message list...");
ImapMessageCollection list = client.ListMessages(EnvelopeParts.UniqueId | EnvelopeParts.Size, ImapCriterion.DontHaveFlags(ImapMessageFlags.Seen));

// Get messages.
for (int i = 0; i < list.Count; i++)
{
    ImapMessage imapMessage = list[i];

    // Download the message to an instance of the MailMessage class.
    MailMessage msg = client.DownloadMailMessage(imapMessage.UniqueId);

    // Display some information about it.
    Console.WriteLine("Size: " + imapMessage.Size);
    Console.WriteLine("Number of attachments: " + msg.Attachments.Count);
    Console.WriteLine("Number of header name value pairs: " + msg.Headers.Count);
}

// Close the connection.
client.Disconnect();

VB.NET

' IMAP server information.
Const serverName As String = "myserver"
Const user As String = "name@domain.com"
Const password As String = "mytestpassword"
Const port As Integer = 993
Const securityMode As SecurityMode = securityMode.Implicit

' Create a new instance of the ImapClient class.
Dim client As New ImapClient()

' Connect to the server.
client.Connect(serverName, port, securityMode)

' Login to the server.
client.Authenticate(user, password)

' Select 'INBOX' mailbox
client.Select("INBOX")

' Get the message list.
Console.WriteLine("Getting message list...")
Dim list As ImapMessageCollection = client.ListMessages(EnvelopeParts.UniqueId Or EnvelopeParts.Size, ImapCriterion.DontHaveFlags(ImapMessageFlags.Seen))

' Get messages.
For i As Integer = 0 To list.Count - 1
    Dim imapMessage As ImapMessage = list(i)

    ' Download the message to an instance of the MailMessage class.
    Dim msg As MailMessage = client.DownloadMailMessage(imapMessage.UniqueId)

    ' Display some information about it.
    Console.WriteLine("Size: " & imapMessage.Size)
    Console.WriteLine("Number of attachments: " & msg.Attachments.Count)
    Console.WriteLine("Number of header name value pairs: " & msg.Headers.Count)
Next i

' Close the connection.
client.Disconnect()

How to obtain account information

This tutorial illustrates how to obtain Mailbox information with a few lines of code in Ultimate IMAP Component. Other examples for SMTP and POP3 can also be found at SMTP blog and POP3 blogThe simplest way to obtain information about a specified mailbox is using the GetMailboxInfo method. You only need to pass the mailbox name to the method. It returns a Mailbox object containing information about the mailbox you have requested.

If you want to obtain mailbox information of a Gmail IMAP account, please ensure the imap client connection is enabled on the GMAIL account setting page as shown in this picture:

IMAP Settings in GMAIL

The following steps illustrate how to obtain mailbox information with Ultimate mail library:

  1. Add using directives to your code to create aliases for existing ComponentSoft namespaces and avoid having to type the fully qualified type names. The code looks similar to the following:


    C#

    using ComponentSoft.Net;
    using ComponentSoft.Net.Mail;

    VB.NET

    Imports ComponentSoft.Net
    Imports ComponentSoft.Net.Mail

  2. Create a new instance of the ImapClient class and call the Connect methods. The code looks similar to the following:
    C#

    // Create a new instance of the ImapClient class.
    ImapClient client = new ImapClient();
    // Connect to the server.
    client.Connect("myserver");
    // Or you can specify the IMAP port with
    // client.Connect("myserver", 143);
    // Login to the server.
    client.Authenticate("user", "password");
    // Get information about the INBOX mailbox.
    Mailbox m = client.GetMailboxInfo("INBOX");
    Console.WriteLine(
    "The number of recent messages: " + m.RecentMessages);
    Console.WriteLine(
    "The number of new unseen messages messages: " + m.NewUnseenMessages);
    // Close the connection.
    client.Disconnect();

    VB.NET

    ' Create a new instance of the ImapClient class.
    Dim client As New ImapClient()
    ' Connect to the server.
    client.Connect("myserver")
    ' Or you can specify the IMAP port with
    ' client.Connect("myserver", 143);
    ' Login to the server.
    client.Authenticate("user""password")
    ' Get information about the INBOX mailbox.
    Dim m As Mailbox = client.GetMailboxInfo("INBOX")
    Console.WriteLine("The number of recent messages: " & m.RecentMessages)
    Console.WriteLine("The number of new unseen messages messages: " & m.NewUnseenMessages)
    ' Close the connection.
    client.Disconnect()

Now you have successfully connected to the IMAP server and obtained information about the mailbox on the server. This is just a basic steps to manipulate mailboxes and messages. For more advanced tutorials, you can download the Ultimate Mail Library and take a look at the documentation as well as a number of carefully designed sample projects.

How to Downloading Mail Message Synchronously

Downloading mail messages from a IMAP server in UltimateMail component is so simple, you just call the DownloadMailMessage method and you retrieve an instance of the MailMessage class. You can now read, modify, save to disk the message. If you just need to download the message to disk or write it into a stream, just call the convenient DownloadMessage method instead.

The example below shows you how to get a list of messages from a IMAP server and download and save all messages to disk:

C#

// Select 'INBOX' mailbox
 client.Select("INBOX");
 // Get the message list.
 Console.WriteLine("Getting message list...");
 ImapMessageCollection list = client.ListMessages(EnvelopeParts.UniqueId | EnvelopeParts.Size);
 // Get messages.
 for (int i = 0; i < list.Count; i++)
 {
 ImapMessage imapMessage = list[i];
 // Download the message to an instance of the MailMessage class.
 MailMessage msg = client.DownloadMailMessage(imapMessage.UniqueId);
 // Display some information about it.
 Console.WriteLine("Size: " + imapMessage.Size);
 Console.WriteLine("Number of attachments: " + msg.Attachments.Count);
 Console.WriteLine("Number of header name value pairs: " + msg.Headers.Count);
 }

VB.NET

' Select 'INBOX' mailbox
 client.Select("INBOX")
 ' Get the message list.
 Console.WriteLine("Getting message list...")
 Dim list As ImapMessageCollection = client.ListMessages(EnvelopeParts.UniqueId Or EnvelopeParts.Size)
 ' Get messages.
 For i As Integer = 0 To list.Count - 1
 Dim imapMessage As ImapMessage = list(i)
 ' Download the message to an instance of the MailMessage class.
 Dim msg As MailMessage = client.DownloadMailMessage(imapMessage.UniqueId)
 ' Display some information about it.
 Console.WriteLine("Size: " & imapMessage.Size)
 Console.WriteLine("Number of attachments: " & msg.Attachments.Count)
 Console.WriteLine("Number of header name value pairs: " & msg.Headers.Count)
 Next i

After downloading messages from the server, you may want to obtain more information about the mailbox such as the number of unread messages and mailbox size, and then upload some messages to the server. See topic Obtaining account information for more details how to use the GetMailboxInfo method to get the account information.