Getting started with IMAP and POP3 components


Introduction

To retrieve messages from e-mail servers, you can use MailBee.NET IMAP and MailBee.NET POP3 components. Their main classes are Imap and Pop3, respectively.

These classes can also be used to manage e-mails and folders, such as delete messages, move them between folders, upload into a folder, search messages for various criteria, manage folders, and so on. Some of this extra functionality is available only with IMAP.

E-mail messages can be downloaded completely (with all the text bodies and attachments), header-only, and mixed mode (such as headers and text body but no attachments). Again, only IMAP provides the full set of features.

Once the e-mail is downloaded, you can parse it, examine any of its properties, work with attachments, embedded pictures and other linked resources , save it into a file or stream, and process it in any other way. And you can send it again (for instance, create a reply to the message and then send the reply with MailBee.NET SMTP component).

The file format of e-mails which is used by SMTP, IMAP and POP3 protocols is called MIME. Therefore, the main class which represents an e-mail message in MailBee.NET is MailBee.Mime.MailMessage. This class can both parse and build e-mails in MIME format.

Imap and Pop3 classes return downloaded e-mails as MailMessage objects (for single e-mails) and collections (for ranges of e-mails).

Also, IMAP protocol can return some additional information with the message, which is called envelope. Thus, when using Imap class, you'll be mostly dealing with collections of envelopes rather than messages. Of course, an IMAP envelope provides access to the contained e-mail message as well.


Feature map, as IMAP vs POP3 comparison

The POP3 protocol is very simple and provides only basic features of e-mail retrieval.

The IMAP protocol (also known as IMAP4) provides much more functions and should be used whenever possible.

The only reason to prefer POP3 is if your server simply does not support IMAP (for instance, built-in e-mail server of MS Windows Server 2003/2008).

Note that MS Exchange DOES support IMAP (although it can be turned off by default, but the same is true for POP3). Moreover, some popular services like Gmail.com simply do not work with POP3 correctly.

E-mail retrieval and management IMAP POP3
Get entire message with attachments + +
Get multiple entire messages + +
Get message header of one or multiple e-mails + +
Get message header and the beginning of body section (body preview) + +
Detect attachments without downloading entire e-mail + +/-
Discover attachment filenames without downloading entire e-mail +
Get text body without downloading entire e-mail +
Get particular attachments without downloading entire e-mail +
Search for new e-mails + +/-
Search for any criteria +
Message flags (Seen, Answered, Flagged, etc) +
Server folders other than Inbox (Drafts, Trash, etc) +
E-mail push (instant notification on new e-mail arrival - IDLE) +/?
Message envelope (e.g. e-mail arrival date) +
Get mailbox quota +/?
Upload e-mail to server +
Copy or move e-mails between folders +
Custom commands + +
Secure authentication + +
Integrated Windows Authentication + +
OAuth 2.0 with Gmail + +
OAuth 2.0 with Outlook.com, Live.com, Hotmail.com +
Connection via proxy (SOCKS4, SOCKS5, HTTP) + +
Exceptions and error codes + +
Monitor progress with events + +
File and memory logging of session with e-mail server + +
Can be used in web (ASP.NET), desktop and console applications + +

+/- The feature is available with significant limitations.

+/? The feature is optional to the protocol implementation.

As soon as the e-mail has been downloaded from the server, MailMessage object comes into play and it's no longer important with which protocol the message was retrieved from the server. The capabilities of e-mail parsing and further processing are protocol-independent.

Some features require licenses for other components of MailBee.NET family. Note that MailBee.NET Objects license includes all individual component licenses.

E-mail parsing and post-processing License required
Parse entire e-mail with header section, text bodies, and attachments
Parse e-mail received in header-only mode
Parse e-mail received as header + incomplete body (body preview)
Parse standalone text body part or attachment received via IMAP
Load e-mail from file, memory, stream, Outlook, XML, System.Net.Mail.MailMessage
Access all headers, sender and recipients, text bodies, linked resources, and attachments
Make plain-text version of HTML-only e-mail
Extract linked resources (e.g. embedded pictures)
Get HTML body and save linked resources as files
Get HTML body and create dynamic URLs to linked resources (for web apps)
Save any plain-text or HTML e-mail as message.htm and linked files
Adjust HTML body (e.g. make links open in a new window)
Remove unsafe content from HTML (e.g. scripts)
Analyze HTML (e.g. find and process all external images)
Non-Latin characters in headers, body, attachment filenames (e.g. UTF-8)
Save all or selected attachments
Save attachment to file, stream or memory
Decode winmail.dat (MS TNEF) and extract all attachments and RTF body
Date, DateReceived, Importance, Priority, Sensitivity
From, ReplyTo, To, CC, and BCC  (as collection and as string)
Serialize e-mail to XML
Save MIME data of e-mail to file, stream, memory
Convert e-mail to Outlook .MSG format Outlook
Convert e-mail to System.Net.Mail.MailMessage
Re-send via SMTP or upload back to IMAP server SMTP or IMAP
Check DKIM and DomainKeys signature
Check if e-mail is SPAM AntiSpam
Check S/MIME signature and decrypt encrypted e-mail Security
Check if e-mail is bounced message or delivery report
Access to every MIME part, time stamps (Received headers), full e-mail size, and UID

As you can see, all the functions of parsing and processing e-mail are also available if you load e-mail from file or memory (it's not necessary to download e-mail only from IMAP or POP3 server). And you can also load e-mails from XML, System.Net.Mail.MailMessage, Outlook .MSG or .PST file.


IMAP and POP3 limitations (e.g. change password feature)

A word on things you should not expect from IMAP and POP3:

IMAP and POP3 protocols are all about managing e-mail in the account but not about managing the account itself.

To change e-mail account password or otherwise manage an account, you'll need to check if your e-mail server supports some kind of a proprietary API for this. It can be ActiveX/COM based, REST, specialized network protocol, and so on.

For instance, some e-mail servers like Plesk Panel support POPPASSD service running at port 106, which lets you remotely change the password with POP3-alike commands.


Import namespaces and set license key

Reference MailBee.NET.dll

To start using MailBee.NET in your projects, add MailBee.NET Objects reference to your project. You can use NuGet Packager Manager console for that:

Install-Package MailBee.NET

If NuGet is not an option (for instance, you have older version of Visual Studio), see below.

The example below is for Visual Studio 2010, but the idea remains the same for any other version. For instance, Import namespaces and set license key topic of SMTP guide features similar actions in their Visual Studio 2008 version.

In Project menu (Website menu for ASP.NET project), click Add a reference:

If Website menu does not appear in the menu bar, you should select your ASP.NET project in Solution Explorer first. This will replace Project menu with Website menu.

In Visual Studio 2010, Add Reference dialog may look differently for desktop/console and ASP.NET web applications. The below is for desktop/console. The ASP.NET version may look pretty much like in Visual Studio 2008.

Under Assemblies/Extensions tab, locate MailBee.NET:

In newer versions of Visual Studio, path to the dll is not shown by default so you may need to hover mouse cursor over to see the path (and determine the version). In this case, it's .NET 4.5 version of MailBee.NET.dll:

Click Add Reference and then Close. MailBee.NET entry should appear in References list of your project.

Import MailBee.NET namespaces

Now, import MailBee.NET namespaces to the beginning of your source code files where you'll use MailBee.NET.

When working with IMAP or POP3, you'll typically need some of these namespaces:

using MailBee;
using MailBee.Mime;
using MailBee.ImapMail;
using MailBee.Pop3Mail;
Imports MailBee
Imports MailBee.Mime
Imports MailBee.ImapMail
Imports MailBee.Pop3Mail

If you're using other components (e.g. S/MIME functionality, HTML processor, bounce e-mail parser, etc), you may also need to import their namespaces as well. For instance:

using MailBee.Security;
using MailBee.Html;
using MailBee.BounceMail;
Imports MailBee.Security
Imports MailBee.Html
Imports MailBee.BounceMail

Obtain license key

Now, you need to specify your trial or permanent MailBee.NET license key to unlock the product. If you do not yet have a key, you can generate the trial key with "Get a Trial Key" utility (available in Programs / MailBee.NET Objects menu).

You can specify the key in a number of ways (Windows registry, app.config or web.config file, directly in the code). This guide shows two methods of that: hard-coded key and key stored in app.config (web.config for ASP.NET).

Using Windows registry is not recommended as your application may be lacking permission to access the required registry branches. If you still need to use the registry (e.g. if your application is distributed with the source code so that you cannot embed the key there), refer to Using License Keys topic in MailBee.NET Objects documentation for details.

Option A - specify license key directly in code

Before the first use and creating any instances of Imap or Pop3 classes, set the static MailBee.Global.LicenseKey property to assign the license key. It's assumed you've already imported MailBee.ImapMail (or MailBee.Pop3Mail) namespace with using (C#) or Imports (VB) directives.

MailBee.Global.LicenseKey = "MN100-0123456789ABCDEF-0123";
MailBee.Global.LicenseKey = "MN100-0123456789ABCDEF-0123"

You can also create and unlock instances of Imap and Pop3 classes, passing the license key as a parameter of a constructor, such as Imap(string). Again, it's assumed you've already imported MailBee.ImapMail (or MailBee.Pop3Mail) namespace.

Imap imp = newImap("MN100-0123456789ABCDEF-0123");
Dim imp As New Imap("MN100-0123456789ABCDEF-0123")

Option B - put license key in app.config or web.config

Alternatively, you can add app.config to your project (if you do not already have it there) and specify MailBee.NET SMTP license key there.

For ASP.NET application, web.config is always available so that you can immediately edit it, but for other application types you may have to add app.config manually.

The below we are using Visual Studio 2010. For a Visual Studio 2008 version, refer to a similar topic in SMTP guide.

In Projects menu, click Add New Item:

Select Application Configuration File and click Add:

In app.config, locate <appSettings/> entry in <configuration> section (if it's not there, create it), and add MailBee.NET license key as follows:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="MailBee.Global.LicenseKey" value="MN100-0123456789ABCDEF-0123"/>
  </appSettings>
</configuration>

Note that <appSettings> may also appear as <applicationSettings> in your case.

If <appSettings> originally looked as <appSettings/> (self-closing tag syntax), you'll need to unfold it to <appSettings></appSettings> so that you could insert <add key .../> there.

The above also applies to ASP.NET application and web.config.

You can also specify the key in machine.config file. This will enable access to the license key to all applications on the computer so that there will be no need to specify the license key in each application separately. For instance, this is the preferred way if you a hosting provider willing to let your hosting clients create and run applications which use MailBee.NET without disclosing your license key to them.


Retrieve e-mail with a single line of code

You can download e-mails in a single of code using these static methods of Imap or Pop3 classes:

For all the samples in this guide, we assume the license key is already set (such as in app.config file), and these namespaces are imported: MailBee.Mime, and MailBee.ImapMail or MailBee.Pop3Mail.

This sample downloads the last e-mail in Inbox via POP3, and displays its HTML body text if any:

MailMessage msg = Pop3.QuickDownloadMessage("pop.domain.com""jdoe""secret", -1);
Console.WriteLine(msg.BodyHtmlText);
Dim msg As MailMessage = Pop3.QuickDownloadMessage("pop.domain.com""jdoe""secret", -1)
Console.WriteLine(msg.BodyHtmlText)

Note that you'll get an exception in case if the Inbox is empty.

You may also get an exception if the server requires SSL. See Retrieve e-mail from server which requires SSL (e.g. Gmail) for details.

The next sample downloads the first e-mail in Inbox via IMAP, and displays its plain-text body. If the e-mail contains only HMTL body, MailBee.NET will convert the HMTL into plain-text automatically:

MailMessage msg = Imap.QuickDownloadMessage("imap.domain.com""jdoe""secret""Inbox", 1);
msg.Parser.HtmlToPlainMode = HtmlToPlainAutoConvert.IfNoPlain;
Console.WriteLine(msg.BodyPlainText);
Dim msg As MailMessage = Imap.QuickDownloadMessage("imap.domain.com""jdoe""secret""Inbox", 1)
msg.Parser.HtmlToPlainMode = HtmlToPlainAutoConvert.IfNoPlain
Console.WriteLine(msg.BodyPlainText)

If the Inbox is empty, you'll get an exception.

The sample below downloads headers for all e-mails in a POP3 inbox, and displays their subjects:

MailMessageCollection msgs =
    Pop3.QuickDownloadMessages("pop.company.com", "jdoe@company.com", "secret", 0);

if (msgs.Count > 0)
{
    foreach (MailMessage msg in msgs)
    {
        Console.WriteLine(msg.Subject);
    }
}
else
{
    Console.WriteLine("Inbox is empty");
}
Dim msgs As MailMessageCollection = _
    Pop3.QuickDownloadMessages("pop.company.com", "jdoe@company.com", "secret", 0)

If msgs.Count > 0 Then
   Dim msg As MailMessage
   For Each msg In  msgs
      Console.WriteLine(msg.Subject)
   Next msg
Else
   Console.WriteLine("Inbox is empty")
End If

As you can see, this sample can handle the situation when the Inbox is empty.

The next sample completely downloads all e-mails in IMAP inbox, and displays the size of every attachment found (making no difference between real attachments and linked resources):

MailMessageCollection msgs =
    Imap.QuickDownloadMessages("pop.company.com", "jdoe@company.com", "secret", "Inbox");

if (msgs.Count > 0)
{
    foreach (MailMessage msg in msgs)
    {
        if (msg.Attachments.Count > 0)
        {
            Console.WriteLine("Attachment size list for message " +
                msg.UidOnServer.ToString());
            foreach (Attachment attach in msg.Attachments)
            {
                Console.WriteLine(attach.Size.ToString());
            }
        }
        else
        {
            Console.WriteLine("Message " + msg.UidOnServer.ToString() +
                " has no attachments");
        }

        Console.WriteLine();
    }
}
else
{
    Console.WriteLine("Inbox is empty");
}
Dim msgs As MailMessageCollection = _
    Imap.QuickDownloadMessages("pop.company.com", "jdoe@company.com", "secret", "Inbox")

If msgs.Count > 0 Then
   Dim msg As MailMessage
   For Each msg In msgs
      If msg.Attachments.Count > 0 Then
         Console.WriteLine("Attachment size list for message " & msg.UidOnServer.ToString())
         Dim attach As Attachment
         For Each attach In msg.Attachments
            Console.WriteLine(attach.Size.ToString())
         Next attach
      Else
         Console.WriteLine("Message " & msg.UidOnServer.ToString() & " has no attachments")
      End If

      Console.WriteLine()
   Next msg
Else
   Console.WriteLine("Inbox is empty")
End If

These single-line methods which don't require you to create instances of Imap or Pop3 classes, however, have some drawbacks:

The main purpose of the single-line methods is for quick testing during the development process. For instance, if you're developing some sort of e-mail viewer, you can temporarily use a quick method there to have some e-mail to test your e-mail viewer with, without the need of implementing production-level e-mail retrieval code at the moment when you're focused on other tasks.


Save all attachments of downloaded e-mail

The samples below download the last e-mail in Inbox and save all its attachments into a local folder (skipping linked resources like inline images). The first sample uses "quick" method to download the e-mail while the second sample creates an instance of Imap or Pop3 class.

Download e-mail with Imap.QuickDownloadMessage or Pop3.QuickDownloadMessage method:

MailMessage imapMsg =
    Imap.QuickDownloadMessage("imap.company.com", "jdoe@company.com", "secret", "Inbox", -1);
imapMsg.Attachments.SaveAll("C:\\Docs", true);

MailMessage popMsg =
    Pop3.QuickDownloadMessage("pop.company.com", "jdoe@company.com", "secret", -1);
popMsg.Attachments.SaveAll("C:\\Docs", true);
Dim imapMsg As MailMessage = _
    Imap.QuickDownloadMessage("imap.company.com", "jdoe@company.com", "secret", "Inbox", -1)
imapMsg.Attachments.SaveAll("C:\Docs", True)

Dim popMsg As MailMessage = _
    Pop3.QuickDownloadMessage("pop.company.com", "jdoe@company.com", "secret", -1)
popMsg.Attachments.SaveAll("C:\Docs", True)

Download e-mail normally, with Imap.DownloadEntireMessage or Pop3.DownloadEntireMessage method:

Imap imp = new Imap();
imp.Connect("imap.company.com");
imp.Login("jdoe@company.com", "secret");
imp.SelectFolder("Inbox");
MailMessage imapMsg = imp.DownloadEntireMessage(imp.MessageCount, false);
imp.Disconnect();
imapMsg.Attachments.SaveAll("C:\\Docs", true);

Pop3 pop = new Pop3();
pop.Connect("pop.company.com");
pop.Login("jdoe@company.com", "secret");
MailMessage popMsg = pop.DownloadEntireMessage(pop.InboxMessageCount);
pop.Disconnect();
popMsg.Attachments.SaveAll("C:\\Docs", true);
Dim imp As New Imap()
imp.Connect("imap.company.com")
imp.Login("jdoe@company.com", "secret")
imp.SelectFolder("Inbox")
Dim imapMsg As MailMessage = imp.DownloadEntireMessage(imp.MessageCount, False)
imp.Disconnect()
imapMsg.Attachments.SaveAll("C:\Docs", True)

Dim pop As New Pop3()
pop.Connect("pop.company.com")
pop.Login("jdoe@company.com", "secret")
Dim popMsg As MailMessage = pop.DownloadEntireMessage(pop.InboxMessageCount)
pop.Disconnect()
popMsg.Attachments.SaveAll("C:\Docs", True)

From now on, we'll always create instances of Imap and Pop3 class when accessing e-mail on the server.

Also note that we disconnect from the server BEFORE saving attachments. Although it's not required, this lets the application free the connection not waiting until all the attachments get saved (which might take some time). Shortly speaking, just a little optimization here.


Display HTML e-mail with embedded pictures

Assuming you downloaded an e-mail and got a MailMessage object, you can then get its HTML body via BodyHtmlText property. However, if the message has images attached, they may not be displayed. It's needed to either save these attachments locally and then modify IMG SRC of these images in the HTML body to reflect saved local files locations or embed these images directly in the HTML body with data:base64 URIs. The latter approach is very easy to use:

string html = msg.GetHtmlWithBase64EncodedRelatedFiles();
Dim html As String = msg.GetHtmlWithBase64EncodedRelatedFiles()

You can then load this HTML content in any browser control or send it as a response to the client in case of a web application.

If embedding into HTML body is not an option for you, you can also store embedded images on the filesystem of the server using MailMessage.GetHtmlAndSaveRelatedFiles method or on an external storage (e.g. Amazon S3 or whatever) using MailMessage.GetHtmlAndRelatedFilesInMemory method.


Display international e-mail addresses (IDN domains)

If you need to correcty display e-mail addresses with non-Latin domain names (they are usually encoded in Punycode), you can decode them in human-readable form with EmailAddress.FromIdnAddress, EmailAddressCollection.FromIdnAddress or EmailAddress.UnescapeIdnDomain methods.

It's safe to use these methods even if the address is not encoded (the methods will return the same value as on input).

string humanReadableEmail = msg.From.FromIdnAddress().Email;
Dim humanReadableEmail As String = msg.From.FromIdnAddress().Email

Make IMAP version from POP3 code

Note that POP3 and IMAP samples of downloading e-mail can be very close to each other. The main differences are:

This makes it easy to adapt most POP3 samples to IMAP (or vice versa, IMAP to POP3):

Given the above and for brevity's sake, many samples in this tutorial feature only POP3 or IMAP support, with the appropriate comments in protocol-specific portions. The samples which are completely specific to IMAP or POP3 are accompanied with a special note.

if you deal with ranges of e-mails (e.g. you need to display a page of 20 e-mails, from 11th to 30th), you should know about yet another difference between how ranges are specified in POP3 and IMAP:

Operations other than downloading e-mail (such as search for new e-mails), can be very different between POP3 and IMAP (and even not always possible with POP3 at all).


Retrieve and parse headers for all e-mails in Inbox

This sample gets headers of all e-mails in the Inbox, and prints From, To, Subject for every e-mail whose header was downloaded:

Imap imp = new Imap();
imp.Connect("imap.company.com");
imp.Login("jdoe@company.com", "secret");
imp.SelectFolder("Inbox");
MailMessageCollection msgs = imp.DownloadMessageHeaders(Imap.AllMessages, false);
// POP3 version: msgs = pop.DownloadMessageHeaders();
imp.Disconnect();

foreach (MailMessage msg in msgs)
{
    Console.WriteLine("From: " + msg.From.ToString());
    Console.WriteLine("To: " + msg.To.ToString());
    Console.WriteLine("Subject: " + msg.Subject);
    Console.WriteLine();
}
Dim imp As New Imap()
imp.Connect("imap.company.com")
imp.Login("jdoe@company.com", "secret")
imp.SelectFolder("Inbox")
Dim msgs As MailMessageCollection = imp.DownloadMessageHeaders(Imap.AllMessages, False)
' POP3 version: msgs = pop.DownloadMessageHeaders()
imp.Disconnect()

Dim msg As MailMessage
For Each msg In msgs
   Console.WriteLine("From: " & msg.From.ToString())
   Console.WriteLine("To: " & msg.To.ToString())
   Console.WriteLine("Subject: " & msg.Subject))
   Console.WriteLine()
Next msg

Retrieve ranges of e-mails

Because ranges are set differently in POP3 and IMAP, two different samples in this topic.

This sample downloads the last 10 e-mails in Inbox via POP3:

Pop3 pop = new Pop3();
pop.Connect("mail.domain.com");
pop.Login("jdoe", "secret");
if (pop.InboxMessageCount > 0)
{
    // If the inbox contains less than 10 e-mails, adjust to that.
    int msgCount = pop.InboxMessageCount > 10 ? 10 : pop.InboxMessageCount;

    // As e-mail indices on the server start with 1 (not 0), must add 1.
    MailMessageCollection msgs =
        pop.DownloadMessageHeaders(pop.InboxMessageCount - msgCount + 1, msgCount);

    foreach (MailMessage msg in msgs)
    {
        Console.WriteLine("Message #" + msg.IndexOnServer.ToString());
        Console.WriteLine("From: " + msg.From.ToString());
        Console.WriteLine("To: " + msg.To.ToString());
        Console.WriteLine("Subject: " + msg.Subject);
        Console.WriteLine();
    }
}
else
{
    Console.WriteLine("Inbox is empty");
}
pop.Disconnect();
Dim pop As New Pop3()
pop.Connect("mail.domain.com")
pop.Login("jdoe", "secret")
If pop.InboxMessageCount > 0 Then
   ' If the inbox contains less than 10 e-mails, adjust to that.
   Dim msgCount As Integer = IIf(pop.InboxMessageCount > 10, 10, pop.InboxMessageCount)

   ' As e-mail indices on the server start with 1 (not 0), must add 1.
   Dim msgs As MailMessageCollection = _
       pop.DownloadMessageHeaders(pop.InboxMessageCount - msgCount + 1, msgCount)

   Dim msg As MailMessage
   For Each msg In msgs
      Console.WriteLine("Message #" & msg.IndexOnServer.ToString())
      Console.WriteLine("From: " & msg.From.ToString())
      Console.WriteLine("To: " & msg.To.ToString())
      Console.WriteLine("Subject: " & msg.Subject)
      Console.WriteLine()
   Next msg
Else
   Console.WriteLine("Inbox is empty")
End If
pop.Disconnect()

The IMAP version of the sample:

Imap imp = new Imap();
imp.Connect("mail.domain.com");
imp.Login("jdoe", "secret");
imp.SelectFolder("Inbox");
if (imp.MessageCount > 0)
{
    // If the inbox contains less than 10 e-mails, adjust to that.
    int msgCount = imp.MessageCount > 10 ? 10 : imp.MessageCount;

    // As e-mail indices on the server start with 1 (not 0), must add 1.
    int firstIndex = imp.MessageCount - msgCount + 1;
    int lastIndex = imp.MessageCount;
    MailMessageCollection msgs = imp.DownloadMessageHeaders(
        firstIndex.ToString() + ":" + lastIndex.ToString(), false);

    foreach (MailMessage msg in msgs)
    {
        Console.WriteLine("Message #" + msg.IndexOnServer.ToString());
        Console.WriteLine("From: " + msg.From.ToString());
        Console.WriteLine("To: " + msg.To.ToString());
        Console.WriteLine("Subject: " + msg.Subject);
        Console.WriteLine();
    }
}
else
{
    Console.WriteLine("Inbox is empty");
}
imp.Disconnect();
Dim imp As New Imap()
imp.Connect("mail.domain.com")
imp.Login("jdoe", "secret")
imp.SelectFolder("Inbox")
If imp.MessageCount > 0 Then
   ' If the inbox contains less than 10 e-mails, adjust to that.
   Dim msgCount As Integer = IIf(imp.MessageCount > 10, 10, imp.MessageCount)

   ' As e-mail indices on the server start with 1 (not 0), must add 1.
   Dim firstIndex As Integer = imp.MessageCount - msgCount + 1
   Dim lastIndex As Integer = imp.MessageCount
   Dim msgs As MailMessageCollection = imp.DownloadMessageHeaders( _
       firstIndex.ToString() & ":" & lastIndex.ToString(), False)

   Dim msg As MailMessage
   For Each msg In msgs
      Console.WriteLine("Message #" & msg.IndexOnServer.ToString())
      Console.WriteLine("From: " & msg.From.ToString())
      Console.WriteLine("To: " & msg.To.ToString())
      Console.WriteLine("Subject: " & msg.Subject)
      Console.WriteLine()
   Next msg
Else
   Console.WriteLine("Inbox is empty")
End If
imp.Disconnect()

Actually, IMAP ranges are much more powerful, they are rather sets than ranges. For instance, you can list multiple individual messages or ranges in a single set, separating them with commas. Example: 5,17,24:30,45:60,122.

You can also use the IMAP syntax like 10:*. It means "select all e-mails from 10th to the last e-mail in the folder".


Detect and retrieve new e-mails

Let's assume we need to completely download all new e-mails and display the attachment count for every downloaded message.

With IMAP, it's very simple as the IMAP server can track new e-mails itself:

Imap imp = new Imap();
imp.Connect("mail.domain.com");
imp.Login("john.doe@company.com", "secret");
imp.SelectFolder("Inbox");
UidCollection uids = (UidCollection)imp.Search(true, "NEW", null);
if (uids.Count > 0)
{
    MailMessageCollection msgs = imp.DownloadEntireMessages(uids.ToString(), true);
    foreach (MailMessage msg in msgs)
    {
        Console.WriteLine("Message #" + msg.IndexOnServer.ToString() +
            " has " + msg.Attachments.Count + " attachment(s)");
    }
}
else
{
    Console.WriteLine("No new messages");
}
imp.Disconnect();
Dim imp As New Imap()
imp.Connect("mail.domain.com")
imp.Login("john.doe@company.com", "secret")
imp.SelectFolder("Inbox")
Dim uids As UidCollection = CType(imp.Search(True, "NEW", Nothing), UidCollection)
If uids.Count > 0 Then
   Dim msgs As MailMessageCollection = imp.DownloadEntireMessages(uids.ToString(), True)
   Dim msg As MailMessage
   For Each msg In msgs
       Console.WriteLine("Message #" & msg.IndexOnServer.ToString() & _
           " has " & msg.Attachments.Count & " attachment(s)")
   Next msg
Else
   Console.WriteLine("No new messages")
End If
imp.Disconnect()

The sample above uses Unique-IDs (UIDs) instead of ordinal message numbers but it would work with message numbers too provided that nobody access the same mailbox simultaneously.

Also note that all the e-mails found are then downloaded with a single command. This may or may not be acceptable in your case. This is fast but may consume too much memory if there are many new e-mails are they are big. Usually, downloading multiple e-mails in a single command makes sense when you download just message headers (because they are quite small).

With POP3, the server knows nothing about new e-mails and you'll need to find out which e-mails are new by yourself.

Even with IMAP, you may also need to implement search for new e-mails manually in case if your idea of which e-mails are new is different from what your server thinks on the same matters. For the server, the e-mail is no longer new if anyone has already selected the folder which contains this e-mail (even if this person never downloaded the e-mail).

If you need to detect not the e-mails which just arrived but all the e-mails you have never seen (and never downloaded), use UNSEEN search flag instead of NEW.


Delete e-mails from server

Imap.DeleteMessagesPop3.DeleteMessagePop3.DeleteMessages methods mark e-mails for deletion.

However, none of these methods actually delete e-mails from the mailbox. To purge e-mails marked as deleted, you should properly close the POP3 session with Pop3.Disconnect or close the IMAP folder with Imap.Close. However, there can be exceptions from this rule (Gmail is an example).

This sample deletes and purges all e-mails in Inbox (don't run it on your working e-mail account as you'll lose all the e-mails there):

Imap imp = new Imap();
imp.Connect("mail.domain.com");
imp.Login("john.doe@company.com""secret");
imp.SelectFolder("Inbox");
imp.DeleteMessages(Imap.AllMessages, false);
imp.Close();
imp.Disconnect();
Dim imp As New Imap()
imp.Connect("mail.domain.com")
imp.Login("john.doe@company.com""secret")
imp.SelectFolder("Inbox")
imp.DeleteMessages(Imap.AllMessages, False)
imp.Close()
imp.Disconnect()

The POP3 version:

Pop3 pop = new Pop3();
pop.Connect("mail.domain.com");
pop.Login("john.doe@company.com""secret");
pop.DeleteMessages();
pop.Disconnect();
Dim pop As New Pop3()
pop.Connect("mail.domain.com")
pop.Login("john.doe@company.com""secret")
pop.DeleteMessages()
pop.Disconnect()

Note that some servers may, for instance, not let you delete e-mail via POP3 or may simply ignore the deletion request. The typical example of a non-standard POP3 and IMAP behaviour is Gmail. See Gmail IMAP and POP3 issues topic for details.


Upload e-mails to IMAP server

This sample creates an empty e-mail with "Message draft" text in the subject and attempts to upload it into Drafts folder on the IMAP server. If the server responds with a negative reply (probably because the folder does not exist), the sample tries to upload into Inbox then:

Imap imp = new Imap();
imp.Connect("mail.domain.com");
imp.Login("john.doe@company.com", "secret");
MailMessage msg = new MailMessage();
msg.Subject = "Message draft";
try
{
    Console.WriteLine("Upload to Drafts");
    imp.UploadMessage(msg, "Drafts");
}
catch (MailBeeImapNegativeResponseException e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine("Upload to inbox");
    imp.UploadMessage(msg, "Inbox");
}
imp.Disconnect();
Dim imp As New Imap()
imp.Connect("mail.domain.com")
imp.Login("john.doe@company.com", "secret")
Dim msg As New MailMessage()
msg.Subject = "Message draft"
Try
   Console.WriteLine("Upload to Drafts")
   imp.UploadMessage(msg, "Drafts")
Catch e As MailBeeImapNegativeResponseException
   Console.WriteLine(e.Message)
   Console.WriteLine("Upload to inbox")
   imp.UploadMessage(msg, "Inbox")
End Try
imp.Disconnect()

You can also upload e-mails you just sent with SMTP, get the UID assigned to the uploaded e-mail, set flags and date, and so on.


Access e-mail in IMAP folders besides Inbox

Just supply the folder name in Imap.SelectFolder call (or Imap.ExamineFolder for read-only access to the folder).

This sample attempts to select "Sent Items" folder. If the server responds with a negative reply, the sample downloads the list of all available folders and displays their names:

Imap imp = new Imap();
imp.Connect("imap.domain.com");
imp.Login("john.doe", "secret");
try
{
    imp.SelectFolder("Sent Items");
}
catch (MailBeeImapNegativeResponseException e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine();
    Console.WriteLine("The available folders are:");
    FolderCollection folders = imp.DownloadFolders();
    foreach (Folder f in folders)
    {
        Console.WriteLine(f.Name);
    }
}
imp.Disconnect();
Dim imp As New Imap()
imp.Connect("imap.domain.com")
imp.Login("john.doe", "secret")
Try
   imp.SelectFolder("Sent Items")
Catch e As MailBeeImapNegativeResponseException
   Console.WriteLine(e.Message)
   Console.WriteLine()
   Console.WriteLine("The available folders are:")
   Dim folders As FolderCollection = imp.DownloadFolders()
   Dim f As Folder
   For Each f In  folders
      Console.WriteLine(f.Name)
   Next f
End Try
imp.Disconnect()

Retrieve e-mail from server which requires SSL (e.g. Gmail)

For Gmail.com, Outlook.com and some other popular services MailBee.NET detects SSL settings automatically. For instance. just specify the host name as imap.gmail.com for IMAP or pop.gmail.com for POP3.

It also works with Live.com, Outlook.com, Hotmail.com. At the moment of writing, the host names to specify are imap-mail.outlook.com and pop-mail.outlook.com for all these domains.

For other IMAP-over-SSL and POP3-over-SSL services, you'll need to set the SSL port explicitly.

The standard IMAP-over-SSL port is 993:

Imap imp = new Imap();
imp.Connect("imap.domain.com", 993);
Dim imp As New Imap()
imp.Connect("imap.domain.com", 993)

The standard POP3-over-SSL port is 995:

Pop3 pop = new Pop3();
pop.Connect("pop.domain.com", 995);
Dim pop As New Pop3()
pop.Connect("pop.domain.com", 995)

By default, MailBee.NET uses the most secure SSL protocol supported by the server (usually, TLS). This is controlled by Imap.SslProtocol and Pop3.SslProtocol properties.

You can also enable STARTTLS mode to use SSL over regular 143 or 110 port by any of these methods: - Set Imap.SslMode or Pop3.SslMode property to SslStartupMode.UseStartTls value BEFORE connecting to the server. - Or, call Imap.StartTls/Pop3.StartTls AFTER connecting to the server.


Gmail IMAP and POP3 issues

Gmail.com, being mostly a web-based e-mail service, provides quite a special implementation of IMAP and POP3 protocols. This topic describes some issues that you should know about.

To configure IMAP and POP3 settings of your Gmail account, open Forwarding and POP/IMAP tab:

POP3 notes:

IMAP notes:

UidCollection uc = (UidCollection)imp.Search(true, "TEXT " + ImapUtils.ToLiteral("Some text"), "utf-8");
Dim uc As UidCollection = CType(imp.Search(True, "TEXT " & ImapUtils.ToLiteral("Some text"), "utf-8"), UidCollection)

Or you can use Google-specific method which gives you all the power of Google search syntax:

UidCollection uc = (UidCollection)imp.Search(true, "TEXT " + ImapUtils.GmailSearch("Some text"), "utf-8");
Dim uc As UidCollection = CType(imp.Search(True, "TEXT " & ImapUtils.GmailSearch("Some text"), "utf-8"), UidCollection)

If you experience Web login required error in Gmail IMAP or POP3, open https://www.google.com/accounts/DisplayUnlockCaptcha page in the browser and confirm your identity to Google. After that, IMAP and POP3 access should be working again.

If you need to disable the auto-detection of Gmail SSL settings, set MailBee.Global.AutodetectPortAndSslMode to false.


MS Exchange IMAP and POP3 issues

This topic is mainly for MS Exchange 2007-2016 and Office 365 (which is powered by MS Exchange 2016). For MS Exchange 2003, many of the issues described below do not apply. Sadly, IMAP and POP3 support in MS Exchange has degraded in newer versions.

The major specifics of MS Exchange POP3 and IMAP access is that MS Exchange mostly targets Outlook clients which work with MS Exchange via MAPI, not POP3 or IMAP. Therefore, neither IMAP nor POP3 is even enabled in MS Exchange by default. Make sure the service required for your application is running.

IMAP/POP access can also be blocked on a user level. Make sure the e-mail account you're using has IMAP/POP access enabled. However, Administrator user cannot have IMAP/POP access enabled under any circumstances.

You'll need to connect via SSL or use secure authentication. MS Exchange 2010 supports only GSSAPI which is, however, supported by MailBee.NET either.

Feature set of MS Exchange is also more limited than in most other IMAP servers. For instance, you cannot use search with international charsets (such as UTF-8). Only ASCII is supported.

You may consider switching to EWS (Exchange Web Services) when working with MS Exchange or Office 365 server. See Ews topic for examples.


Log file of IMAP and POP3 session

You can enable logging of IMAP or POP3 conversation between MailBee.NET client and the server in a number of ways. You can use logging into a file or memory, subscribe to Imap.LogNewEntry or Pop3.LogNewEntry event which raises each time a new log record is about to be created, and much more.

Logging is useful for trouble-shooting and tracking all the activity for later use. The code below enables logging of all the activity of Imap and Pop3 objects into a file and clears that file:

Imap imp = new Imap();
imp.Log.Enabled = true;
imp.Log.Filename = "C:\\Temp\\imap_log.txt";
imp.Log.Clear();

Pop3 pop = new Pop3();
pop.Log.Enabled = true;
pop.Log.Filename = "C:\\Temp\\pop3_log.txt";
pop.Log.Clear();
Dim imp As New Imap()
imp.Log.Enabled = True
imp.Log.Filename = "C:\Temp\imap_log.txt"
imp.Log.Clear()

Dim pop As New Pop3()
pop.Log.Enabled = True
pop.Log.Filename = "C:\Temp\pop3_log.txt"
pop.Log.Clear()

Troubleshoot common errors and problems

Typical issues you may face and their possible remedy:

As a general suggestion, read carefully the exception message as it may already provide some useful information, and always enable logging when you face any connectivity errors. The log file is a very helpful source of the debug information which you can use to understand and fix the issue or send it to AfterLogic Support Team for further analysis.

To learn how to enable logging, see Log file of IMAP and POP3 session topic. To submit the log file to AfterLogic, create a ticket at http://helpdesk.afterlogic.com and upload the file there.

In case if certain e-mail cannot be parsed properly, you can save it as .EML file using MailMessage.SaveMessage method, and then open it in Mozilla Thunderbird. Does it look correctly there? If it's displayed OK, you can then submit it to AfterLogic as described above.


Send feedback to AfterLogic

Copyright © 2006-2017 AfterLogic Corporation. All rights reserved.