Check Exchange from the Command Line

Through the years, you tend to accumulate a suite of tools, practices and settings as you use Linux. In my case, this has meant a Mutt configuration that fits me like a tailored suit and a screen session that at home reconnects me to my IRC session and at work provides me with quick access to e-mail with notifications along the bottom of the terminal for Nagios alerts and incoming e-mail. I've written about all of these different tools through years, but in this article, I talk about how I adapted when one of my scripts no longer worked.

My e-mail notification script is relatively straightforward. I configure fetchmail on my local machine, but instead of actually grabbing e-mail, I just run fetchmail -c, which returns each mailbox along with how many messages are unseen. I parse that, and if I have any unread mail, I display it in the notification area in screen. I wrote about that in my February 2011 Hack and / column "Status Messages in Screen", and up until now, it has worked well for me. Whenever I set up my computer for a new job, I just configure fetchmail and reuse the same script.

Recently, however, we switched our mail servers at work to a central Exchange setup, which by itself wouldn't be too much of an issue—in the past I just configured Mutt and fetchmail to treat it like any other IMAP host—but in this case, the Exchange server was configured with security in mind. So in addition to using IMAPS, each client was given a client certificate to present to the server during authentication. Mutt was able to handle this just fine with a few configuration tweaks, but fetchmail didn't fare so well. It turns out that fetchmail has what some would call a configuration quirk and others would call a bug. When you configure fetchmail to use a client certificate, it overrides whatever user name you have configured in favor of the user specified inside the client certificate. In my case, the two didn't match, so fetchmail wasn't able to log in to the Exchange server, and I no longer got new mail notifications inside my screen session.

I put up with this for a week or so, until I realized I really missed knowing when I had new e-mail while I was working. I decided there must be some other way to get a count of unread messages from the command line, so I started doing research. In the end, what worked for me was to use OpenSSL's s_client mode to handle the SSL session between me and the Exchange server (including the client certificate), and then once that session was established, I was able to send raw IMAP commands to authenticate and then check for unread messages.

OpenSSL s_client

The first step was to set up an OpenSSL s_client connection. Most people probably interact with OpenSSL on the command line only when they need to generate new self-signed certificates or read data from inside a certificate, but the tool also provides an s_client mode that you can use to troubleshoot SSL-enabled services like HTTPS. With s_client, you initiate an SSL connection and after it outputs relevant information about that SSL connection, you are presented with a prompt just as though you used Telnet or Netcat to connect to a remote port. From there, you can type in raw HTTP, SMTP or IMAP commands depending on your service.

The syntax for s_client is relatively straightforward, and here is how I connected to my Exchange server over IMAPS:

$ openssl s_client -cert /home/kyle/.mutt/imaps_cert.pem
 ↪-crlf -connect

The -cert argument takes a full path to my client certificate file, which I store with the rest of my Mutt configuration. The -crlf option makes sure that I send the right line feed characters each time I press enter—important for some touchy IMAPS servers. Finally the -connect argument lets me specify the hostname and port to which to connect.


Kyle Rankin is Chief Security Officer at Purism, a company focused on computers that respect your privacy, security, and freedom. He is the author of many books including Linux Hardening in Hostile Networks, DevOps Troubleshooting and The Official Ubuntu