Conquer Email with Postal and Compose

Published

Creating a custom email server is a breeze with Postal and Compose. Take a deep dive in this article as we tackle all things email.

Handling large amounts of email going out from an organization can be a complex service to administer. That's why services like Sendgrid and Mailgun exist; to simplify the process. But there is an alternative in the form of Postal. Built on RabbitMQ and MySQL, Postal makes email easy to generate mail, manage its delivery and keep track of non-delivery. It's not a complete mail server but can sit in front of other mail services triggering events on incoming mail and ensuring that mail goes out to good servers, securely.

In this article, we'll show you how to deploy the Postal application stack, with the Postal application itself running in the IBM Bluemix Container Service, and Compose RabbitMQ and Compose for MySQL providing the data storage layer.

Introduction to Postal

Postal is Email from your apps, but on steroids.
Statistics Screenshot

The postal management console displays statistics such as incoming and outgoing messages delivered (as well as reasons why they may not have been delivered) and makes adding things like webhooks and tracking links easy and intuitive.
webhooks screenshot

It's an open-source project, making the code freely available to install on any server. Compared to something like the sendmail MTA (Mail Transport Agent) Postal's focus is on sending mail on behalf of applications efficiently. As mail sending can be constrained by various factors, it uses RabbitMQ's message queues and MySQL to manage that backlog.

Those are just a few of the many features Postal offers that makes developing with email a snap. Let's take a look at how to spin up our own Postal server.

Postal using Docker

Postal can be installed locally using the quick install guide. However, in this article, we'll deploy Postal in a containerized environment using the Docker container for Postal. This container provides a fully functioning Postal application as well as a docker-compose.yml file to set up two other services that Postal relies upon: MySQL and RabbitMQ. You can use docker-compose locally to create all of the necessary services to run Postal on your local development machine, but when it comes to pushing those services to production, you'll want a more hardened and robust solution.

To make our service more secure and scalable, we'll use Compose's hosted RabbitMQ and MySQL services, and configure our Postal container to use them. Then, we'll deploy to IBM's Bluemix Container Service.

Create the RabbitMQ Server

Postal uses RabbitMQ as its message broker. When emails are queued to be sent, they're placed in a RabbitMQ queue. Using Compose RabbitMQ ensures that your emails are delivered safely and quickly with minimal downtime.

Spin up a new RabbitMQ deployment by click on the Create Deployment button in Compose dashboard.

Then, select RabbitMQ from the Production Deployments menu and click Create Deployment. You can leave the settings at their defaults, or optionally provide a new deployment name, but we recommend you leave the Location settings alone unless you have a reason to change them.

At this point, you should have a running RabbitMQ deployment. In the Deployment Overview page, scroll down until you see the Connection Strings section. Take note of those as we'll need them later.

Now, we'll set up a username and password so Postal can access this RabbitMQ instance. Click on the browser tab and you'll see a list of all of the available vhosts for RabbitMQ.

Select the vhost by clicking on the link and you'll be taken to the users page. Click on Add User to configure the postal user.

You can make the username and password whatever you'd like, but make sure you remember the username and password you type here. You won't be able to retrieve it later.

Finally, set up the permissions of that user. We want Postal to be able to handle everything it needs, so let's set the permissions for this user to be completely open using the .* permission level:

Create the MySQL Server

The next step in setting up our Postal application is to create the MySQL database that will store the content of your emails, as well as statistics and tracking links.

Head to the Deployments page and click the Create New Deployment button.

Then, select MySQL from the Production Deployments menu and click Create Deployment. You can leave the settings at their defaults, or optionally provide a new deployment name, but we recommend you leave the Location settings alone unless you have a reason to change them.

To access the MySQL connection strings, click on the reveal your credentials link. This will ask you to authenticate using your account and then display your credentials in the Connection Info section of the deployment page.

These credentials are available later, so there's no need to take note of them yet.

Creating a Container in IBM Bluemix Container Service

Now that we have the data services set up, we can deploy our Postal container and begin connecting it up to our Compose services. Our Postal container uses environment variables to link our containers to our data services, so once we run the container on a sandbox at first and then move to production versions of the services in the future.

Setting up the Bluemix and CloudFoundry CLI

The first thing we'll need to do is set up the Bluemix and CloudFoundry CLI. These command-line applications will help us manage our IBM Bluemix

To get started, first navigate to console.ng.bluemix.net and create an account (or log into your existing account). There are two ways you can deploy your application: in a clustered environment using Kubernetes, or as Docker single and scalable containers. Since our application only has one container, we'll choose the single and scalable containers option.

Follow the instructions on the IBM Bluemix site for creating single and scalable containers. Once you've created the container, download the CloudFoundry CLI in the format appropriate for your platform if you haven't done so already. We can verify the installation was completed successfully by running the following command:

cf -v 

Next, install the Bluemix CLI for your platform and install the IBM Container Service plugin so we can start creating our containers in the Bluemix service:

bx plugin install IBM-Containers -r Bluemix  

You can verify the installation by checking out the list of installed plugins:

bx plugin list  

Once you've installed the Bluemix CLI, you'll need to set up your API within the correct region. You'll only need to do this the first time you run the Bluemix CLI:

bx api https://api.ng.bluemix.net  

Now, it's time to log into Bluemix so we can push our Postal image up to it:

bx login  

Pushing Our Custom Postal Image to Bluemix Container Service

Next, we'll want to create a private image registry in the Bluemix Container Service to upload our Postal container image bundled with our custom configuration changes. This needs to be private, rather than on a public registry such as DockerHub, because this image will have full access to our database.

The first step is to create a namespace in the bluemix container registry. You can think of a namespace as the base URL of your registry; you'll likely have a different namespace for every organization or project you wish to deploy. We'll access the Bluemix Container Services plugin by using the ic command modifier for the Bluemix CLI:

bx ic namespace-set <your namespace here>  

If we wanted a namespace for this project of compose_postal, we would have the following:

bx ic namespace-set compose_postal  

And now, we'll initialize the Bluemix Container Service for our namespace and account:

bx ic init  

Once we've initialized the Container Service, we can start to build our local image. First, we'll put together a simple Dockerfile to tell docker how to build our custom Postal image. We'll also configure our environment variables with location and credentials of our Compose hosted services.

FROM sax1johno/postal  
ENV MYSQL_ROOT_PASSWORD <your_mysql_password>  
ENV MYSQL_DATABASE postal  
ENV MYSQL_HOST <mysql_connection_string>  
ENV RABBITMQ_HOST <rabbitmq_connection_string>  
ENV RABBITMQ_DEFAULT_USER <your_rabbitmq_username>  
ENV RABBITMQ_DEFAULT_PASS <your_rabbitmq_password>  
ENV RABBITMQ_DEFAULT_VHOST postal  

Where you see above, make sure you replace those with your actual credentials from Compose.

Finally, let's build our container using the Bluemix CLI, which will automatically upload the build image to our private image repository. The -t flag gives us a tag name that we can use to refer to our image later:

$ bx ic build -t registry.ng.bluemix.net/<your namespace>/postal

Remember to replace with your actual namespace. If you used our namespace above, your command would look like the following:

$ bx ic build -t registry.ng.bluemix.net/compose_postal/postal

You can double-check our image actually made it all the way to your images repository by typing the following into the terminal:

$ bx ic images REPOSITORY                                                  TAG                 IMAGE ID            CREATED             SIZE  

registry.ng.bluemix.net/compose_postal/postal                          latest              8de059ee71fc        2 minutes ago         317.4 MB  

registry.ng.bluemix.net/ibm-node-strong-pm                  latest              322b9ca7b2dc        2 weeks ago         616.4 MB  

registry.ng.bluemix.net/ibmliberty                          latest              6595ea483bf5        2 weeks ago         552.8 MB  

registry.ng.bluemix.net/ibmnode                             latest              b2c351248227        2 weeks ago         472.4 MB  

registry.ng.bluemix.net/ibmnode                             v4                  b2c351248227        2 weeks ago         472.4 MB  

registry.ng.bluemix.net/ibmnode                             v1.1                7d11220193d6        2 weeks ago         449.2 MB  

registry.ng.bluemix.net/ibmnode                             v1.2                84efce0c747b        2 weeks ago         465.2 MB  

You should see your new image listed there.

Building and Deploying Our Container

Now that we've built our Postal container and made it available to the Bluemix Container Service in our private registry, there's just one step left: it's time to run the container!

$ bx ic run --name postal registry.ng.bluemix.net/compose_postal/postal

If all goes well, you should now have a container running in the IBM Bluemix Container Service. You can double-check that your container is running by running the following command:

$ bx ic ps 

CONTAINER ID        IMAGE                                           COMMAND             CREATED             STATUS                  PORTS                         NAMES  

68f6536a-82f        registry.ng.bluemix.net/compose_postal/postal:latest   ""                  3 minutes ago          Running 6 seconds ago   80/tcp                      postal  

Your service is now running in the cloud, but we still need to attach it to a public IP address. To find out the IP addresses available to you, run the following command:

43.222.342.122

NOTE: If you don't see any IP addreses in this list, run the following command to request one.

$ bx ic ip-request

Then, run the previous ips command to see the IP addresses leased to you.

Finally, let's bind one of those ip addresses to our running container:

bx ic ip-bind <your ip address> postal  

Now, just load up a web browser and navigate to your IP address and port. You can test this now by navigating to the UI component of Postal in a browser at http://<your ip address>.

For more information on using the Bluemix Container Service, check out the running single containers tutorial on the Bluemix site.

Final Steps: Running the First-Run Postal Commands

To finish the installation, postal needs you to run its initialization scripts from within your Bluemix container. This initializes the database schemas and sets up the default vhost in RabbitMQ, among some other small administrative tasks.

The Bluemix CLI wraps several common docker commands, including docker attach which we can use as an interactive shell into our container. To connect, you'll need to know the container ID for our postal container:

$ bx ic ps 

CONTAINER ID        IMAGE                                           COMMAND             CREATED             STATUS                  PORTS                         NAMES  

68f6536a-82f        registry.ng.bluemix.net/compose_postal/postal:latest   ""                  3 minutes ago          Running 6 seconds ago   80/tcp                      postal  

Then, we'll attach to that container using it's Container ID:

bx ic attach 68f6536a-82f  

You should now have access to an interactive shell within the container. We'll use this to run our postal setup commands. The first will initialize the database schemas and RabbitMQ vhosts, and the second will guide you through the process of creating an admin user for your postal installation.

cd /opt/postal/bin  
./postal initialize
./postal make-user

Wrapping up

There you have it! By combining IBM Bluemix Container Service, Compose MySQL, and Compose RabbitMQ, we have a fully functional, robust, modern email management environment with multiple mail servers, webhooks, an HTTP and SMTP API, and many more of the goodies we've come to expect from a production mailer. Since all of the services we're using are scalable, this system will help you conquer the email layer whether you're a scrappy startup or are managing hundreds of email servers


If you have any feedback about this or any other Compose article, drop the Compose Articles team a line at articles@compose.com. We're happy to hear from you.

attribution Daria Nepriakhina

John O'Connor
John O'Connor is a code junky, educator, and amateur dad that loves letting the smoke out of gadgets, turning caffeine into code, and writing about it all. Love this article? Head over to John O'Connor’s author page and keep reading.