Thursday, 12 March 2015

PowerShell SMTP server for Elastic Beanstalk

Applications developed in .net commonly send email by creating mime files (.eml files) and dropping them into a specified folder.  The actual sending often depends on Microsoft's IIS 6 SMTP server.

SMTP server replacement in Elastic Beanstalk

When such applications get migrated to Elastic Beanstalk (EB), every instance of the application runs on it's own instance (server).  Any functionality that rights locally, writes to the local storage of that instance, which can be replaced at any time.  Each instance also has to have it's own SMTP server installation, and IIS 6 can't be easily scripted.

An alternative method is therefore required to pick up .eml files generated and emailing them.  Ideally, the applications should be changed, but as this is not always practical, I created a solution to schedule a task to regularly run a PowerShell script.  The script checks for files in a location (dropmail folder), and processes them.

The simplest way to make changes to Elastic Beanstalk instances is through “.config” files in the .ebextensions folder.  A file “schedulemail.config” is created in the .ebextensions folder.

The solution is a simple way that illustrates a number of things, including the use of ebextensions with Windows Elastic Beanstalk applications, scheduling tasks with PowerShell, and sending .eml files with PowerShell (more later).

The .config files you create in .ebextensions are YAML files.  The key things to know about these files are:
  • indentation is critical (think Python)
  • you can't use tabs, only spaces
  • elastic beanstalk applications simply fail if there's anything wrong.
I have found that the most common reason for a simple, silent, failure of an EB deployment is a tab in a .config file.

This config file creates three files:
c:/software/sendFile.ps1
c:/software/archiveEmail.ps1
c:/software/scheduleMail.ps1

It then runs the last of these as a command.  This creates a scheduled task that runs sendFile.ps1 every minute and archiveEmail.ps1 every 10 minutes.

Emails are archived to an S3 bucket, where a lifecycle rule can be set up to delete anything older than 2 weeks, but that can be modified as required.  Of course, whether or not it is necessary to archive the email files would depend entirely on your application.

The actual sendFile.ps1 in this file sends email using Mandrill, but on the way there I also used two other methods for sending .eml files.  Any of them can very easily be substituted.

The config file can be downloaded from my github repository and modified.  You will have to add your own key, and if you want to receive notification in the event of failure, add your own email.

Saturday, 7 March 2015

Sending .eml files using PowerShell

In this post, I provide three different scripts for sending a mime file (e.g. .eml file as is created by .net applications) via email.

I had to learn a few tricks along the way, and thought it worth documenting it here.

The scripts form the basis of a replacement for Microsoft's IIS 6 SMTP server.

Using Amazon SES

First ensure SES is properly configured for your domain. This involves the usual proving you own the domain etc., as well as requesting a removal of the limit that allows you initially to only test it.

Once SES is set up, you set up SNS to monitor the sending. The simplest way is to simply email SNS notifications to a dedicated mailbox where you can then search for specific email addresses on demand to see if emails were delivered, bounced or rejected.

Of course, you can set up something much more clever with SNS given time and inclination.

The work-horse of this method is Send-SESRawEmail. For me the problem was that Send-SESRawEmail takes a MemoryStream as input, and I struggled to find the documentation on how to do this. I'm not sure how efficient it is, but this script takes a file and converts it to a MemoryStream before passing it in.

Using SMTP

It is possible to send an email directly to an SMTP server.  I’ve not tried encrypted SMTP yet.  This obviously requires an SMTP server to be set up correctly, but you may well have this for other puposes.

Essentially, what you do is simply connect to the SMTP port and talk to it.  For this you create a TcpClient Object and a StreamWriter object and write the handshake, then the content to port 25.  In spite of both the sender and receiver being included in the .eml file, you still need to provide a sender and recipient in the initial handshake.

The script here will send an email file and takes 6 parameters (including the filename).  Download and use Get-Help to get a bit more information, or simply have a look at the script.  There's a lot more information on scripting network connections in PowerShell in this post by Lee Holmes.

Using Mandrill

We’ve been using Mandrill for some time to send emails.  You can send to Mandrill through SMTP, but in this solution I call the Mandrill restful API directly.  When I eventually worked out how to do it, this was the simplest solution, as well as keeping with what we already use. The SendFile-Mandrill.ps1 script requires just the filename and your Mandrill API key.