Validating email addresses

Need to determine whether the recipient’s email address exists? That’s how.

For this task, we’ll use Address Validator – one of the components of MailBee.NET Objects library for .NET platform. There are several validation levels you can use, depending on how precise you need the validation to be:

1) RegexCheck will simply check if the string value looks like an actual email address. The biggest benefit of this validation method is that it’s very fast, it doesn’t perform any network operations. And if the check says the email address is invalid, it will stay invalid today, tomorrow, next year – so it’s safe to remove that address from your database.

2) DnsQuery will, in addition to syntax check, take the domain part of email address and run DNS MX lookup to determine if there are SMTP MX hosts which are able to accept email for that domain. While that still doesn’t allow for determining whether email account itself exists, but it’s very useful for confirming that it’s possible to deliver mails to that domain.

To run such a check, you can have one or several DNS servers specified – and in case of multiple DNS servers, load between them will be distributed automatically.

3) SmtpConnection performs DNS MX lookup and additionally attempts to connect to port 25 of SMTP server found during the lookup. If test connection is successful, that would mean the host is actually able to accept emails for the particular domain.

4) SendAttempt is the most advanced check method available, it determines SMTP MX for the domain, connects to that host, sends EHLO/HELO and MAIL FROM command. Basically, it will imitate sending mail out using that MX host, but will not send actual message data. If the check is successful, that means the server is fine with accepting email messages for the particular recipient.

As you can see, each next validation level includes all the previous ones. The higher the level, the more accurate check is. But if you’re going to use SmtpConnection and SendAttempt levels, make sure your system has a public IP address with a valid reverse DNS record. Ideally, you should run such a validation from a system with well established mail server running there, and with proper DNS records pointing to it. It’s also important to ensure that your system is not in blacklists, the checks may fail otherwise.

The following example shows how to run a validation check for a single email address:

using System;
using MailBee;
using MailBee.AddressCheck;

class Program
{
    static void Main(string[] args)
    {
        EmailAddressValidator valid = new EmailAddressValidator("MN100-0123456789ABCDEF-0123");

        // To perform DNS MX lookup queries, we need some DNS servers for that.
        valid.DnsServers.Autodetect();

        // Logging into a file is not required for the component to work
        // but helpful for debugging and understanding things under the hood.
        valid.Log.Enabled = true;
        valid.Log.Filename = @"C:\Temp\log.txt";
        valid.Log.Clear();

        AddressValidationLevel result = valid.Verify("jdoe@company.com");
        Console.WriteLine(result.ToString());
    }
}

Note that SendAttempt is the default validation method used, so there’s no need to specify it explicitly.

If the validation was successful, AddressValidationLevel.OK is returned – otherwise, result shows the particular validation level at which the verification failed. RegexCheck result means the email address is bad and cannot be used. DnsQuery result means that DNS MX lookup has failed; it might be a temporary failure though, so it’s best to mark the address in your database as a potentially bad one and try another check in a few days. Same goes for SmtpConnection result – MX host may be down temporarily.

And if you get SendAttempt result, it may mean that sending attempt failed due to greylisting, a spam prevention technique that makes server respond with something like “try again later” – and if you actually try again later, e.g. in an hour, the email address may pass the check then. You can also check Reason property of the Verified event arguments as it may help understanding why the address has failed the validation.

If you validate a large number of email addresses, you can make use of multi-threading for a great performance boost. With up to 60 threads used, you can check up to 100K addresses per hour – all that with the most accurate check method available. This sample demonstrates validating multiple email address, with multi-threading used:

using System;
using MailBee;
using MailBee.AddressCheck;

class Program
{
    // This method will be executed for each e-mail address in the bulk,
    // whenever it gets verified, with either positive or negative result.
    private static void valid_Verified(object sender, VerifiedEventArgs e)
    {
        Console.WriteLine("*** Verified ***");
        Console.WriteLine("Email: " + e.Email);
        Console.WriteLine("Result: " + e.Result.ToString());
        if (e.Reason != null)
        {
            Console.WriteLine("Reason: " + e.Reason.Message);
        }
        Console.WriteLine();
    }

    static void Main(string[] args)
    {
        EmailAddressValidator valid = new EmailAddressValidator("MN100-0123456789ABCDEF-0123");

        // To perform DNS MX lookup queries, we need some DNS servers for that.
        valid.DnsServers.Autodetect();

        // Logging into a file is not required for the component to work
        // but helpful for debugging and understanding things under the hood.
        valid.Log.Enabled = true;
        valid.Log.Format = LogFormatOptions.AddContextInfo;
        valid.Log.Filename = @"C:\Temp\log.txt";
        valid.Log.Clear();

        // Subscribe to event.
        valid.Verified += new VerifiedEventHandler(valid_Verified);

        string[] emails = new string[] { "jdoe@company.com", "bob@example.com", "alice@domain.com" };

        // Run the verification in multi-threaded mode.
        valid.MaxThreadCount = -1;
        valid.Verify(emails);
    }
}
Validating email addresses

Getting instant notifications on new emails with IMAP IDLE

If your application uses IMAP and it needs to know when a new message arrives to mailbox, there are two approaches which let you do that.

One of the methods is known as polling, your application connects to mail server every once in a while and checks for new messages. This is how most web-based email applications work, they can actually sync the list of messages between IMAP server and their database, or simply check for recent messages, IMAP protocol has built-in support for that – you can either search for UNSEEN messages, which means those you didn’t download yet, or NEW messages which just arrived.

The other approach assumes that your application stays connected to the mail server, and once a new message arrives, the mail server would immediately notify your application. This approach is made available by IMAP IDLE extension, it’s supported by the majority of mail servers out there, and as long as your application can maintain the persistent connection to the mail server, you should be able to use IMAP IDLE. Note that while this method can’t really be used with web applications which must return the response as fast as possible and terminate, it’s fairly simple to utilize it for desktop or server apps which can afford long-lived connections.

MailBee.NET Objects, email library for .NET platform, supports both the methods. To locate mails which just arrived, you simply run IMAP search for NEW messages:

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();

As for the second approach, documentation for MailBee.NET Objects includes a tutorial on using IMAP IDLE, with two samples, one of them is designed for .NET 4.5 and uses async/await methods.

Below is a very simple example that demonstrates the idea. To run this sample, put button1 button on the form and attach Form1_Closing method to Closing event of the form.

// To use the code below, import MailBee namespaces at the top of your code
using MailBee;
using MailBee.ImapMail;

// Put the code below inside your class.

// Imap object declared global because it's accessed from several methods.
Imap imp = null;

bool finished = false;
bool started = false;

// Idling event is used to keep UI responsive and stop idling is desired.
private void imp_Idling(object sender, ImapIdlingEventArgs e)
{
    Application.DoEvents();
    if (finished)
    {
        ((Imap)sender).StopIdle();
        button1.Text = "Go idle";
    }
}

// Monitor folder changes and save them in the log file.
private void imp_MessageStatus(object sender, ImapMessageStatusEventArgs e)
{
    ((Imap)sender).Log.WriteLine("Got " + e.StatusID + " status update");
}

// Start/stop idling.
// Add button1 on the form to make this sample working.
private void button1_Click(object sender, System.EventArgs e)
{
    if (started)
    {
        finished = true;
    }
    else
    {
        started = true;

        imp = new Imap();

        // Enable logging into a file.
        imp.Log.Filename = @"C:\Temp\log.txt";
        imp.Log.Enabled = true;
        imp.Log.Clear();

        // Connect to the server and check if IDLE is supported.
        imp.Connect("mail.domain.com");
        if (imp.GetExtension("IDLE") == null)
        {
            MessageBox.Show("IDLE not supported");
        }
        else
        {
            // Login and select inbox.
            imp.Login("jdoe", "secret");
            imp.SelectFolder("Inbox");

            // Attach event handlers.
            imp.Idling += new ImapIdlingEventHandler(imp_Idling);
            imp.MessageStatus +=new ImapMessageStatusEventHandler(imp_MessageStatus);

            button1.Text = "Stop idle";

            // Go idle. This call will block until imp.StopIdle()
            // is called from elsewhere.
            imp.Idle();
        }

        // Disconnect from the server.
        imp.Disconnect();

        started = false;
        finished = false;
    }
}

// Finish idling if the user closes the application.
// To make this method work, attach it to Closing event of the form.
private void Form1_Closing(object sender,
    System.ComponentModel.CancelEventArgs e)
{
    if (imp != null && imp.IsBusy)
    {
        imp.StopIdle();
    }
}

The sample takes care of checking if IDLE is supported by the server, stopping idling if requested or if the application is closed by the user. 

The tricky part about using IDLE is that the single IDLE session cannot be longer than 30 minutes, so your application will need to reconnect to server periodically.

From my experience, the interval of 15 minutes is sufficient for most servers. But I’ve recently found out that, for example, GoDaddy IMAP server terminates IDLE session after 2 minutes, and MailBee logs show this:

[05/05/2021 16:48:38.64] [INFO] Will go idle.
[05/05/2021 16:49:07.07] [SEND] MBN00000008 IDLE\r\n
[05/05/2021 16:49:08.10] [RECV] + idling\r\n [Total 10 bytes received.]
[05/05/2021 16:51:08.20] [INFO] Error: Socket connection was aborted by remote host.
[05/05/2021 16:51:08.20] [INFO] Will disconnect from host "imap.secureserver.net".
[05/05/2021 16:51:08.21] [INFO] Disconnected from host "imap.secureserver.net".
[05/05/2021 16:51:08.23] [INFO] Error: Not yet connected to the server. Call Connect first.

So if you encounter a similar issue, it would make sense to try restarting IDLE every 60-90 seconds rather than every 15-25 minutes for a typical scenario.

Getting instant notifications on new emails with IMAP IDLE

Using MailBee.NET EWS to access Office 365 mailbox in non-interactive case

I recently posted an article on how to access Office 365 mailbox for a non-interactive application (where users don’t need to provide their consent to the app to access their mailboxes). In that sample, we had to use MS Graph instead of IMAP access, to make use of OAuth 2.0. There is, however, another option – EWS.

Again, we’ll use MailBee.NET Objects as a library for making connections with the mail server. It’s a set of email components for .NET platform, and it allows for accessing MS Exchange servers (including Office 365) via Exchange Web Services. Since we’re speaking of a non-interactive case, we’ll be accessing the mailbox using credentials of an application in Azure portal.

The basics of creating an app registration in Azure are covered in OAuth 2.0 for Office 365 Accounts (installed applications) article or OAuth 2.0 with IMAP/SMTP for Office 365 in ASP.NET Core 3.1 MVC applications version for web apps. But in this case, we’re not using IMAP so we won’t need IMAP.AccessAsUser.All permission. At “API Permissions screen”, click “Add a permission” button and switch to “APIs my organization uses” tab. In search bar, type “office” and select “Office 365 Exchange Online”:

On the next screen under “Application permissions” section, select “full_access_as_app” and click “Add permissions”:

Once you’re back to “API permissions” screen, be sure to select the newly added permission and Grant admin access for organization.

The following sample demonstrates the use of MailBee.NET EWS component for accessing Office 365 mailbox non-interactively. We’ll obtain the authentication token, log onto Office 365 via Exchange Web Services to read the newest message in Inbox and to send a test email out.

To build this sample, you’ll need to add Microsoft.Exchange.WebServices, Microsoft.Identity.Client, MailBee.NET and MailBee.NET.EWS packages in Nuget.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MailBee;
using MailBee.EwsMail;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Identity.Client;

// We need this because MailMessage type exists in both MailBee and Managed EWS
using MailBeeMailMessage = MailBee.Mime.MailMessage;

namespace EwsWithOauthConsoleApp
{
    class Program
    {
        private static string Tenant = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Directory (tenant) ID, from Azure app.
		private static string Instance = "https://login.microsoftonline.com/";
		private static string ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"; // Application (client) ID, from Azure app.
		private static string ClientSecret = "secret"; // You create one in "Certificates & secrets" of Azure app registration.
		private static string email = "user@some.office365.domain";

        static async System.Threading.Tasks.Task Main(string[] args)
        {
            MailBee.Global.LicenseKey = "MN120-nnnnnnnnnnnnnnnnnnnnnnnnnnnn-nnnn";

            // Using Microsoft.Identity.Client 4.22.0
            IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
                .Create(ClientId)
                .WithClientSecret(ClientSecret)
                .WithTenantId(Tenant)
                .Build();

            // The permission scope required for EWS access
            var ewsScopes = new string[] { "https://outlook.office365.com/.default" };

            // Make the token request
            AuthenticationResult authResult = null;
            authResult = await app.AcquireTokenForClient(ewsScopes).ExecuteAsync();
            OAuthCredentials authCreds = new OAuthCredentials(authResult.AccessToken);

           // Access Office365 mailbox
            Ews ewsClient = new Ews();
            ewsClient.InitEwsClient(ExchangeVersion.Exchange2010_SP1, TimeZoneInfo.Utc);
            ewsClient.SetServerUrl("https://outlook.office365.com/EWS/Exchange.asmx");
            ewsClient.SetCredentials(authCreds);
            ewsClient.Service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, email);

           // Retrieve information on Inbox and load the newest message
            FolderId foldId = null;
            foldId = ewsClient.FindFolderIdByFullName("Inbox");
            EwsItem mailItem = null;
            mailItem = ewsClient.DownloadItem(foldId, 0, EwsItemParts.GenericItem);
            Console.WriteLine("From: " + mailItem.From);
            Console.WriteLine("Date: " + mailItem.Date);
            Console.WriteLine(mailItem.Subject);

           // Send out a simple email message
            MailBeeMailMessage msg = new MailBeeMailMessage();
            msg.Subject = "Sending message from EWS";
            msg.BodyPlainText = "Message sent at: " + DateTime.Now.ToString();
            msg.BodyHtmlText = "<html>Message sent at: " + DateTime.Now.ToString() + "</html>";
            msg.To.AddFromString("test@mydomain.com");
            msg.From.AsString = email;
            msg.SetUniqueMessageID(null);
            ewsClient.SendMessage(msg);
        }
    }
}
Using MailBee.NET EWS to access Office 365 mailbox in non-interactive case

Using Graph API to access Office 365 mailbox in non-interactive case

Office 365 email service will be gradually revoking IMAP access with login/password authentication. You’ll need to use IMAP via OAuth 2.0 instead.

MailBee.NET Objects, email library for .NET platform, allows for accessing Office 365 accounts via IMAP with OAuth 2.0 used. However, it will only work in an interactive scenario when the user has to explicitly grant consent for your app to access their mailbox. The user will see Office 365 popup in the browser asking for consent and must click Agree.

In a non-interactive case, you would need to access mailbox using credentials of an application in Azure portal rather than user’s credentials – and currently, Microsoft allows that via their proprietary Graph API only, not IMAP.

To create an app registration in Azure, see OAuth 2.0 for Office 365 Accounts (installed applications) article or OAuth 2.0 with IMAP/SMTP for Office 365 in ASP.NET Core 3.1 MVC applications version for web apps. The only difference would be that these articles describe how to set permissions for IMAP (IMAP.AccessAsUser.All permission). But we’ll set permissions for Graph instead. Your app in Azure portal must have Mail.Read and User.Read.All enabled in Application Permissions (NOT Delegated Permissions). Click the picture to enlarge:

Let’s suppose we need to download all the email messages from the particular user account. The idea of the following sample is to use Graph to download email source from the server, feed it to MailBee.NET library and then use its MailMessage object the same way as you do when getting email from IMAP – for instance, to save a message as .EML file, or to display message headers or attachments when looping through all the messages found in the account.

To build this sample, you’ll need to add Microsoft.Graph, Microsoft.Graph.Auth and MailBee.NET packages in Nuget.

using System;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using System.Collections.Generic;
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using MailBee.Mime;

namespace MsGraphWithMailBeeConsoleApp
{
	class Program
	{
		private static string Tenant = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Directory (tenant) ID, from Azure app.
		private static string Instance = "https://login.microsoftonline.com/";
		private static string ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"; // Application (client) ID, from Azure app.
		private static string ClientSecret = "secret"; // You create one in "Certificates & secrets" of Azure app registration.
		private static string email = "user@some.office365.domain";

		static async Task Main(string[] args)
		{
			// Confidential app does not require consent from the user. With public apps (which require consent) we can use IMAP but
			// with confidential apps Graph is the only option.

			// Your app in Azure portal must have Mail.Read and User.Read.All enabled in Application Permissions (not Delegated Permissions).
			IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(ClientId)
		   .WithTenantId(Tenant)
		   .WithClientSecret(ClientSecret)
		   .Build();

			List scopes = new List();
			scopes.Add(".default");

			AuthenticationResult result = null;

			result = await app.AcquireTokenForClient(scopes).ExecuteAsync();

			ClientCredentialProvider authProvider = new ClientCredentialProvider(app);
			GraphServiceClient graphClient = new GraphServiceClient(authProvider);

			// Profile is not needed for this sample but can be useful for your app.
			// Note that we cannot use Me here because there is no signed-in user ("Me" user).
			var profile = await graphClient.Users[email].Request().GetAsync();

			// We get IDs of messages here.
			var messages = await graphClient.Users[email].Messages
				.Request()
				.Select("sender,subject") // You can remove this line, the sample does not need it but it shows how to request extra info with messages.
				.GetAsync();

			if (messages.Count == 0)
			{
				Console.WriteLine("Mailbox is empty");
			}
			else
			{
				// Get raw data of the most recent message in the email account and save it to disk
				// (note that in Graph messages are sorted from newer to older by default, contrary to IMAP).
				MailMessage msg = new MailMessage();
				using (var msgStream = await graphClient.Users[email].Messages[messages[0].Id].Content.Request().GetAsync())
				{
					msg.LoadMessage(msgStream);
					msg.SaveMessage(@"C:\Temp\msg.eml");
				}

				// Print some info on the message.
				Console.WriteLine(msg.From.ToString());
				Console.WriteLine(msg.Subject);
				Console.WriteLine(msg.Date);
				foreach (MailBee.Mime.Attachment att in msg.Attachments)
				{
					Console.WriteLine(att.Filename);
				}
			}
		}
	}
}

Using Graph API to access Office 365 mailbox in non-interactive case

Sending mail to addresses containing non-ASCII characters

If you require sending messages to email addresses which contain non-ASCII characters like “äöü”, that’s how it’s done. However, important to determine whether those characters are in domain or username part of email address.

If international characters are a part of domain name, you’ll need to convert domain name into Punycode. The following example demonstrates how it’s done with MailBee.NET Objects:

MailBee.Global.LicenseKey = "Trial or permanent key";
Smtp mailer = new Smtp();
mailer.Log.Enabled = true;
mailer.Log.Filename = @"C:\Temp\log.txt";

mailer.SmtpServers.Add("mail.domain.com", "jdoe", "secret");
mailer.From.Email = "jdoe@domain.com";
mailer.From.DisplayName = "John Doe";
EmailAddress addr = new EmailAddress("jane.doe@äöü.com", "Jane Doe");
mailer.To = addr.ToIdnAddress();

mailer.Subject = "Sending mail to addresses containing non-ASCII characters";
mailer.BodyHtmlText = "This is a sample mail message.";

mailer.Send();

It is perfectly safe to use this method for addresses which don’t contain any international characters, you’ll just get the new object which has the same values as the current one.

And if those characters are in username, not just in domain name – then you need to set Smtp.RequestEncoding property to UTF8. Bear in mind that many SMTP servers are unable to deal with international email addresses, so you may wish to check if particular SMTP server returns UTF8SMTP or SMTPUTF8 capability in EHLO response.

Sending mail to addresses containing non-ASCII characters

Troubleshoot SSL/TLS errors by disabling .NET troubleshooting tools

Logging is the immense tool for troubleshooting of .NET apps, especially when it comes to debugging network-related code. However, it turns out that sometimes these troubleshooting tools can be the root of the problem!

A client reported that they experience the strange [NotSupportedException: The certificate key algorithm is not supported.] exception when connecting to GMail’s IMAP over SSL with our MailBee.NET Objects email library. First thought was that TLS 1.2 was not in place (it’s required by Google) but further testing showed that this wasn’t true.

With extra research, we found that the client’s app had System.Diagnostics logging enabled for network connections. Normally tracing network connections with System.Diagnostics helps detect and eliminate various network issues but this time it caused the issue itself. Removing <system.diagnostics> section from app.config or web.config fixed this error.

Troubleshoot SSL/TLS errors by disabling .NET troubleshooting tools

Use TLS 1.3 for IMAP and SMTP connections

To take advantage of the most secure TLS 1.3 connections in e-mail .NET applications, you don’t necessarily need the latest .NET Core 3.0 or .NET 5 (even though the corresponding enum values are not defined in earlier versions).

The below shows how you can establish an IMAP connection using TLS 1.3. As an example, we’ll use GMail as the mail server and MailBee.NET Objects email component as the client. The key is setting ServicePointManager.SecurityProtocol static property prior to connecting to a mail server (be it IMAP, SMTP or POP3):

ServicePointManager.SecurityProtocol=SecurityProtocolType.Tls12 | (SecurityProtocolType)12288;

By default, MailBee.NET checks the value of ServicePointManager.SecurityProtocol, and if it’s set to non-default value, MailBee.NET will use all the flags listed in it as the allowed security protocols. In particular, SecurityProtocolType.Tls12 | (SecurityProtocolType)12288 means a combination of TLS 1.2 and TLS 1.3 (the best will be selected during the connection procedure, depending on what the mail server supports). .NET Framework may not have the corresponding value for TLS 1.3 in SecurityProtocolType enum yet so we use its int value which we cast to SecurityProtocolType type.

Here’s the complete sample with TLS 1.3 over Gmail’s IMAP:

using System;
using System.Net;
using System.Net.Security;
using MailBee;
using MailBee.ImapMail;

namespace ConsoleApplicationNet45
{
	class Program
	{
		static void Main(string[] args)
		{
			MailBee.Global.LicenseKey = "your key";
			Imap imp = new Imap();
			imp.Log.Enabled = true;
			imp.Log.Filename = @"C:\Temp\log.txt";
			imp.Log.Clear();
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |(SecurityProtocolType)12288; // Request TLS 1.3 but allow TLS 1.2 fallback
			imp.Connect("imap.gmail.com", 993);
			SslStream s = (SslStream)imp.GetStream();
			Console.WriteLine(s.SslProtocol.ToString()); // See that it's actually TLS 1.3
			imp.Login("user@gmail.com", "password");
			imp.Disconnect();
		}
	}
} 

In my tests, the technique above works with .NET 4.5 and newer and .NET Core 2.1 and newer. TLS 1.3 support must also be installed and activated in Windows.

Use TLS 1.3 for IMAP and SMTP connections

Using MailBee.NET Objects in Azure cloud

MailBee.NET Objects library is fully compatible with Microsoft Azure. You can use it just the same way you do on a normal PC.

For instance, let’s assume you have an ASP.NET MVC5 web app which you publish on Azure. You can modify Controllers/HtmlController.cs as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using MailBee;
using MailBee.ImapMail;

namespace WebApplicationAzure.Controllers
{
	public class HomeController : Controller
	{
		public ActionResult Index()
		{
			return View();
		}

		public ActionResult About()
		{
			ViewBag.Message = "Your application description page.";
			MailBee.Global.LicenseKey = "your key";
			Imap imp = new Imap();
			string logPath = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, "log.txt");
			imp.Log.Filename = logPath;
			imp.Log.Enabled = true;
			imp.Log.Clear();
			try
			{
				imp.Connect("mail.domain.com");
				imp.Login("your@account.com", "password");
				FolderCollection col = imp.DownloadFolders();
				imp.Disconnect();
				ViewBag.Message = $"Number of folders: {col.Count}, log path is {logPath}";
			}
			catch (MailBeeException ex)
			{
				ViewBag.Message = ex.ToString();
			}
			ViewBag.Log = System.IO.File.ReadAllText(logPath);
			return View();
		}

		public ActionResult Contact()
		{
			ViewBag.Message = "Your contact page.";

			return View();
		}
	}
} 

In Views/Home/About.cshtml, make sure you have Message and Log blocks.
Don’t forget to add a reference to MailBee.NET library via Nuget.
Now, when you publish the app and navigate to About page, this will display the number of folders in an IMAP account and the contents of the log file produced by MailBee.

Using MailBee.NET Objects in Azure cloud

Fix IMAP errors with imap.sina.net service

If you’re getting “The envelope data is corrupted or incorrect” when downloading e-mails from sina.net with MailBee.NET Objects, you may face the issue that their mail server returns IMAP envelopes incorrectly in case if a message becomes read (Seen) during downloading.

You can avoid this by keeping message flags intact during downloading (so that download process won’t trigger Seen flag). This code downloads last e-mail in the current folder in sina.net-compatible way:

imp.SetSeenForEntireMessages = false; // Do not set Seen flag on download
MailMessage msg = imp.DownloadEntireMessage(imp.MessageCount, false);


			
Fix IMAP errors with imap.sina.net service

Workaround for intermittent “NO [ALERT]” errors in IMAP

Sometimes (a customer faced this with imap.orange.fr provider), you may be getting intermittent NO responses which cause MailBee to throw an exception (MailBee doesn’t know if this response is intermittent or not). This usually happens when selecting a folder.

For instance, the following can be found in the log:

[16:35:00.52] [RECV] * NO [ALERT] Mailbox is at 83% of quota\r\n [Total 41 bytes received.]

To workaround this problem, just repeat select folder operation in case if the previous one failed due to a negative response from the IMAP server.

try
{
  imap.SelectFolder("INBOX");
}
catch (MailBeeImapNegativeResponseException)
{
  imap.SelectFolder("INBOX");
}
Workaround for intermittent “NO [ALERT]” errors in IMAP