10/4/2019 Admin

Google Email Viewer in Server Side Blazor

You can create a Blazor server-side application that will allow any user with a GMail account to view their emails.

This solution does not require that they set their GMail account to less secure access.


After the application is set up, any user with a GMail account can log into the application by clicking the Login button.


They enter their normal GMail username and password.


When they use the application for the first time, GMail will require the user to approve access.


Their emails will display HTML content as well as embedded images.


If they log into the normal GMail website and tag an email…


When viewing that email in the Blazor GMail application, they will see that the email will show up when clicking on the button that has the same name as the tag.

Set Up The Application


We start with the code from the article: Google Authentication in Server Side Blazor.

Open it in Visual Studio 2019 (or later).


Add the following NuGet packages:

  • Google.Apis.Gmail.v1
  • MailKit

Enable GMail API

You need to add the Google GMail API.

Go to: https://console.developers.google.com/apis/dashboard

Sign in with your Google account and select the project used to generate keys for theGoogle Authentication in Server Side Blazor project.


Select Enable APIs and Services.


Search for and select GMail.


Click the Enable button to enable the API.


In Visual Studio, open the Components/_ViewImports.cshtml file and add the following code:

@using Microsoft.Extensions.Configuration @using System.Threading @using System.Text @using System.IO @using Google.Apis.Auth.OAuth2 @using Google.Apis.Gmail.v1 @using Google.Apis.Gmail.v1.Data @using Google.Apis.Services @using Google.Apis.Util.Store

Building The Application


All of the remaining code is contained in the Pages/GMail folder.

The diagram above shows what part of the application each file is responsible for generating.


A class that is passed a reference to a MimeMessage and generates HTML suitable to be rendered by a browser control.

The code is from: https://github.com/jstedfast/MimeKit/blob/master/samples/MessageReader/MessageReader/HtmlPreviewVisitor.cs


This displays a single message. It is passed a Google Message object that is then converted to a MimeKitMessage object because that object allows for easier C# manipulation and allows us to call the HTMLPreviewVisitor class that displays embedded images in the email and will also allow access to any attachments in the email (that code is commented out).

								@using MimeKit @using MessageReader @strError <div style="padding:2px; vertical-align:top">     <div><i>@MimeKitMessage.Date.ToString()</i></div>     <div><b>From:</b> @MimeKitMessage.From.ToString()</div>     <div><b>To:</b> @MimeKitMessage.To.ToString()</div>     <div><b>Subject:</b> @MimeKitMessage.Subject</div>     <br />     <div>@((MarkupString)@htmlEmail)</div> </div> @code {     [Parameter] public Message paramMessage { get; set; }     MimeMessage MimeKitMessage;     string strError = "";     string htmlEmail = "";     protected override void OnInitialized()     {         try         {             if (paramMessage != null)             {                 string converted = paramMessage.Raw.Replace('-', '+');                 converted = converted.Replace('_', '/');                 byte[] decodedByte = Convert.FromBase64String(converted);                 using (Stream stream = new MemoryStream(decodedByte))                 {                     // Convert to MimeKit from GMail                     // Load a MimeMessage from a stream                     MimeKitMessage = MimeMessage.Load(stream);                     // Convert any embedded images                     var visitor = new HtmlPreviewVisitor();                     MimeKitMessage.Accept(visitor);                     htmlEmail = visitor.HtmlBody;                     //If the email has attachments we can get them here                     //var attachments = visitor.Attachments;                 }             }         }         catch (Exception ex)         {             strError = ex.Message;         }     }     }       EmailFolderControl.razor

This displays the emails. It is passed a reference to the Google API so that it can retrieve the emails. The GetFolderContents method is marked public so that it can be invoked by the Email.razor control that it is contained in. the Email.razor control will pass the GetFolderContents method the selected tag (such as “Inbox”).

@strError <table>     <tbody>         <tr>             <td                  style="width:auto; text-align:left; vertical-align:top">                 @foreach (var message in ColMessages)                 {                     <EmailMessageControl paramMessage="message">                     </EmailMessageControl>                     <br />                     <hr size="20">                 }             </td>         </tr>     </tbody> </table> @code {     [Parameter] public GmailService service { get; set; }     List<Message> ColMessages = new List<Message>();     string strError = "";     public void GetFolderContents(string folder)     {         try         {             strError = "";             ColMessages = new List<Message>();             // Get all the EMAIL folders for the current user ("me")             var request = service.Users.Messages.List("me");             request.LabelIds = folder;             // Used for paging             //request.MaxResults = 10;             //request.PageToken = 1;             // Get messages             var Messages = request.Execute();             // do we have any messages?             if (Messages.ResultSizeEstimate > 0)             {                 foreach (var email in Messages.Messages)                 {                     // Get the selected Email                     var emailInfoReq =                          service.Users.Messages.Get("me", email.Id);                     // Must request the *raw* version so that we get a .EML                     // version that we can use to be converted to MimeKit                     emailInfoReq.Format =                         UsersResource                         .MessagesResource                         .GetRequest.FormatEnum.Raw;                     // Load a MimeMessage from a stream                     Message GMailMessage = emailInfoReq.Execute();                     // do not add message if already in the collection                     if (!ColMessages.Any(x => x.Id == GMailMessage.Id))                     {                         ColMessages.Add(GMailMessage);                     }                 }             }         }         catch (Exception ex)         {             strError = ex.Message;         }     } }


This is the main page for the Email application.

The primary purpose of this control is to connect to the GMail API.

This also displays a list of available tags that the GMail account has configured and also contains the EmailFolderControl. When a user selects a tag, it calls the GetFolderContents method in the EmailFolderControl passing the selected tag. The EmailFolderControl then displays the emails that have that tag.

@page "/email" @using System.Security.Claims @inject IConfiguration _configuration @strError <br /> <br /> <!-- AuthorizeView allows us to only show sections of the page --> <!-- based on the security on the current user --> <AuthorizeView>     <!-- Show this section if the user is logged in -->     <Authorized>         @if (Gmaillabels != null)         {             <table>                 <tbody>                     <tr>                         <td style="width:200px; text-align:left; vertical-align:top">                             @foreach (var EmailFolder in Gmaillabels)                             {                                 <div style="padding:2px; vertical-align:top">                                     <button class="btn btn-primary btn-sm btn-block"                                             bind="@EmailFolder"                                             @onclick="(() => ShowFolder(EmailFolder))">                                         @EmailFolder.Name                                     </button>                                 </div>                             }                         </td>                         <td>                             <EmailFolderControl @ref="_emailFolder" service="service">                             </EmailFolderControl>                         </td>                     </tr>                 </tbody>             </table>         }     </Authorized>     <!-- Show this section if the user is not logged in -->     <NotAuthorized>         <p>You must be logged in to use this page</p>     </NotAuthorized> </AuthorizeView> @code {     [CascadingParameter]     private Task<AuthenticationState> authenticationStateTask { get; set; }     EmailFolderControl _emailFolder;     private ClaimsPrincipal User;     GmailService service;     string folder = "INBOX";     string strError = "";     UserCredential credential;     public List<Label> Gmaillabels = new List<Label>();     static string[] Scopes = { GmailService.Scope.GmailReadonly };     static string ApplicationName = "Blazor GMail";     protected override async Task OnInitializedAsync()     {         try         {             // Get the current user             User = (await authenticationStateTask).User;             if (User.Identity.IsAuthenticated)             {                 // Get the credentials for the current user that is stored in a                 // directory that serves as a common repository for documents.                 string credPath =                     System.Environment.GetFolderPath(                         System.Environment.SpecialFolder.Personal);                 credPath = Path.Combine(credPath, ".credentials/",                     System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);                 // Set the settings from the appsettings.json file                 ClientSecrets objClientSecrets = new ClientSecrets();                 objClientSecrets.ClientId = _configuration["Google:ClientId"];                 objClientSecrets.ClientSecret = _configuration["Google:ClientSecret"];                 // Requesting Authentication or loading previously                 // stored authentication for userName                 credential = await GoogleWebAuthorizationBroker                     .AuthorizeAsync(objClientSecrets,                     Scopes,                     User.Identity.Name,                     CancellationToken.None,                     new FileDataStore(credPath, true));                 // Create Gmail API service.                 service = new GmailService(new BaseClientService.Initializer()                 {                     HttpClientInitializer = credential,                     ApplicationName = ApplicationName,                     ApiKey = _configuration["Google:ClientSecret"]                 });                 // Get all the EMAIL folders for the current user ("me")                 UsersResource.LabelsResource.ListRequest request =                     service.Users.Labels.List("me");                 // List Email Folders (as Google Labels)                 List<Label> ColLabels =                     request.Execute().Labels                     .ToList()                     .OrderBy(x => x.Name)                     .ToList();                 // Add Inbox as first Label                 Gmaillabels.Add(ColLabels.Where(x => x.Name == "INBOX").FirstOrDefault());                 // Add all labels except INBOX (that has already been added)                 // that are of type "user"                 foreach (var item in ColLabels                     .Where(x => x.Name != "INBOX" && x.Type == "user"))                 {                     Gmaillabels.Add(item);                 }             }         }         catch (Exception ex)         {             strError = ex.Message;         }     }     // Call this method to show the contents of     // the selected folder (Tag)     void ShowFolder(Label paramEmailFolder)     {         Label EmailFolder = paramEmailFolder;         folder = EmailFolder.Id;         _emailFolder.GetFolderContents(folder);     } }



Google Developers Dashboard

Using OAuth 2.0 to Access Google APIs

GMail API .Net Quickstart


The project is available on the Downloads page on this site.

You must have Visual Studio 2019 (or higher) installed to run the code.

An error has occurred. This application may no longer respond until reloaded. Reload 🗙