Jason's Blog

A stochastic thought repository

Using Gnome Keyring With Msmtp, Offlineimap, and Imapfilter via Cron

| Comments

Update Jan 28th, 2012: Simplified cron portion.
Update Jan 27th, 2011: Added portion relavent to cron. It’s down at the bottom of the page.

In my previous post, I walked through setting up using mutt, msmtp, offlineimap, imapfilter, and archivemail to work together. As I wrote the post, I was reminded of how bothered I felt about having passwords for my email accounts in my configuration files. For a single user computer, this isn’t a huge problem, but I would still prefer keep my passwords out of plain text.

Some searching online lead me to decide to use some pre-existing integration done using gnome keyring, which lets your store passwords in an encrypted form.

A gnome-keyring patch for msmtp has already been integrated into the msmtp-gnome package in the Ubuntu repositories, and a nice script to add the appropriate data to the keyring exists. Another great post I found explains how to integrate offlineimap with gnome-keyring with a python helper script. It defines a couple functions that can pull the username and password directly within the configuration file. I’ve updated my own configuration files and tutorial in the previous post.

I didn’t find any examples of using imapfilter with gnome-keyring, but I was reminded after seeing the example extended settings file that since the configuration files are actually Lua scripts, we can use a slightly modified version of the python helper script used with offlineimap, and then simply pipe the input into the settings file to clean up.

imapfilter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/python
"""
File: imapfilter.py

Used to grab IMAP password information from
Gnome-Keyring.

Usage:
   ./imapfilter.py SERVER_NAME INFO

   where INFO is either "user" or "password", depending
   on the information you want.
"""

import sys
import gtk
import gnomekeyring as gkey

class Keyring(object):
    def __init__(self, name, server, protocol):
        self._name = name
        self._server = server
        self._protocol = protocol
        self._keyring = gkey.get_default_keyring_sync()

    def has_credentials(self):
        try:
            attrs = {"server": self._server, "protocol": self._protocol}
            items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
            return len(items) > 0
        except gkey.DeniedError:
            return False

    def get_credentials(self):
        attrs = {"server": self._server, "protocol": self._protocol}
        items = gkey.find_items_sync(gkey.ITEM_NETWORK_PASSWORD, attrs)
        return (items[0].attributes["user"], items[0].secret)

    def set_credentials(self, (user, pw)):
        attrs = {
                "user": user,
                "server": self._server,
                "protocol": self._protocol,
            }
        gkey.item_create_sync(gkey.get_default_keyring_sync(),
                gkey.ITEM_NETWORK_PASSWORD, self._name, attrs, pw, True)

def main(server, info):
    keyring = Keyring("offlineimap " + server, server, "imap")
    (username, password) = keyring.get_credentials()

    if info == "user":
        print(username)
    elif info == "password":
        print(password)
    else: # neither user nor pass
        sys.exit(-2)

if __name__ == '__main__':
    server = sys.argv[1]
    info = sys.argv[2]
    main(server, info)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-------------------------------------
-- Partial Imapfilter configuration
-- example.lua
-------------------------------------

-- Function strips trailing newlines
-- piped back from imapfilter.py
function trim(s)
    return (s:gsub("^%s*(.-)%s*$", "%1"))
end

-- extract username and password from gnome-keyring
status, myuser = pipe_from('/path/to/imapfilter.py mail.example.com user')
myuser = trim(myuser)

status, mypass = pipe_from('/path/to/imapfilter.py mail.example.com password')
mypass = trim(mypass)

ACCOUNT = IMAP {
        server = 'mail.example.com',
        username = myuser,
        password = mypass,
}

Finally, the trick to allowing cron to access the gnome-keyring is found in supplying it with the right environmental variable (notably, DBUS_SESSION_BUS_ADDRESS) so that offlineimap can talk with your already authenticated session of gnome-keyring. My original script to do this was really kludgey, but I found a simpler version of the script from an individual who has a very similar setup.

Take the export_x_info.sh script below, and make it run on startup. Note that is must start after DBus.

export_x_info.sh
1
2
3
4
5
6
7
#!/bin/bash
# file: export_x_info.sh
# Export the dbus session address on startup so it can be used by cron
touch $HOME/.Xdbus
chmod 600 $HOME/.Xdbus
env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.Xdbus
echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.Xdbus

If the script is called correctly, you will see a file ~/.Xdbus created, that looks like the following:

1
2
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-some-long-complicated-name
export DBUS_SESSION_BUS_ADDRESS

Then, you can use cron to run the following:

pullmail.sh
1
2
3
#!/bin/bash
# file: pullmail.sh
source $HOME/.Xdbus; /usr/bin/offlineimap

Congradulations! You now have gnome-keyring managing your passwords for you, and your mail is being fetched automatically.

Comments