UWP Edition (Universal Windows, UAP 10.0)

MailBee.NET library is also available for Universal Windows applications. It's based on .NET Core edition with extra modifications required to make it work with UWP (UWP is not fully compatible with .NET Core).

UWP edition mostly has .NET 4.5 feature set (including async/await methods). Still, a number of limitations do exist. First, it's limitations of .NET Core:

What you need to run MailBee with UWP

The MailBee.NET.dll for UWP resides in C:\Program Files (x86)\MailBee.NET Objects\uap10.0 folder. Or, via NuGet, the required .DLL will be installed automatically. Just run this command:

Install-Package MailBee.NET

You must update Microsoft.NETCore.UniversalWindowsPlatform NuGet package to 5.2.2 (for Visual Studio 2015) or higher version (for Visual Studio 2017).

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance) must be called before accessing any MailBee classes. This initializes codepages support in UWP runtime.

Socket support is different in UWP therefore methods like Imap.GetSocket return StreamSocket, not Socket.

You must use SocketCreating event instead of ClientServerCertificates.AutoValidation to configure which SSL certificate errors can be tolerated (useful if you need to connect to a mail server with self-signed certificate). See code snippet in Imap.SocketCreating topic for example.

Filesystem access (paths to locations accessible for reading or writing files) is limited to the app's folders like ApplicationData.Current.LocalFolder.Path. If you just need some place where to save the log file for debugging, Path.Combine(ApplicationData.Current.LocalFolder.Path, "log.txt") path can be used. For example:

msg.Parser.WorkingFolder = ApplicationData.Current.LocalFolder.Path (assuming msg is MailMessage instance).

Capabilities section of Package.appxmanifest must have Internet (Client) and Private Networks (Client & Server) options checked. The latter is needed if you want to connect to localhost mail servers. Otherwise, you may get UnauthorizedAccessException or MailBeeSocketTimeoutException.

In our tests of Windows authentication, login with SASL NTLM method didn't work with UWP apps while SASL GSSAPI does. See AuthenticationMethods topic for more info on the authentication mechanisms available in MailBee.

When using Google APIs (such as for OAuth 2.0), Google settings must be stored in json file (see example below). It's Google APIs limitation.

UWP example

This C#/VB example logs in your Gmail inbox via OAuth 2.0 and displays the body of the last e-mail, including embedded pictures if any (the pictures will be base64 embedded directly in HTML). The sample also demonstrates logging IMAP session into a file, excepting handling, enabling self-signed certificates (the latter is not needed for Gmail but can be useful if you need to use a local mail server). To make this sample work, do the following:

C#

using System;
using System.IO;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Popups;
using Windows.Storage;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography.Certificates;
using System.Text;
using System.Threading;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Oauth2.v2;
using Google.Apis.Oauth2.v2.Data;
using Google.Apis.Services;
using MailBee;
using MailBee.Mime;
using MailBee.ImapMail;

namespace UniApp1
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        static void Imp_SocketCreating(object sender, SocketCreatingEventArgs e)
        {
            // Demonstrate how we can allow self-signed or expired certificates.
            e.NewSocket = new StreamSocket();
            e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
            e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
            e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
        }

        private async void button_Click(object sender, RoutedEventArgs e)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            MailBee.Global.LicenseKey = "MN1XX-XXXXXXXX-XXXX";

            Imap imp = new Imap();
            imp.Log.Filename = Path.Combine(ApplicationData.Current.LocalFolder.Path, "log.txt");
            imp.Log.Enabled = true;
            await imp.Log.ClearAsync();

            // Request Gmail IMAP/SMTP scope and the e-mail address scope.
            string[] scopes = new string[] { "https://mail.google.com/", Oauth2Service.Scope.UserinfoEmail };

            System.Diagnostics.Debug.WriteLine("Requesting authorization");
            Uri SecretsUri = new Uri("ms-appx:///Assets/client_secret.json", UriKind.Absolute);
            UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(SecretsUri, scopes, "user", CancellationToken.None);
            System.Diagnostics.Debug.WriteLine("Authorization granted or not required (if the saved access token already available)");

            if (credential.Token.IsExpired(credential.Flow.Clock))
            {
                System.Diagnostics.Debug.WriteLine("The access token has expired, refreshing it");
                if (await credential.RefreshTokenAsync(CancellationToken.None))
                {
                    System.Diagnostics.Debug.WriteLine("The access token is now refreshed");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("The access token has expired but we can't refresh it :(");
                    return;
                }
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("The access token is OK, continue");
            }

            System.Diagnostics.Debug.WriteLine("Requesting the e-mail address of the user from Google");

            // Sometimes, you may also need to set Initializer.ApplicationName property.
            // In our tests, setting just Initializer.HttpClientInitializer was enough for Google.
            Oauth2Service oauthService = new Oauth2Service(
                new BaseClientService.Initializer() { HttpClientInitializer = credential });

            // Userinfo.Get may crash if you run the app under debugger (a bug in Google API).
            // If this happens, use "Start without debugging" instead.
            Userinfoplus userInfo = await oauthService.Userinfo.Get().ExecuteAsync();
            string userEmail = userInfo.Email;
            System.Diagnostics.Debug.WriteLine("E-mail address is " + userEmail);

            // Build XOAUTH2 token. Can be used with Gmail IMAP or SMTP.
            string xoauthKey = OAuth2.GetXOAuthKeyStatic(userEmail, credential.Token.AccessToken);

            try
            {
                await imp.ConnectAsync("imap.gmail.com", 993);
                await imp.LoginAsync(null, xoauthKey, AuthenticationMethods.SaslOAuth2);
                await imp.SelectFolderAsync("Inbox");
                MailMessage msg = await imp.DownloadEntireMessageAsync(imp.MessageCount, false);
                await imp.DisconnectAsync();
                string html = msg.GetHtmlWithBase64EncodedRelatedFiles();
                web.NavigateToString(html);
            }
            catch (MailBeeException ex)
            {
                if (imp.IsConnected)
                {
                    await imp.DisconnectAsync();
                }
                System.Diagnostics.Debug.WriteLine(ex.ToString());
                MessageDialog dialog = new MessageDialog(ex.ToString());
                await dialog.ShowAsync();
            }
        }
    }
}

VB

Imports Windows.UI.Popups
Imports Windows.Storage
Imports Windows.Networking.Sockets
Imports Windows.Security.Cryptography.Certificates
Imports System.Text
Imports System.Threading
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Oauth2.v2
Imports Google.Apis.Oauth2.v2.Data
Imports Google.Apis.Services
Imports MailBee
Imports MailBee.Mime
Imports MailBee.ImapMail

Public NotInheritable Class MainPage
    Inherits Page

    Sub Imp_SocketCreating(sender As Object, e As SocketCreatingEventArgs)
        e.NewSocket = New StreamSocket()
        e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName)
        e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted)
        e.NewSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired)
    End Sub

    Private Async Sub button_Click(sender As Object, e As RoutedEventArgs) Handles button.Click
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)

        MailBee.Global.LicenseKey = "MN1XX-XXXXXXXX-XXXX"

        Dim imp As New Imap()

        imp.Log.Filename = Path.Combine(ApplicationData.Current.LocalFolder.Path, "log.txt")
        imp.Log.Enabled = True
        Await imp.Log.ClearAsync()

        ' Request Gmail IMAP/SMTP scope and the e-mail address scope.
        Dim scopes As String() = New String() {"https://mail.google.com/", Oauth2Service.Scope.UserinfoEmail}

        System.Diagnostics.Debug.WriteLine("Requesting authorization")
        Dim SecretsUri As New Uri("ms-appx:///Assets/client_secret.json", UriKind.Absolute)
        Dim credential As UserCredential = Await GoogleWebAuthorizationBroker.AuthorizeAsync(SecretsUri, scopes, "user", CancellationToken.None)
        System.Diagnostics.Debug.WriteLine("Authorization granted or not required (if the saved access token already available)")

        If credential.Token.IsExpired(credential.Flow.Clock) Then
            System.Diagnostics.Debug.WriteLine("The access token has expired, refreshing it")
            If Await credential.RefreshTokenAsync(CancellationToken.None) Then
                System.Diagnostics.Debug.WriteLine("The access token is now refreshed")
            Else
                System.Diagnostics.Debug.WriteLine("The access token has expired but we can't refresh it :(")
                Return
            End If
        Else
            System.Diagnostics.Debug.WriteLine("The access token is OK, continue")
        End If

        System.Diagnostics.Debug.WriteLine("Requesting the e-mail address of the user from Google")

        ' Sometimes, you may also need to set Initializer.ApplicationName property.
        ' In our tests, setting just Initializer.HttpClientInitializer was enough for Google.
        Dim oauthService As New Oauth2Service(New BaseClientService.Initializer() With {
            .HttpClientInitializer = credential
        })

        ' Userinfo.Get may crash if you run the app under debugger (a bug in Google API).
        ' If this happens, use "Start without debugging" instead.
        Dim userInfo As Userinfoplus = Await oauthService.Userinfo.Get().ExecuteAsync()
        Dim userEmail As String = userInfo.Email
        System.Diagnostics.Debug.WriteLine(Convert.ToString("E-mail address is ") & userEmail)

        ' Build XOAUTH2 token. Can be used with Gmail IMAP or SMTP.
        Dim xoauthKey As String = OAuth2.GetXOAuthKeyStatic(userEmail, credential.Token.AccessToken)

        Dim savedEx As MailBeeException = Nothing ' Unlike C#, we can't await in Catch in VB14 (although this will change in VB17).
        Try
            Await imp.ConnectAsync("imap.gmail.com", 993)
            Await imp.LoginAsync(Nothing, xoauthKey, AuthenticationMethods.SaslOAuth2)
            Await imp.SelectFolderAsync("Inbox")
            Dim msg As MailMessage = Await imp.DownloadEntireMessageAsync(imp.MessageCount, False)
            Await imp.DisconnectAsync()
            Dim html As String = msg.GetHtmlWithBase64EncodedRelatedFiles()
            web.NavigateToString(html)
        Catch ex As MailBeeException
            savedEx = ex
            System.Diagnostics.Debug.WriteLine(ex.ToString())
        End Try
        If imp.IsConnected Then
            Await imp.DisconnectAsync()
        End If
        If savedEx IsNot Nothing Then
            Dim dialog As New MessageDialog(savedEx.ToString())
            Await dialog.ShowAsync()
        End If
    End Sub
End Class

Send feedback to AfterLogic

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