You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
6.1 KiB

---
title: Using Mutt with Exchange
tags:
- Linux
- Vim
- Mutt
- FZF
description: Like many organisations, the company I work at uses an Exchange server for email and calendar. My preferred email client is NeoMutt. I use Davmail to make these two work together.
date: 2020-03-10
---
[Mutt](http://www.mutt.org/) is an extremely powerful, vim like email client. Unfortunately, like many, the company I work for uses Exchange for email and calenders. As a Linux user, I can't (and don't want) to install outlook and I don't want to have to open a web browser, every time I want to check an email. My mission was to find a way to manage my work emails using Mutt.
For the purpose of this blog, I assume that you cannot connect to the Exchange server directly with IMAP or SMTP. If you are unsure, check at `yourdomain.com/owa/#path=/options/popandimap`. If you can use IMAP natively, use it.
## DavMail
The solution to my dilemma was [Davmail](http://davmail.sourceforge.net/). This works as a middle~~man~~ (person) between the Exchange server and any standards compliant email client, in my case Mutt. Davmail will translate IMAP and SMTP requests to the Exchange equivalents, as well as LDAP for contacts. The result: you can use whichever email client you like to manage your cooperate emails.
## Configuring DavMail
The [setup help](http://davmail.sourceforge.net/linuxsetup.html) for DavMail is good, so I am not going to try to reinvent the wheel. I suggest you read the documentation.
If you find it easier to configure the server using a GUI, you can. Run `davmail` and fill in the boxes. Nothing groundbreaking here.
If you would like to run Davmail without a GUI in the future, simply change the `davmail.server` property from `false` to `true` in the configuration file (by default this is in your home directory).
```bash
sed -i '/davmail\.server=/s/false/true/' .davmail.properties
```
Now, you can start the server with
```bash
nohup davmail davmail.properties &
```
## Configuring Mutt
You can now connect to the locally running Davmail server as though it was an IMAP / SMTP server. Unless you have configured it differently, you will need to connect using port 1143 for IMAP and 1025 for SMTP.
Your credentials will be you Active Directory username and password and, with that, you should be able to send and receive emails using the exchange server.
```muttrc
set folder = "imap://127.0.0.1:1143/"
set imap_user = "domain/user.name"
set imap_pass = "password"
set spoolfile = +INBOX
mailboxes = +INBOX
set realname = 'Your Name'
set from = 'your-email@company.com
set use_from = yes
set smtp_url="smtp://$imap_user:$imap_pass@127.0.0.1:1025"
set ssl_force_tls = no
set ssl_starttls = no
```
Note here I have disabled `tls` authentication. This is for the communication between the mail client and the local server, so the information never leaves the computer.
Also, you might prefer not to put your password in a configuration file in clear text. You can run shell commands to populate variables so, in my case, I use the command line password manager [Pass](https://www.passwordstore.org/).
This allows me to change the `imap_pass` line to
```
set imap_pass = `pass show domainCreds | head -n 1`
```
## Adding contacts
One potential solution is to use [this perl script](https://github.com/namato/dotfiles/blob/e7ce282c8883dd1971356a0ea53c75b47105c8fa/scripts/ldap.pl). After setting Mutt's `query_command`, it will query the LDAP server to search for contacts when typing in the recipient fields.
It works but, in my opinion, has 2 shortcomings.
Firstly, it relies on an internet connection, meaning it is not possible to compose an email offline to send it when you get online. Admittedly, it is rare that I will be doing much with emails offline, but I like to have the option.
Secondly, and more importantly for me, the lookup is slow, particularly if you have to connect through a slow VPN.
### Local contacts
Storing contacts locally solves solves both problems, with the cost of using up disk space.
I created a contacts folder and ran the following in bash.
```bash
for i in {a..z}; do
ldapsearch -H 'ldap://localhost:1389/' -D 'DOMAIN\USERNAME' -w 'PASSWORD' -b ou=people "mail=$i*" > "$i.people"
done
```
Change the credentials as needed and you will end up with a file for each letter of the alphabet. I did this because the Exchange server in question wouldn't return more than 100 results at a time. Making a request for each letter meant I didn't have to work out how to deal with paging with Davmail.
To use this in Mutt, I created a script called lookup that takes all the contacts and puts them in the form `email<tab>Name<tab>title`.
```bash
#!/usr/bin/env bash
cat $HOME/Contacts/*.people | awk -v RS="\n\n" -v ORS="\n" '{gsub("\n","§",$0); print $0}' | while read line; do
echo "$line" | tr '§' '\n' | egrep '^(cn|mail|title):' | cut -d':' -f2- | tr '\n' '\t'
done
```
Then in my Mutt configuration, I have the line:
```muttrc
set query_command = "/home/jonathan/Contacts/lookup | grep '%s'"
```
This means I can start typing a name or email address, press `ctrl`+`t`, and you can select a contact.
## Contact lookup in VIM
If I am writing an email to more than one person, I find it much easier to add the recipients in vim using FZF. To make this happen, I pair the [fzf.vim](https://github.com/junegunn/fzf.vim) plugin with the following snippet in my vimrc file:
```vim
function! s:make_email_list(lines)
let l:emails = []
"return type( a:lines )
for email in a:lines
let l:address = substitute(split( email, "\t" )[0], " ","","" )
let l:name = split( email, "\t" )[1]
let l:emails = add( l:emails, l:name . " <" . l:address . ">" )
endfor
return join(l:emails, ', ')
endfunction
inoremap <expr> <c-c> fzf#vim#complete({
\ 'source': '$HOME/Contacts/lookup',
\ 'reducer': function('<sid>make_email_list'),
\ 'options': '--multi',
\ 'down': '30%' })
```
This uses the same lookup script as before, but this time it is passed to FZF. I can fuzzy search for contacts by pressing `ctrl`+`c`.
This is only useful if you have `edit_headers` set in your `.muttrc` file which allows you to set and modify the email headers in your editor.