Nov
24
Written by:
Michael Washington
11/24/2017 3:58 PM
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
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.
Search for, and select: Storage account - blob, file, table, queue.
Click Create.
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
Go to: https://StorageExplorer.com and download and install the Azure Storage Explorer.
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.
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
Open Visual Studio 2017.
Select File then New then Project.
Create an Azure Functions project.
Open local.settings.json.
Update both the AzureWebJobsStorage and AzureWebJobsDashboard values with the Primary Connection String you copied from the Azure Storage Explorer earlier.
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
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…
Search for MailKit, select it, and install it.
It will install.
Right-click on Dependencies and select Add Reference.
Add a reference to System.Configuration.
Right-click on the Project node, and select Add, then New Item…
Create a function called PopEmail.
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);
}
}
}
}
Hit F5 to run the project.
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).
If we look in the Azure Storage Explorer under tables/pop3Messages…
We will see a list of emails that each have a unique RowKey.
If we look under under Blob Containers/pop3Messages…
We will find the email content.
If you download the file, change its extension to .htm, you can open the email and view it.
Publishing
We can publish the function to Azure using the directions at this link.
After publishing, log into the Azure Portal, and select App Services.
Select the App Service that the function is contained in and select Application settings.
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.