git clone http://ratfactor.com/repos/addrbook/addrbook.git
Created to work with the Aerc email client, but is completely useable from the command line and might also work within other email clients so long as they can launch terminal applications.
Relational databases are great and text files are great. So which did I choose for Addrbook? Both! I chose a database (SQLite) to store the address book entries as proper relation database. But I also chose to interact with the entries as text files. It turns out we can have the best of both worlds if we treat the text as the interface for the database.
Describing a text file as an “interface” probably sounds unusual. All it means in this case is that any time you interact with an address book entry, it will be in the form of a text file.
When you view an entry, you are looking at the contents of a text file that was created for you that very instant from the contents of the address book database.
If you edit an entry, you do so by editing the text file in your favorite text editor. Then Addrbook imports your changes back into the database.
If you didn’t know better, you would think the text files are the only storage used by Addrbook. You wouldn’t even know the database existed. But it does and Addrbook won’t work without it.
The text files are retained after they have been used, which means that the database and text files are always 100% in sync with each other. (The only reason this would not be true is if you’ve circumvented Addrbook’s interface, or there was an error in Addrbook, or your computer crashed while you were editing an entry.)
The “help” message that is printed when you run Addrbook with no arguments explains how editing works in the form of a list:
After using this program for a while, I am convinced that the database + text file method not only works reliably, but gives the “best of both worlds” by having plain text input and output in the Unix fashion, while retaining the full power and reliability of a proper industrial-grade database (SQLite).
To query your address book entries, you can query the database with SQL or query the text files with your favorite command line tools. Use whichever method is the most convenient or comfortable!
First, to run addrbook at all, you’ll need to install the sqlite3 gem:
gem install sqlite3
There is no installer, so you’ll need to prepare the directories for addrbook:
mkdir ~/beans/addrbook
mkdir ~/beans/addrbook/txt
Create the addrbook.db database from the make_db.sql schema file. I like to
do this interactively in the sqlite3 shell to confirm everything is correct.
Example SQLite session (silently creates the required tables):
$ sqlite3 ~/beans/addrbook/addrbook.db
SQLite version 3.50.4 2025-07-30 19:33:53
sqlite> .read addrbook-repo/make_db.sql
While you’re in there, verify the schema:
sqlite> .schema
CREATE TABLE contact (
contact_id INTEGER PRIMARY KEY,
name,
added,
notes
);
CREATE TABLE email ( contact_id INTEGER, email);
CREATE TABLE phone ( contact_id INTEGER, phone);
CREATE TABLE url ( contact_id INTEGER, url);
sqlite> .quit
Specify the path to the base directory in an environment variable like so:
ADDRBOOK_PATH=$HOME/beans/addrbook
export ADDRBOOK_PATH
Or you can hard-code your own path in the addrbook source like I did! (See the source, near the top.)
Note: You can test addrbook with a temporary path like I often did while developing, like so:
$ ADDRBOOK_PATH=/tmp/addr_test/ ./addrbook list
In summary, the address book directory should contain the following structure:
[dir]/addrbook.db - sqlite3 database, init with make_db.sql
[dir]/txt/ - empty directory, will store text files
The editor used to edit contacts is determined in the following order:
$VISUAL$EDITORA viewer is determined likewise:
$PAGERThe ‘cat’ command is hard-coded to run whatever executable is named ‘cat’ on your system.
I wrote Addrbook for use within the Aerc terminal email client.
I’ve got this in ~/.config/aerc/binds.conf:
[view]
# Address Book: av,ae,aa = "Address View, Edit, Add"
av = :term addrbook view '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter>
ae = :term addrbook edit '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter>
aa = :term addrbook add '{{(index .From 0).Address}}' '{{(index .From 0).Name}}'<Enter>
For a full explanation of these bindings, see the “Aerc binding details” section below.
When you run addrbook without any arguments, it prints a usage summary which will always be current. (I’ll try to keep it current here too, but it’s easy to forget.)
Usage: addrbook <command> [params]
Available commands:
add [email addr] [name] Create new contact entry
edit <email addr | ID> Update contact as text, import changes.
view <email addr | ID> Display contact as text with pager
cat <email addr | ID> Output contact as text (to 'cat')
reimport <contact number> Updates contact DB entry from text.
list Display list of current contacts.
autocomplete-email <fuzzy> TODO
The 'edit' command is the normal way to update a contact. It:
1. Writes the database contents of the entry to a text file.
2. Opens the text file in your editor.
3. Imports the edited contact information back to the database.
The 'reimport' command performs only Step 3 and exists mostly for
recovery if the edit process was interrupted.
The three steps listed above are the most concise explanation I’ve managed to write explaining how the edit process makes a round-trip from the database to text files and back again.
Here’s an explanation of the Aerc quickstart configuration above so you’ll be armed with the ability to modify mine or make your own shortcut bindings.
To quote man aerc:
To execute a command, press : to bring up the command
interface. Commands may also be bound to keys, see
aerc-binds(5) for details.
[...]
Dynamic arguments are expanded following aerc-templates(7)
depending on the context.
Creating new contacts in the address book from an email client will require just the email address. Optionally, it can take the contact’s name as well.
To test the value of an Aerc ‘template’ with a message selected in various Aerc
contexts (list, compose, view, etc.), you can use the built-in Aerc echo
command:
:echo {{.From}}
This was news to me until I started reading RFCs on my first attempt at this,
but an email’s “From:” header can contain more than one sender for some dang
reason. So the From property actually returns a list.
To get the first email address and name to addrbook, I’m using the following
pair of templates as parameters. You can try these out with echo:
:echo {{(index .From 0).Address}}
:echo {{(index .From 0).Name}}
To open a new terminal emulator in a “tab” in Aerc, use the term command:
:term <cmd> [<arguments>]
(You can also leave off the command and Aerc will run your shell instead.)
When the command exits, the terminal will close.
The bindings config file is broken into sections. I’ve added mine to the
[view] section, which is when you’re looking at an email, but not
composing a reply. Be careful about using a binding that starts with the
letter ‘a’ in the list context because that’s bound by default to the
“archive” action!
As you can see in my ‘aa’ and ‘ae’ key binding examples, I put quotes around the arguments as they’re passed to addrbook. Not strictly needed for the email address (which shouldn’t have spaces!), but definitely needed to pass a name with spaces like “John Smith” as a single argument.
One of the problems with storing information in a binary format (even a very open and reliable one like SQLite) is that it’s hard to track it with standard source control tools.
The mechanism for editing addrbook contact entries is writing them to plain text files. So the data is always kept in perfect sync between text and database without any additional effort! (You can trick it, of course, but that’s on you.)
Therefore, it is completely reasonable to put the txt directory
under standard textual version control to keep track of changes
to your contact data.
Version control plus a standard automated backup system (you do have a backup system, right?) should be quite good protection against mistakes and equipment failures.
This was initially inspired by Max Schillinger’s emailbook. It’s less than 150 lines of commented shell script (and nearly half are for handling the command-line interface).
I’d intended to re-implement emailbook in Ruby (so it would run on OpenBSD). After I made some good headway on my clone (and had added a ‘notes’ field), I was reading the Aerc man pages and realized there was another way to send the the current contact’s email address to the application from Aerc while leaving STDIN available for interactive use.
So at this point, Addrbook bears zero resemblance to emailbook. Nevertheless, without the inspiration, I never would have thought to make this at all. So thanks Max!
I still believe in the original mission of libre software. I honestly don’t know how I should be licensing things in 2026. If pressed, probably a GNU license.