UWP Edition (Universal Windows, UAP 10.0)
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:
- License key can only be set in the code (no Windows Registry, machine.config and so on).
- No sync versions of many methods, only
async/await
versions. You'll get PlatformNotSupportedException when calling, let's say, Imap.Connect
instead of Imap.ConnectAsync
.
- No BounceMail support.
- No Exchange Web Services (EWS) support.
- ICalVCard library is not supported.
- No mail merge and e-mail address validation over database.
- No RTF-to-HTML conversion during parsing MS-TNEF (winmail.dat), Outlook .MSG and .PST files.
- No HTML to PDF conversion (MailBee.Pdf component is disabled).
- Some limitations on working with certificates.
- Direct send without SMTP relay server: no system DNS server autodetection via WMI, config file or Windows Registry. It still works on Windows but may not work on other platforms. The affected method: DnsServerCollection.Autodetect.
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):
- No HTML-to-PDF conversion.
- No Windows registry support (e.g. no way to store the license key there).
- No ICalVCard library support (you can use other open-source alternatives like iCal.NET).
- No impersonation support (doesn't make sense in UWP anyway).
- Limited support of DNS servers auto-detection for firect send without SMTP relay server.
- CryptoServiceProvider class not supported.
- NTLM and GSSAPI authentication will always work via NegotiateStream class, not via Win32 API (which is not available in UWP).
What you need to run MailBee with UWP (Windows 10 Fall Creators Update or newer)
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.
What you need to run MailBee with UWP (older Windows)
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
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:
- Copy file (e.g. bouncedatabase.xdb into Assets folder of the project)
- In Solution Explorer, include this file into a project and set Build Action to Content
- In the app code, get the path to the Assets folder:
var path = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets")
- Get the path to the file:
string xdbPath = Path.Combine(localizationDirectory.Path, "bouncedatabase.xdb")
- Load the file contents:
byte[] xdb = await File.ReadAllBytesAsync(xdbPath)
- Initialize BounceMail parser
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.
UWP example
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:
- Create Blank App (Universal Windows)
- Update Microsoft.NETCore.UniversalWindowsPlatform NuGet package to 5.2.2 (or a higher version if you're using Visual Studio 2017).
- Place Button (named button1) and WebView (named web) controls on the form.
- Add NuGet references for MailBee.NET, Google.Apis.Oauth2.v2, Microsoft.Bcl.Async (the latter is needed for Google APIs to work). If getting "Package restore failed. Rolling back package changes" error, this means Microsoft.NETCore.UniversalWindowsPlatform is still of 5.1.0 version or lower.
- Add client_secrets.json file to your Assets folder and set its Build Action to Content. You can download this JSON file from Credentials section of Google Developer Console. Unlike classic .NET Framework, Google APIs for UWP cannot yet consume OAuth 2.0 secrets directly from code, only from this file (more exactly, from URL).
- Add Click handler for Button1.
- Replace MainPage.xaml.cs or MainPage.xaml.vb with the code below.
- Apply your MailBee.NET license key.
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
Send feedback to AfterLogic
Copyright © 2006-2024 AfterLogic Corporation. All rights reserved.