A Locally Running Dovecot in Guix — GNUcode.me

A Locally Running Dovecot in Guix

by Joshua Branson — June 08, 2021

So, I have been wanting to set up a locally running dovecot server for a LONG time now. Essentially I have an email account at dismail.de, and Emacs' Gnus is pretty slow at searching for my emails. I could switch to using mu4e or notmuch, which ARE BLAZINGLY fast at searching your emails, BUT after listening to John Wiegley, who is one of the current Emacs maintainers, talk about how Emacs' Gnus mode is so cool...I've been using Gnus ever since. Essentially Gnus is a newsreader. It is a way to handle lots news that is similar to reddit. In Gnus, after you've read a message, you do not see it again by default. This is handy, because since you are getting so much email, it's useful to only see messages that you have not read.

Emacs's Gnus is actually the best way I've seen at handling LOTS of email, particularly mailing lists. For example, I am currently subscribed to guix-devel, help-guix, and bug-hurd. With Gnus, I can open up these email folders and I only see messages that I have not read, AND the emails are organized by threads NOT date:

Image

With my cursor on the top of the thread, pressing C-k, will kill the entire thread. So when I open up this folder again, I will not see that thread. Let's suppose that I've read all of the messages in that thread "Re: website: A little help running the website locally". So that now Gnus looks like this when I open it up:

Image

Pressing Shift-A-Shift-T, will pull up the entire thread, so that I can re-read the whole conversation:

Image

Anyway, the main problem that I have had with Gnus (for years...I should have fixed this a long time ago), is that it is REALLY slow and pretty much not responsive at searching for my email. I could try to search for my email with Gnus, but it would typically fail. I guess that something with dismail's servers are wonky, because I did not have this problem when I had a paid fastmail account.

So, one solution to continue using Gnus, but have decent searching is to have a locally running dovecot server that will serve my emails. I'll also be querying that local server instead of the remote one. Sounds plausible. Here's what you need to do:

First you need to fetch your remote email and put it in a local maildir. I prefer mbsync, because it is what all the cool kids are doing.

Here is my ~/.mbsyncrc

IMAPAccount dismail
# Address to connect to
Host imap.dismail.de
User jbranso@dismail.de
Pass VERYSECRETPASSWORD
# To store the password in an encrypted file use PassCmd instead of Pass
# PassCmd "gpg2 -q --for-your-eyes-only --no-tty -d ~/.mailpass.gpg"
#
# Use SSL
SSLType IMAPS
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore dismail-remote
Account dismail

MaildirStore dismail-local
Subfolders Verbatim
# The trailing "/" is important
Path ~/.mail/dismail.de/
Inbox ~/.mail/dismail.de/Inbox

Channel dismail
Master :dismail-remote:
Slave :dismail-local:
# show all folders
Patterns *
# Automatically create missing mailboxes, both locally and on the server
Create Both
# Save the synchronization state files in the relevant directory
SyncState *

mbsync -a running in a cron job, syncs up my email. The config in guix for that looks like so:

(define mbsync-every-5-minutes
  ;; Collect garbage 5 minutes after midnight every day.
  ;; The job's action is a shell command.
  #~(job "*/5 0 * * *"            ;Vixie cron syntax
         "mbsync -Va"
         #:user "joshua"))

...
(operating-system
...
(services
    (append
        (list
            (service mcron-service-type
                (mcron-configuration
                     (jobs (list mbsync-every-5-minutes)))))
     %desktop-services)))

Now all we need is the configuration for a locally running dovecot server, which looks like so:

(dovecot-service #:config
                     (dovecot-configuration
                      (mail-location "maildir:~/.mail/dismail.de:LAYOUT=fs")
                      (listen '("127.0.0.1"))
                      ;; I do not need ssl support in a locally running dovecot.  :)
                      (ssl? "no")
                      (protocols
                       (list (protocol-configuration
                              (name "imap")
                              (mail-max-userip-connections 1))))
                      (services (list
                                 (service-configuration
                                  (kind "imap")
                                  (client-limit 1)))))

The bit that really got me confused for a while was that I needed LAYOUT=fs in the mail-location line. Essentially, isync creates a maildir in a slightly different format than what dovecot expects. Adding in the "LAYOUT=fs" fixes this.

The last bit is we have to tell Emacs how to connect to the server:

(setq
 user-mail-address "myemailaccount@dismail.de"
 user-full-name "Joshua Branson")

(setq gnus-secondary-select-methods
     '((nnimap "localDismail"
               (nnimap-address "localhost")
               (nnimap-stream network)
               (nnimap-server-port 143)
               )))

Pretty cool stuff? Right!?