Category Archives: GitHub

Microsoft 365 Mailbox Attachment Processor

A .NET8 C# Application to Process Microsoft 365 Email Messages and Attachments

Introduction

Recently, I was asked how attachments from a Microsoft 365 mailbox could be automatically pushed into an Azure storage file share, so that the attachments can be made accessible to an onward process which needs to be executed on an Azure Virtual Machine. Whilst there are many ways this can be achieved; I decided to create a C# Console application to process the messages and attachments from Microsoft 365 mailbox inbox folder.

You can download this blob post as a PDF here.

Source Code

The source code for this solution can be found in my GitHub repo here.

Dependencies

There are several dependencies for this to work, these are described in the list below.

  • A Microsoft Entra ID registered application, with the following delegated application permissions:
  • An application secret (this can also be a certificate if needed)
  • Install the Microsoft ExchangeOnlineManagement PowerShell tools
  • Create a Microsoft Exchange Online application policy to allow the application access to the mailbox

# Connect to Exchange Online

Connect-ExchangeOnline -UserPrincipalName [Your Exchange Online Admin UPN] [-ShowBanner:$false]

# Create the app policy

New-ApplicationAccessPolicy -AppId [Your application ID] -PolicyScopeGroupId [Full email address of the mailbox] -AccessRight RestrictAccess -Description “Restrict the Mailbox Processor app..”

Reference: Limiting application permissions to specific Exchange Online mailboxes – Microsoft Graph | Microsoft Learn

  • Create an Azure storage account
  • Create an Azure storage account file share

Nuget Packages

The following Nuget packages are a dependency as defined in the project settings.

  <ItemGroup>

    <PackageReference Include=”Azure.Core” Version=”1.44.1″ />

    <PackageReference Include=”Azure.Identity” Version=”1.13.1″ />

    <PackageReference Include=”Azure.Storage.Files.Shares” Version=”12.21.0″ />

    <PackageReference Include=”Microsoft.Extensions.Configuration.Binder” Version=”9.0.0″ />

    <PackageReference Include=”Microsoft.Extensions.Configuration.Json” Version=”9.0.0″ />

    <PackageReference Include=”Microsoft.Graph” Version=”5.63.0″ />

    <PackageReference Include=”Microsoft.Graph.Core” Version=”3.2.1″ />

    <PackageReference Include=”Microsoft.Identity.Client” Version=”4.66.2″ />

  </ItemGroup>

Mailbox Processor Application

The mailbox processor application consists of the following C# Classes and an appsettings.json file.

File NamePurpose
AuthContext.csA C# Class representing the authentication context for the application
JSONConfigurationBuilder.csA C# Class building the configuration from appsettings.json into the application context
MSAzureStorageOperations.csA C# Class with a method to stream the attachment to Azure Storage File Share
MSGraphOperations.csA C# Class with methods to work with the Microsoft Graph API e.g. read/move messages and attachments and folders
Program.csA C# program, the core of the application
Reference.csA C# Class to store the appsettings that are referenced by the application
Appsettings.jsonThe configuration settings for the application

Application Settings

The application settings have been described below.

{

  “AppSettings”: {

    “MailFolderName”: “[The mailbox folder to target to read the messages]”,

    “MailEmailAddress”: “[The mailbox email address]”,

    “MailSubjectSearchString”: “[The subject search string for each mail message]”,

    “ProcessedMessagesFolderName”: “[Process message mailbox folder name]”,

    “AzureStorageConnectionString”: “[The Azure storage connection string] “,

    “AzureStorageFileShareName”: “[Azure storage file share name]”,

    “MSEntraApplicationClientId”: “[Microsoft Entra ID Application Id]”,

    “MSEntraApplicationSecret”: “[Microsoft Entra ID Application Secret]”,

    “MSEntraApplicationTenantId”: “[Microsoft Entra ID Tenant Id]”

  }

}

Application Runtime Process

The application process is described below.

  1. The configuration is initialised
  2. The messages are retrieved from the defined mailbox folder name
  3. Each message is processed in the message collection and the emails with the matched string that are contained in the subject are processed
  4. A console output of the message ID, received date, received from, and subject is displayed
  5. Each attachment is processed and if the file is a file attachment, then the attachment is uploaded to the Azure file share specified in the Azure storage account connection string and file share name
  6. The number of messages processed, and the number of attachments processed is displayed in the output of the console

Sample Output

The mailbox has two messages with the subject containing the search string “course completions”.

The mailbox attachment processor is executed, it displays the following output.

Two messages are processed, although three were seen in the previous email, but since the search string was not contained in the subject, only two messages were processed which were matched.

Two messages are processed, although three were seen in the previous email, but since the search string was not contained in the subject, only two messages were processed which were matched.

Three attachments in total were processed and uploaded to an Azure storage file share.

The email messages were moved to the ProcessedMessages folder, as defined in the application setting ProcessedMessagesFolderName.

When the application is executed again, the output is shown below as there are no longer any matched messages to process.

Closing Thoughts

From a development point of view, using this method provides a simple solution. Other considerations:

  • Store the storage account key in Azure Key Vault
  • Store the application secret (if used( in Azure Key Vault
  • The Azure resource hosting the application e.g. Function App, can have a managed identity and RBAC access can be provided to Azure Key Vault for the service principal (Azure Key Vault access policies are now deprecated)
  • Environment settings can be stored in the hosting environment configuration rather than in the appsettings.json file.

References

Limiting application permissions to specific Exchange Online mailboxes – Microsoft Graph | Microsoft Learn

Blazor Simple AI Project (Part 4) Invoice Analysis with Microsoft Azure Document Intelligence

Welcome to the Blazor Simple AI Single Page App, Part 4 of the Microsoft AI services journey, which now includes invoice analysis which utilises Microsoft Azure AI Document Intelligence service. The document Intelligence service is used to extract the text from an invoice using a pre-built model. A sample of some of the models is shown below in document intelligence studio.

This document explains the project in my GitHub repository which is available here: https://github.com/tejinderrai/public/tree/main/BlazorSimpleAI.

If you would like to download the whole series of posts for the Blazor Simple AI Project, you can download the PDF here.

Since part 3, the following nuget packages have been added to the project.

Azure.AI.DocumentIntelligence (Pre-release)

New Components

Three components have been developed for the image analysis. These are as follows:

  1. InvoiceLoader.Razor – A component which includes the child component (InvoiceFileList.Razor), which uploads invoices to Azure blog storage container
  2. InvoiceFileList.Razor – A component which lists the invoices that a present in the invoice upload container
  3. InvoiceViewer.Razor – A component which allows the user to view the uploaded invoice in a dialog

Provisioning a Microsoft AI Document Intelligence Service

To provision a Microsoft AI Document Intelligence Service resource, follow the instructions in the article below.

Create a Document Intelligence (formerly Form Recognizer) resource – Azure AI services | Microsoft Learn

Learn about Microsoft AI Document Intelligence

To learn more about the capabilities of Microsoft AI Document Intelligence capabilities, see. Document Intelligence documentation – Quickstarts, Tutorials, API Reference – Azure AI services | Microsoft Learn. Microsoft Azure AI Document Intelligence includes more analysis capabilities, not just specifically an invoice model.

Configuration Settings Changes

The following configuration settings were added to appsettings.json.

“AzureDocumentIntelligenceConfig”: {

    “AzureDocumentIntelligenceKey”: “[Your Azure Document Intelligence Key]”,

    “AzureDocumentIntelligenceEndpoint”: “[Your document intelligence endpoint https://[Resource Name].cognitiveservices.azure.com/”

  },

“AzureStorageConfig”: {

    “AzureStorageInvoiceContainer”: “[Your Invoice Upload Container Name]”,

    “AzureStorageInvoiceProcessedContainer”: “[Your Invoice Processed Container Name]”,   },

The invoice processed container is the output interface file that is generated from the text extracted from the original invoice file. It is an output of JSON which utilises the InvoiceAnalysisData data type.

Note: Whist this project utilises the service key, in an enterprise environment, you must consider using token based access to the service secured by Microsoft Entra ID, or if you wish to utilise the service key for any reason, utilise Azure Key Vault to protect the key used by the application with a managed identity for the application to access the service key stored in Azure Key Vault.

Components

Invoice Loader Component (InvoiceLoader.Razor)

The invoice upload component utilises Blazor InputFile for the user to select the file to upload in the application. The component reads the Azure Storage connection string from the configuration, including the container, then uploads the file to the container and also adds a blob http header for the file content type taken from the file properties. The Radzen notification service is used to notify the user of the application activities. I also included a basic spinner as part of the interaction for the upload process.

Invoice File List Component (InvoiceFileList.Razor)

This component reads the Azure Storage connection string from the configuration, including the container, then displays the invoice blob file names in a Radzen DataGrid. A button is added to view the invoice, or process the invoice, which then calls the Radzen notification service to display the activities being taken by the application.

Invoice Viewer Component (InvoiceViewer.Razor)

This component is a child component displayed in a Radzen dialog box which displays the original uploaded invoice directly from the Azure blob storage invoice upload container. A storage SAS key is generated which provides time limited access to the user in order for the invoice to be displayed in the dialog.

Data Classes

InvoiceAnalysisData.cs – The class for the invoice.

InvoiceItem.cs –  The class for the invoice items.

Invoice Sample

I have created an invoice samples to test the pre-built invoice model from Microsoft Azure Document Intelligence.

Supplier 1 Invoice (PDF)

I created two additional sample invoices, both of which were tested and successfully processed. I have not covered the upload of these in my blog post.

Supplier 2 – Jpeg image

(Missing Quantity)

Invoice 3 – Handwritten Invoice – jpeg image

The UI

The UI for invoice analysis is as follows.

Invoice Analysis

Upload File

View Button – Opens the PDF in a dialog box

Process Button – Interactive Dialog box

Processing Completed – Invoice details – text extracted into InvoiceAnalysis object.

Submit Button – Create an output interface file in JSON format.

Azure Storage – (invoiceanalysisupload container)

Processed Output file

File Contents

{
"VendorName":"Car Parts UK Ltd",
"VendorAddress":"15 Street Gardens\nPoole, Dorset, DS11 333",
"CustomerName":"Car Shop",
"CustomerAddress":null,
"InvoiceItems":[
{"Quantity":10.0,"ItemDescription":"Ferrari 360 Spider Hood","Amount":"50000"},
{"Quantity":5.0,"ItemDescription":"Ferrari 360 Spider Gearbox","Amount":"12500"}
],
"Tax":"12500",
"InvoiceTotal":"75000"
}

Note: The code does not extract the customer address, but this is in fact possible.

The handwritten jpeg image, the second invoice as a jpeg image and the PDF all proved to have 100% extraction using the Microsoft AI Document Intelligence service. That’s just amazing!

It is as simple as that!

The reason for creating a interactive SPA as a sample app, is to demonstrate the features. The same code can be used in event driven architectures, or scheduled triggers. That will be something I will  post next.

Invoice 2 – jpeg output

Invoice 2- viewer

Invoice 2 – Processed

Invoice 3 – Handwritten jpeg

CarShop .NET Core Blazor Project – Part 5

Following on from Part 4, where I provided the links to the CarShop views SQL, I have now published the C# project which defines the data model classes for the CarShop database tables and views. The data classes project has been separated into it’s own project as this will be shared as a dependency with the CarShop Blazor Server project and in future, I will develop the API’s in a separate project.

The project has been published on my GitHub repo here.

You can also follow the guidance from Microsoft to create model classes with the Entity Framework, documented here.

CarShop .NET Core Blazor Project – Part 4

Following on from Part 3, where I provided the links to the CarShop database seeding SQL, I have now published the database view SQL scripts in my public GitHub repo. At present there are two database views.

The database view scripts are listed below.

1 – CarModels_View.sql – provides view of car manufacturers and models.
2 – Vehicles_View.sql – provides a view of vehicles with column data vs foreign key identifiers

The CarShop database view SQL scripts can be found in my GitHub repo here.

It is likely that over the course of developing the project, the number of views will expand, hence the reason to separate out the location of the view SQL scripts as apposed to the database mode creation or data seeding SQL scripts.

CarShop .NET Core Blazor Project – Part 3

Following on from Part 2, where I provided the link to the CarShop schema deployment SQL, I have now published the database seeding scripts in my public GitHub repo, for the initial supporting data. At present there are six tables in the database which have data seeding scripts.

The data seeding scripts are listed below.

1 – EngineSize.sql – Inserts a list of engine sizes into the EngineSize table.
2 – Salutation.sql – Inserts a list of salutations for customers into the Salutation table (only basic salutations are loaded)
3 – CarFuelType.sql – Inserts the car fuel types for vehicles into the CarFuelTypes table
4 – CarColour.sql – Inserts a basic list of car colours into the CarColours table
5 – CarManufacturers.sql – Inserts a basic list of car manufacturers into the CarManufacturers table
6 – VehicleStatus.sql – Inserts a list of Vehicle status flags into the VehicleStatus table.

The CarShop data seeding SQL scripts can be found in my GitHub repo here.

CarShop .NET Core Blazor Project – Part 2

Following on from Part 1, where I introduced the CarShop project, I have now published the database scripts in my public GitHub repo, for the data model. At present there are nine tables in the database schema, which need to be created in a specific order to maintain relationships. The tables are listed below.

CarManufacturers – Table to hold all car manufacturer details

CarModels – Table to hold all car models

VehicleStatus – Table to hold the vehicle status e.g. “For Sale”

CarFuelTypes – Table to hold the fuel type for a vehicle

CarColours – Table to hold the car colours

Engine Size – Table to hold all car engine sizes

Vehicles – Table to hold all car vehicle details which has relationships to the above tables as per the Part 1 CarShop project blog post showing the schema diagram.

Salutations – Table to hold all customer salutations

Customers – Table to hold all customer details which has a relationship with Salutations

Some of the tables hold default e.g. Vehicles previous owners has a default of 1 since the vehicles are not new at the Carshop.

The CarShop model SQL scripts can be found in my GitHub repo here.

My Public Code Repository on GitHub

For a while now, I have been adding code inline within my blob posts. I’ve now released a public repository on GitHub, which I will be using moving forward to publish all my community shared code, free for use with the MIT license.

I will start to publish my previous code into the public repository, for now I’ve published a recent .NET 5 console app which is a basic RSS reader that currently reads the .NET teams RSS feed. My public repository can be found below.

Tejinder Rai on GitHub