Killing your Outlook with Docker and davmail

Chris Weyl

September 29, 2014

Share +

Love it or hate it, sometimes we have to use an Exchange server to communicate. This may pose a problem for you, if you prefer a non-Microsoft mail client: if the compatibility features are enabled, you'll be able to access your mail via IMAP and send over SMTP, as the Internet intended.

If not... well... that's where tools like davmail come in. davmail is a Java application that knows how to translate between standards-compliant clients (like, say, Thunderbird) and an Exchange server that speaks only Exchange. It's a great tool -- and one of the only solutions. It's also standalone, can be used statelessly, and -- with apologies -- is Java, making it a fantastic candidate for running inside a Docker container.

Goals

Install Docker on a CenturyLink Cloud instance, provision a stateless container image running a davmail instance, and have the system manage the container via upstart.

Caveats

Provisioning a CenturyLink Cloud instance is left as an exercise for the reader. For simplicity, we're using the docker.io package from Ubuntu and configuring by hand. One may find a more satisfying approach in using tools like puppet-git-receiver and Gareth Rushgrove's most excellent docker Puppet Forge module to manage the use of the upstream Docker packages as well as our container's upstart configuration -- both of which will be covered in a future tutorial. Security is of utmost concern, particularly in a corporate environment, so please note that securing the connections between your local workstation and the cloud instance. Common -- and well-established -- solutions include the use of ssh port forwarding or (for a less ad-hoc approach) stunnel. Even if your mail is boring beyond belief, please, do not access it unencrypted. It just makes the rest of us look bad.

Prerequisites

For the purposes of this article, we're going to assume that you're an enligtened sort, and are running a Ubuntu 14.04-based cloud instance (or workstation, or...). If not, keep on reading. You can fire up basic Ubuntu machine fairly easily. Install and configure on your system:

Install Docker

We'll use Docker as packaged by Ubuntu:

[gist id=c31941bbb5a4a5f449b3 file="docker.io-install.log" /]

On line 33 we see a docker group being created. It's worth mentioning that adding your userid to this group will allow you to interface with the docker service without needing to "sudo" it all the time; this is left as an exercise for the reader.

Create/choose our image

does not require any bind-mounts or other external volumes to be attached;

is stand-alone; and

does not run davmail as root inside the container.

You may need to edit the davmail configuration to reflect the specific needs of your Exchange environment. If so, you can use this image as a starting point, ADD the changed configuration to the image, and rebuild. Here's the Dockerfile for this image:

[gist id=c31941bbb5a4a5f449b3 file="Dockerfile" /]

...and for kicks, let's try it:

[gist id=c31941bbb5a4a5f449b3 file="docker-run-trial.log" /]

Tada! :)

Configure a container to run as a system service via upstart

upstart is an approach to unix daemon management. It is available by default on recent Ubuntu systems, and is very convienient to our purposes.

[gist id=c31941bbb5a4a5f449b3 file="docker-corporate-davmail.conf" /]

Note how our upstart config does a couple different things here:

declares dependencies on the docker.io service (lines 6 and 7)

declares that the service should be relaunched if it terminates unexpectedly (line 11) and establishes safe limits (line 12)

declares how to start (lines 15-27) and stop (lines 30-35) the service.

Not surprisingly, the heart is centered around the docker run command that we can see at the core of the upstart config.

[gist id=c31941bbb5a4a5f449b3 file="docker-run-command.sh" /]

Our Docker port-forwards are also established; from the "trial run" log above we can see that the ports davmail will listen on are:

SMTP port 1025

POP port 1110

IMAP port 1143

CALDAV port 1080

LDAP port 1389

Remember nix systems disallow non-privileged process from binding to ports < 1024, and as such ours have been remapped. We additionally tell docker to bind ours such that our cloud instance:

listens to the exported ports + 10,000

binds only to ports on the loopback interface

That is, when you go looking for IMAP, you'll find it accessible at 127.0.0.1:11143 from the cloud instance only; this prevents attackers from being able to connect to your davmail instance remotely. Now that we have an upstart config file, all that remains is to install the file appropriately (that is, copy it into /etc/init/ and start the service:

[gist id=c31941bbb5a4a5f449b3 file="upstart-config.log" /]

This container is stateless -- that is, it only handles translating between standards-compliant and Exchange-compliant tools. You can start, stop, kill, abuse, disabuse, etc, the container davmail is running inside without fear of anything more than disrupting communications between your clients and the server. Complexity avoided is hours of time we get to keep.

Enjoy!

And with that, you have davmail running inside a container, with the appropriate port-mappings configured. You can now use this to interface the mail client(s) of your choice with an Exchange server. This author recommends pine... But that might just be him :)