=> 🏡 Home | Back to notes

Email client (aerc)

Last updated on 20 October 2024

This note documents my current setup for email.

It includes:

=> 1

=> 2

=> 3

=> 4

=> 5

Pre-start: Handling local credentials

To securely store credentials for syncing, I use pass [6]. I recommend installing this for your system and setting it up with a GPG key.

=> 6

One issue I had whilst using pass was that it would frequently timeout, and the GPG dialog would fail to work or would interfere with the running mail client. As such, I extended the TTLs of the agent by adding these lines to my ~/.gnupg/gpg-agent.conf:

default-cache-ttl 34560000
max-cache-ttl 34560000

Once set-up, add the needed credentials for your various mail accounts to pass. For some services (e.g. Fastmail and Google) an app-specific password should be generated for this. E.g.:

pass insert Email/fastmail

Step 1: Managing contacts (vdirsyncer and khard)

I use vdirsyncer to sync contacts to a local directory. This allows khard to read and search contacts locally and surface them to aerc.

To install both of these, use Homebrew on a Mac: brew install vdirsyncer khard.

vdirsyncer setup

Once installed, create a new configuration file for vdirsyncer at ~/.config/vdirsyncer/config:

[general]
status_path = "~/.config/vdirsyncer/status/"

# Personal Contacts
[pair personal_addressbook]
a = "personal_addressbook_local"
b = "personal_addressbook_remote"
collections = ["from a", "from b"]
metadata = ["displayname"]

[storage personal_addressbook_local]
type = "filesystem"
path = "~/.config/khard/personal/"
fileext = ".vcf"

[storage personal_addressbook_remote]
type = "carddav"
auth = "basic"
url = "https://carddav.fastmail.com/dav/addressbooks/user/USERNAME@fastmail.com/Default"
username = "USERNAME@fastmail.com"
password.fetch = ["command", "pass", "Email/fastmail"]

This syncs my Fastmail (i.e. personal, non-work) contacts to ~/.config/khard/personal/. The final three blocks of the config file (the pair and two storage blocks) can be repeated for each account you wish to sync contacts for.

I use it with both Fastmail and Google, and it works well. For Google contacts, the url I use is: https://www.googleapis.com/carddav/v1/principals/USERNAME@DOMAIN.COM/lists.

khard setup

For khard, create a new config file at ~/.config/khard/khard.conf with contents along the lines of the example on the website [7]. Specifically, for the [addressbooks] section, I use the ~/.config dir primarily out of laziness, as this auto-syncs with my dotfiles.:

=> 7

[addressbooks]
[[personal]]
path = ~/.config/khard/personal/Default
[[work]]
path = ~/.config/khard/work/default
...

In the latter example, the default is lowercase as this is how Google names its default address books.

Testing contacts

To test this is all working, run a sync and then try searching for a contact:

vdirsyncer sync
khard list john

If you have a contact named John, you should see them listed.

Step 2: Syncing email (mbsync)

Although aerc can directly connect to IMAP servers, I prefer to have mail synced locally. This allows me to manage it using local tools (such as notmuch) but it also enables me to back things up more easily.

I use mbsync for syncing IMAP accounts to a local Maildir directory. It is part of a package called isync and can be installed with Homebrew: brew install isync.

To set it up, create a file at ~/.mbsyncrc. I find the mbscync config file fiddly and unintuitive, but have set my personal Fastmail IMAP account up as follows. These blocks can be repeated for your other IMAP accounts (just ensure to use unique names for the accounts, stores, and channels).

IMAPAccount personal
Host imap.fastmail.com
Port 993
User USERNAME@fastmail.com
PassCmd "pass Email/fastmail"
TLSType IMAPS
AuthMechs LOGIN

IMAPStore personal-remote
Account personal

MaildirStore personal-local
Path ~/Syncthing/Maildir/personal/
Inbox ~/Syncthing/Maildir/personal/INBOX
SubFolders Verbatim

Channel personal
Far :personal-remote:
Near :personal-local:
Patterns *
Expunge None
CopyArrivalDate yes
Sync All
SyncState *
Create Both

You may notice that I reference a Maildir in my Syncthing directory. This is to ensure my mail is backed-up to other machines.

To test this is working, run mbsync -a and check the Maildir directory for your account. You should see your mail syncing.

Step 3: Organising email (notmuch)

To install it, use Homebrew (on a Mac): `brew install notmuch`.

To set it up, run `notmuch`. This will prompt for a few bits of info and setup a database at the root of your Maildir and a configuration file at `~/.notmuch-config`.

The defaults for the config are pretty good, but for reference I add mine below:

[database]

Path to your Maildir

path=/Users/will/Syncthing/Maildir

[user]

I don't think this affects much unless you use notmuch for sending mail too

primary_email=USER@DOMAIN.COM

other_email=email1;email2;

[new]

default tags for new messages

tags=unread;inbox;

ignore=

[search]

how to manage searches (i.e. ignore deleted/spam mail)

exclude_tags=deleted;spam;

[maildir]

sync some notmuch tags with maildir flags (e.g. read/unread)

synchronize_flags=true

I also ensure to add the following to `~/Syncthing/.stignore` to prevent Syncthing from syncing the `notmuch` database (which is huge, but can be rebuilt):

.notmuch/xapian

notmuch hooks [8] can be set up to run commands alongside `notmuch`. For example, to add/remove tags before or after mail is processed. 
=> https://notmuchmail.org/doc/latest/man5/notmuch-hooks.html 8

My approach is simple, and I just have a single `post-new` hook in `~/Syncthing/Maildir/.notmuch/hooks/post-new` to make my mail management a little easier:

!/bin/bash

Reference Maildir folders for tagging

notmuch tag +personal "folder:/personal/"

notmuch tag +account2 "folder:/account2/"

Handle sent and spam mail by IMAP folders

e.g. if Gmail marks it as spam, tag it as spam

notmuch tag +sent "folder:/Sent/" and not tag:sent

notmuch tag +spam "folder:/Spam/" and not tag:spam

Handle customer specific tags

notmuch tag +customer1 from:customer1.com

notmuch tag +customer2 from:customer2.com and tag:personal

Remove the new tag from all new emails

notmuch tag -new tag:new

(Note: after creating this file for the first time, be sure to ensure it's executable: `chmod +x ~/Syncthing/Maildir/.notmuch/hooks/post-new`)

Because our config file auto-applies the `unread` tag, we don't need to handle it here, but we could if we wanted to.

If you now run `notmuch new`, the Maildir will be processed according to the config and any hooks you've setup.

You can now try running a search to show how fast it runs:

notmuch search from:domain1.com

notmuch search tag:personal

## Step 4: Setting-up `aerc`

I now talk about installing and setting-up `aerc`, which will bring all of this together into one place.

### Installation

Although it's installable from Homebrew, the distributed binary does not include `notmuch` support. As such, I compile `aerc` from source using the headers installed as part of the `notmuch` installation from earlier.

First, make sure to have `go` installed (according to the website [9]).
=> https://go.dev 9

Clone the `aerc` repo and change into it:

git clone https://git.sr.ht/~rjarry/aerc

cd aerc

Set some flags so the build process knows where to find the `notmuch` headers and so the linker can find the library. In my case (and versions), this was done using:

export CPATH=/opt/homebrew/Cellar/notmuch/0.38.3/include

export LIBRARY_PATH=/opt/homebrew/Cellar/notmuch/0.38.3/lib

Now compile `aerc` with the `notmuch` tag:

gmake GOFLAGS=-tags=notmuch

### Mail sync script

To help automate some of the mail fetching and tagging tasks, I added a script (largely taken from the example on the aerc wiki [10]). This script will be invoked whenever `aerc` wants to fetch new mail (as we'll set up later):
=> https://man.sr.ht/~rjarry/aerc/integrations/notmuch.md 10

!/bin/sh

MBSYNC=$(pgrep mbsync)

NOTMUCH=$(pgrep notmuch)

if [ -n "$MBSYNC" -o -n "$NOTMUCH" ]; then

echo "Already running one instance of mbsync or notmuch. Exiting..."

exit 0

fi

Actually delete the emails tagged as deleted

notmuch search --format=text0 --output=files tag:deleted | xargs -0 --no-run-if-empty rm -v

mbsync -a

notmuch new

I save this in `~/.config/aerc/mail-sync`. As above, ensure this script is executable: `chmod +x ~/.config/aerc/mail-sync`.

### Accounts setup

The `aerc` accounts setup is highly flexible. The man page (like this Arch Wiki one) [11] is a good reference.
=> https://man.archlinux.org/man/aerc-accounts.5.en 11

Below is a sample of mine (in `~/.config/aerc/accounts.conf`), which demonstrates `notmuch` and `khard` integration:

[Combined]

source = notmuch://~/Syncthing/Maildir

query-map = ~/.config/aerc/map.conf

default = INBOX

from = Will Webberley USERNAME@DOMAIN.COM

check-mail-cmd = ~/.config/aerc/mail-sync

check-mail = 2m

check-mail-timeout = 30s

[Personal]

source = notmuch://~/Syncthing/Maildir

outgoing = smtps://USERNAME%40fastmail.com@smtp.fastmail.com:465

maildir-store = ~/Syncthing/Maildir

maildir-account-path = personal

outgoing-cred-cmd = pass Email/fastmail

check-mail-cmd = mbsync personal && notmuch new

check-mail = 2m

default = INBOX

from = Will Webberley USERNAME@DOMAIN.COM

cache-headers = true

copy-to = Sent

address-book-cmd = khard email -a personal --parsable --remove-first-line %s

[Work1]

source = notmuch://~/Syncthing/Maildir

... etc.

This setup includes a Combined account which is optional but I like it for having a single view across all my accounts. You can also see this account invoking the `mail-sync` script we created earlier.

The `khard` integration offers auto-complete suggestions as you type a name or email address into the mail composer.

The Combined account also makes use of a query map which maps "folders" onto `notmuch` queries. My `~/.config/aerc/map.conf` looks like this:

Inbox=tag:inbox

Todo=tag:todo and not tag:archived and not tag:deleted

All=not tag:archived and not tag:deleted and not tag:spam

Sent=tag:sent

Spam=tag:spam

### General `aerc` configuration

I created a `~/.config/aerc/aerc.conf` file to set some general options. This file is also hugely configurable [12]. Mine is very basic by comparison:
=> https://man.archlinux.org/man/aerc-config.5.en 12

[general]

default-save-path=~/Downloads

log-file=~/.aerc.log

[ui]

styleset-name=nord

fuzzy-complete=true

icon-new=✨

icon-attachment=📎

icon-old=🕰️

icon-replied=📝

icon-flagged=🚩

icon-deleted=🗑️

[statusline]

[viewer]

alternatives=text/plain,text/html

header-layout=From,To,Cc,Bcc,Date,Subject

[compose]

header-layout=From,To,Cc,Subject

reply-to-self=false

empty-subject-warning=true

no-attachment-warning=^[^>]*attach(ed|ment)

[multipart-converters]

text/html=pandoc -f markdown -t html --standalone

[filters]

text/html=pandoc -f html -t plain

text/plain=colorize

text/calendar=calendar

message/delivery-status=colorize

message/rfc822=colorize

.headers=colorize

[openers]

[hooks]

[templates]

An interesting part of this is the filter for HTML. By default `aerc` cannot display HTML emails. This makes emails impossible to view if there is no `text/plain` alternative. In my example I use `pandoc` to convert HTML to plain text, which works OK for me. Other solutions might involve `w3m` or other tools.

The `multipart-converters` section allows for specifying how non-plain parts of the email can be generated. Once an email is written (in `text/plain`) an HTML part can then be generated by running `:multipart text/html` when in review mode.

### Running `aerc`

Run :check-mail in the Combined account to check that's working, try sending mail, check out the autocomplete of contacts via Khard, and try searching for emails.

For day-to-day use, I strongly recommend reading through the aerc wiki and man pages, and also experimenting with the setups published by other people.

=> Back to notes

Proxy Information
Original URL
gemini://wilw.capsule.town/notes/aerc.gmi
Status Code
Success (20)
Meta
text/gemini;lang=en-GB
Capsule Response Time
258.030789 milliseconds
Gemini-to-HTML Time
2.239544 milliseconds

This content has been proxied by September (ba2dc).