Sending Email from Web App using On-Prem SMTP Server and Storage Queue Relay
When organizations move web applications to the cloud, they often look to hosting environments such as Azure Web Apps. The Platform as a Service (PaaS) environments are very appealing because they reduce the operations and management overhead, but in some cases it turns out that things that used to be easy to do on-prem have now become more complicated. One example is applications that use a local (on-prem) SMTP servers to send email.
A Web App will typically not have access to the on premises network unless steps are taken to connect it using either an App Service Environment or Web App Virtual Network integration in combination with Express Route or VPN connection. Consequently, the Web App will not have access to the on-prem SMTP relay when deployed in the cloud.
There are tools such as SendGrid that can be leveraged, but for some organizations (e.g., Government Agencies) use of such services may break compliance, e.g. with TIC rules. So early cloud adopters may be faced with some challenges in order to comply with existing approved services for relaying email while modernizing their applications and moving to the cloud.
Solutions such as App Service Environment and Express Route will certainly get the job done, but they may make the deployment more costly and complicated and it certainly seems like overkill if the only purpose is to relay email.
Another option is to have the Web App enqueue mail messages on a Storage Queue in Azure and have an application (on-prem or in a virtual network peered with the on-prem network) do the actual sending of emails through the local SMTP server.
I have made an application that does just that. It is written in C# (.NET Core 2.0) and can be found in this GitHub repository. The repository contains 3 small .NET core projects: A shared library with a class for serializing and deserializing mail messages, the MailQ application, which will grab messages from a queue, and a MailSender test application, which can be used to put mail messages on the queue and also as a code example for how to send messages from the Web App.
MailQ service application is available as Docker image and it can be run with a command line:
#Running docker container and passing environment variables
docker run -e ConnectionString='AZURE STORAGE ACCOUNT CONNECTION STRING' -e MailQueueName='QUEUE NAME' -e SmtpServer='smtp.domain.us' hansenms/mailq
There are several ways it can be deployed. One option would be to run this Docker container directly on the on-prem network, another would be in a virtual network that is peered with the on-prem network through VPN connections or Express Route. The illustration below shows both options.
MailQ service is deployed you can use the
MailSender test application to send an email to the storage queue. You will need to set the following environment variables:
SmtpServer. You can run the client with:
You will be prompted for email addresses, subject and message body.
MailQ service and the
MailSender test application use a
SerializeableMailMessage class, which I found here and I made a few modifications to it. This class is used to serialize and deserialize
MailSender app is mainly intended for test purposes, but you can also use it to find the code that you would need in your web app to enqueue mail messages on the Azure Storage Queue. The code starts by forming a
System.Net.Mail.MailMessage object, which is the object you would normally send using the
System.Net.Mail.SmtpClient. The only modification you will need to your code is to serialize the message (using the provided class) and add it to the queue instead of sending. You can even abstract this choice in a function and pick whether to send directly with the SmtpClient or adding it to the queue depending on where the application is deployed.
Last comment is that while the example I used here is sending email, a similar workflow could be used for other types of messages that may need to be relayed back to legacy on-prem systems. Depending on the types of messages you are trying to relay, you can also consider Azure Service Bus. You can find a comparison of Storage Queue and Service Bus in the Azure Documentation.
If you have other solutions to such problems, do let me know and as always please let me know if you have questions/comments/suggestions.