Skip to content

DavMail Office365 Bridge

Recently I started at an institution which uses a groupware which is deliberately incompatible with open groupware protocols such as IMAP,SMTP,CalDAV. This leaves the option to use the provided webinterface which I think is inconvenient.

Fortunately there exists the DavMail project, which is a bridge between the ExchangeWebServices and open protocols. It works by being a client to EWS and then exposing a server interface on the usual ports shifted up by 1000 (e.g. IMAP being at 1143 instead of 143). There are two possible operation modes, one as a local deamon to run on desktop systems and one server/headless version. For a single desktop client, the first is fine, but I wanted to have access from my phone too. Unfortunately the headless version does not yet have an oauth workflow to log in with the two-factor authentication. The workaround is to register through the desktop version and then copy the authentication token to the headless deployment.

Acquiring the Authentication Token

Info

skip this section if you don't have 2FA

Install DavMail on a desktop system and keep the default values, except change the authentication method to O365Interactive. The easiest way to trigger the MFA authentication is to open the CalDAV interface at http://localhost:1080/ and log in with your email and password.

This opens a dialog of DavMail with a link which you can use in any browser, authenticate to Microsoft and provide the SMS/auth token and authorize the DavMail application. Copy the final link (with the token in the parameters) showing an empty page, back to the DavMail dialog. After successful authentication, close davmail and locate the davmail.properties file to extract the line which starts with

davmail.oauth.<user@email.tld>.refreshToken={AES}...

This is your oauth token which keeps you logged in. It is encrypted with your password such that on successful authentication to the DavMail server it can decrypt the token and use it to log into the EWS service.

Preparing a TLS Certificat

When running DavMail as a server, the connection no longer stays on the localhost and must be secured by TLS. Acquire a TLS certificate for the domain you want to run the service on with e.g. Let's Encrypt or ZeroSSL.

This usually returns a key.pem (unencrypted RSA key) and cert.pem (with Certificate-Chain). To prepare it for DavMail, it has to be stored in PKCS12 format. First encrypt the private key with a password of your choice:

openssl rsa -aes256 -in key.pem -out key.encrypted

and then create the PKCS12 container with a fresh container password:

openssl pkcs12 -export -in cert.pem -inkey key.encrypted -certfile cert.pem -out davmail.p12 -legacy

Info

depending on your java and openssl versions, you might need the -legacy option to create the p12

As ACME certificates usually have a 90 day validity, you need to automate this process in a cron script.

Deploying a DavMail server

The easiest option to run the DavMail headless version is as docker image with docker-compose and the following configuration:

version: "3"

services:
  davmail:
     image: quay.io/connectical/davmail
     ports:
         - "1080:1080" # caldav
         - "1025:1025" # smtp
         - "1143:1143" # imap
     volumes:
        - logs:/var/log/davmail
        - ./davmail.properties:/etc/davmail/davmail.properties
        - ./davmail.p12:/etc/davmail/davmail.p12
volumes:
   logs

Info

the docker hub image of davmail is no longer maintained and is now pushed to quay.io

The ./davmail.p12 path should point to the previously prepared PKCS12 container.

To prepare the davmail.properties file, download a default version from https://github.com/ogarcia/docker-davmail/blob/master/.circleci/docker/davmail.properties and set up the certificate with the matching passwords:

davmail.ssl.keystoreType=PKCS12
davmail.ssl.keystoreFile=/etc/davmail/davmail.p12
davmail.ssl.keystorePass=<container password>
davmail.ssl.keyPass=<secret key password>

More importantly, enable the headless version to authenticate to EWS. therefore replace davmail.enableEws=auto with

davmail.enableEws=EWS
davmail.authenticator=davmail.exchange.auth.O365Authenticator

davmail.oauth.<user@email.tld>.refreshToken={AES}...

If you want to proxy multiple users, add a line for each.

Run the server with

docker-compose up -d
and make sure that the ports are open in your firewall.

Authentication problems

The login page at https://login.microsoftonline.com/ has a different oauth flow depending on your user agent. To get the simplest flow, pretend to not be a browser with e.g.

davmail.userAgent=python-requests/2.31.0

Warning

This user agent is also used for the login page of a possible ADFS. Your friendly administrator may ask you about suspicious non browser logins.

Clients

To connect clients to the new server, you need the correct settings as there is no autoconfiguration available. As server address it is always the one you used for the certificate creation. As username, use your full email, and the correct password.

Protocol Port Config
IMAP 1143 enable TLS (not STARTTLS) and cleartext auth
SMTP 1025 enable TLS, plain auth
CaDav https://server.domain:1080/ make sure to use https

Troubleshooting: K9 Mail on Android

When setting up the mail account on K-9 mail or its derivatives, it fails because of an unsupported IMAP command. This is resolved by creating a new empty folder named SPECIAL-USE through the Outlook web interface.

Troubleshooting: Kmail Timeout

Kmail has a very short timeout on fetching messages. For large messages, davmail is not fast enough to fetch the message via http before kmail times out. A workaround is to let davmail cache messages with

davmail.folderSizeLimit=1000000
However, this is somehow limited to 1000 messages.