Nov 24

Written by: Michael Washington
11/24/2017 3:58 PM  RssIcon

You can create an automated Azure function that will retrieve emails from a Pop3 email account and store the list of the emails in an Azure storage Table and the emails themselves as Azure storage Blobs. To do this, we will leverage the open source project, MailKit and to create, debug, and deploy the Azure function, we will use Azure Functions Tools for Visual Studio.

Note: Azure Functions Tools is included in the Azure development workload of Visual Studio 2017 version 15.4, or a later version. Make sure you include the Azure development workload in your Visual Studio 2017 installation (See: Azure Functions Tools for Visual Studio for assistance).

Create An Azure Storage Account

image

We will need a general Azure storage account.

If you do not already have a general Azure storage account, log into the Azure Portal, and select New.

image

Search for, and select: Storage account - blob, file, table, queue.

image

Click Create.

image

Fill in the options and click Create.

Your Azure storage, that will contain your Table and Blob storage, will now be created.

Install The Azure Storage Explorer

image

Go to: https://StorageExplorer.com and download and install the Azure Storage Explorer.

image

When you open the application and log in (using your Azure username and password), you will see your storage.

Create a Blob Container called pop3-messages and a Table called pop3messages.

image

When you select the storage account, and look in its Properties, you can access the Primary Connection String.

Use Ctrl+C to copy it. You will need it for a later step.

Create The Azure Function

image

Open Visual Studio 2017.

image

Select File then New then Project.

image

Create an Azure Functions project.

image

Open local.settings.json.

image

Update both the AzureWebJobsStorage and AzureWebJobsDashboard values with the Primary Connection String you copied from the Azure Storage Explorer earlier.

image

While were here, add keys and values to log into your Pop3 email server.

You can get the settings for popular services here: List of SMTP and POP3 Server (also a list here).

Save and close the file.

Add MailKit

image

To add MailKit, the open source library that will allow us to retrieve emails, we need to right-click on the Project node in the Solution Explorer, and select Manage NuGet Packages…

image

Search for MailKit, select it, and install it.

image

It will install.

image

Right-click on Dependencies and select Add Reference.

image

Add a reference to System.Configuration.

image

Right-click on the Project node, and select Add, then New Item…

image

Create a function called PopEmail.

image

Make it a Timer trigger.

Use the following code:

 

using MailKit.Net.Pop3;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Table;
using System;
using System.Configuration;
using System.Net;
namespace Pop3Email
{
    public static class PopEmail
    {
        public class EmailMessage : TableEntity
        {
            public DateTime EmailDate { get; set; }
            public string EmailFrom { get; set; }
            public string EmailTo { get; set; }
            public string EmailSubject { get; set; }
        }
        // Note: "0 */5 * * * *" will run once every 5 minutes. 
        // Change it to: "0 */1 * * * *" to run once a minute
        [FunctionName("PopEmail")]
        public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, 
            [Table("pop3messages", Connection = "AzureWebJobsStorage")]CloudTable outputTable,
            TraceWriter log)
        {
            log.Info("function processed a request.");
            string _cloudUploadedFilesContainerName = "pop3-messages";
            string _storageConnectionString = ConfigurationManager.AppSettings["AzureWebJobsStorage"];
            string _POP3Server = ConfigurationManager.AppSettings["POP3Server"];
            int _POP3Port = Convert.ToInt32(ConfigurationManager.AppSettings["POP3Port"]);
            bool _POP3UseSSL = Convert.ToBoolean(ConfigurationManager.AppSettings["POP3UseSSL"]);
            string _POP3Username = ConfigurationManager.AppSettings["POP3Username"];
            string _POP3Password = ConfigurationManager.AppSettings["POP3Password"];
            using (var client = new Pop3Client())
            {
                // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                client.Connect(_POP3Server, _POP3Port, _POP3UseSSL);
                // Note: since we don't have an OAuth2 token, disable
                // the XOAUTH2 authentication mechanism.
                client.AuthenticationMechanisms.Remove("XOAUTH2");
                client.Authenticate(_POP3Username, _POP3Password);
                for (int i = 0; i < client.Count; i++)
                {
                    string strMessageGUID = Guid.NewGuid().ToString();
                    var message = client.GetMessage(i);
                    var NewItem = new EmailMessage();
                    NewItem.EmailDate = message.Date.Date;
                    NewItem.EmailSubject = message.Subject;
                    log.Info($"Got Message: {message.Subject}");
                    // Get all From Addresses
                    string strFromAddresses = "";
                    foreach (var item in message.From.Mailboxes)
                    {
                        strFromAddresses += item.Address + ";";
                    }
                    NewItem.EmailFrom = strFromAddresses;
                    // Get all To Addresses
                    string strToAddresses = "";
                    foreach (var item in message.To.Mailboxes)
                    {
                        strToAddresses += item.Address + ";";
                    }
                    NewItem.EmailTo = strToAddresses;
                    NewItem.PartitionKey = "pop3";
                    NewItem.RowKey = strMessageGUID;
                    NewItem.ETag = "*";
                    try
                    {
                        var operation = TableOperation.Insert(NewItem);
                        outputTable.ExecuteAsync(operation);
                    }
                    catch (Exception ex)
                    {
                        log.Info(ex.Message);
                    }
                    // Save the Message as a Blob because it is too big to fit in a Table
                    var EmailContent = ((MimeKit.TextPart)message.Body).Text;
                    var _cloudStorageAccount = CloudStorageAccount.Parse(_storageConnectionString);
                    var _cloudBlobClient = _cloudStorageAccount.CreateCloudBlobClient();
                    var _cloudFilesBlobContainer =
                        _cloudBlobClient.GetContainerReference(_cloudUploadedFilesContainerName);
                    CloudBlockBlob targetBlockBlob = 
                        _cloudFilesBlobContainer.GetBlockBlobReference(strMessageGUID);
                    log.Info($"UploadFromStream: {strMessageGUID}");
                    targetBlockBlob.UploadTextAsync(EmailContent);
                    // [OPTIONAL] Mark the message for deletion
                    // client.DeleteMessage(i);
                }
                log.Info("client.Disconnect");
                client.Disconnect(true);
            }
        }
    }
}

 

image

Hit F5 to run the project.

image

The Azure CLI will run.

As long as the project is running, it will check for emails every 5 minutes (unless you change the timer setting – see the comments in the code on how to do this).

image

If we look in the Azure Storage Explorer under tables/pop3Messages

image

We will see a list of emails that each have a unique RowKey.

image

If we look under under Blob Containers/pop3Messages

image

We will find the email content.

image

If you download the file, change its extension to .htm, you can open the email and view it.

Publishing

image

We can publish the function to Azure using the directions at this link.

image

After publishing, log into the Azure Portal, and select App Services.

image

Select the App Service that the function is contained in and select Application settings.

image

This will take you to the screen that will allow you to add the needed application settings.

When you publish a function to Azure, it will not copy the application settings from local.settings.json. You have to copy the values from that file to Azure manually.

Notes

If you get authentication errors, your email service may require you to go into special settings to enable Pop3 access. For example, Yahoo email requires you to enable Less Secure Settings.

MailKit will allow you to connect with IMAP rather than Pop3. There is a getting started at this link.

Links

List of SMTP and POP3 Server (also a list here)

Visual Studio 2017

Azure Storage Explorer

MailKit

Using .NET class libraries with Azure Functions

Improvements to Azure Functions in Visual Studio

Download

The project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

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


Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation