With Windows 10 Fall Creators Update and newer, you can use the DLL based on .NET Standard 2.0 version of MailBee.NET Objects (C:\Program Files (x86)\MailBee.NET Objects\uap10.0.16299). This is the most recommended approach.
If your UWP app must target an older version of Windows, you can use the special UWP edition of MailBee.NET library. UWP edition mostly has .NET 4.5 feature set (including async/await
methods). Still, a number of limitations do exist for that "old" UWP version:
async/await
versions. You'll get PlatformNotSupportedException when calling, let's say, Imap.Connect
instead of Imap.ConnectAsync
.However, in case if you can use the .NET Standard 2.0 version (the Min Target of your UWP project is Windows 10 Fall Creators Update), there will be much fewer limitations (and most of them are very specific and don't affect most apps):
In Project properties, make sure that Target version and Min version is Windows 10 Fall Creators Update or newer. The MailBee.NET.dll resides in C:\Program Files (x86)\MailBee.NET Objects\uap10.0.16299 folder. Or, via NuGet, the required .DLL will be installed automatically:
Install-Package MailBee.NET
The above installs MailBee.NET.dll from lib\uap10.0.16299 folder of the package.
Install System.Text.Encoding.CodePages package:
Install-Package System.Text.Encoding.CodePages
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)
must be called before accessing any MailBee classes. This initializes codepages support in the runtime.
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
The above installs MailBee.NET.dll from lib\uap10.0 folder of the package (assuming that Min Target for the project is Windows version older than Fall Creators Update).
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 .NET runtime.
Socket support is different in UWP therefore methods like Imap.GetSocket
return StreamSocket, not Socket. Socket class was not supported by UWP prior to Windows 10 Fall Creators Update.
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. ClientServerCertificates.AutoValidation property is not supported.
In case of Windows 10 Fall Creators Update being Min Target (so that .NET Standard 2.0 version of MailBee.NET.dll is used instead of "old" UWP version),
Imap.GetSocket
will return Socket (not StreamSocket). And you can use ClientServerCertificates.AutoValidation property.
Filesystem access in UWP (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).
If your UWP app must load some additional files (let's use the bounce database for BounceMail component as an example), it should store them in Assets folder:
var path = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets")
string xdbPath = Path.Combine(localizationDirectory.Path, "bouncedatabase.xdb")
byte[] xdb = await File.ReadAllBytesAsync(xdbPath)
DeliveryStatusParser parser = new DeliveryStatusParser(xdb)
BounceMail is not available in UWP prior to Windows 10 Fall Creators Update.
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. You may also need more settings (Package Manifest / Declarations / Protocol / Name) in case if you want to add OAuth 2.0 authentication, see OAuth 2.0 for Universal Windows apps guide.
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.
This is the UWP example for older Windows. In case of Windows 10 Fall Creators Update or newer, see OAuth 2.0 for Universal Windows apps guide.
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:
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/", "https://www.googleapis.com/auth/userinfo.email" }; 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. Userinfo 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(); } } } }
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/", "https://www.googleapis.com/auth/userinfo.email"} 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 Userinfo = 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
Copyright © 2006-2024 AfterLogic Corporation. All rights reserved.