409 lines
13 KiB
Markdown
409 lines
13 KiB
Markdown
|
+++
|
||
|
title = "Email Setup with isync, notmuch, afew, msmtp and Emacs"
|
||
|
author = ["Elia el Lazkani"]
|
||
|
date = 2020-12-02T21:00:00+01:00
|
||
|
lastmod = 2021-06-28T00:01:02+02:00
|
||
|
tags = ["email", "isync", "notmuch", "afew", "msmtp", "emacs"]
|
||
|
categories = ["misc"]
|
||
|
draft = false
|
||
|
+++
|
||
|
|
||
|
I was asked recently about how I have my email client setup. As I naturally do, I replied with something along the lines of the following.
|
||
|
|
||
|
> I use isync, notmuch, afew and msmtp with emacs as an interface, let me get you a link on how I did my setup from my blog.
|
||
|
|
||
|
To my surprise, I never wrote about the topic. I guess this is as better time as any to do so.
|
||
|
|
||
|
Let's dig in.
|
||
|
|
||
|
<!--more-->
|
||
|
|
||
|
|
||
|
## Bird's-eye View {#bird-s-eye-view}
|
||
|
|
||
|
Looking at the big list of tools mentioned in the title, I _could_ understand how one could get intimidated but I **assure** you these are very basic, yet very powerful, tools.
|
||
|
|
||
|
First task is to divide and conquer, as usual. We start by the first piece of the puzzle, understand email.
|
||
|
|
||
|
In a very simplified way of thinking of email is that each email is simply a file. This file has all the information needed as to who sent it to whom, from which server, etc...
|
||
|
The bottom line is that it's simply a file in a folder somewhere on a server. Even though this might not be the case on the server, in this setup it will most certainly be the case locally on your filesystem. Thinking about it in terms of files in directories also makes sense because it will most likely be synchronized back with the server that way as well.
|
||
|
|
||
|
Now you might ask, what tool would offer us such a way to synchronize emails and my answer would be... Very many, of course... come on this is _Linux_ and _Open Source_ ! Don't ask silly questions... But to what's relevant to my setup it's _isync_.
|
||
|
|
||
|
Now that I have the emails locally on my filesystem, I need a way to interact with them. Some prefer to work with directories, I prefer to work with tags instead. That's where _notmuch_ comes in. You can think of it as an email tagging and querying system. To make my life simpler, I utilize _afew_ to handle a few basic email tasks to save me from writing a lot of _notmuch_ rules.
|
||
|
|
||
|
I already make use of _emacs_ extensively in my day to day life and having a _notmuch_ interface in _emacs_ is great. I can use _emacs_ to view, tag, search and send email.
|
||
|
|
||
|
Oh wait, right... I wouldn't be able to send email without _msmtp_.
|
||
|
|
||
|
|
||
|
## isync {#isync}
|
||
|
|
||
|
[isync](https://isync.sourceforge.io/) is defined as
|
||
|
|
||
|
> a command line application which synchronizes mailboxes.
|
||
|
|
||
|
While isync currently supports **Maildir** and **IMAP4** mailboxes, it has the very logical command of `mbsync`. Of course !
|
||
|
|
||
|
Now, _isync_ is very well documented in the `man` pages.
|
||
|
|
||
|
```bash
|
||
|
man mbsync
|
||
|
```
|
||
|
|
||
|
Everything you need is there, have fun reading.
|
||
|
|
||
|
While you read the `man` pages to figure out what you want, I already did that and here's what I want in my `~/.mbsyncrc`.
|
||
|
|
||
|
```conf
|
||
|
##########################
|
||
|
# Personal Configuration #
|
||
|
##########################
|
||
|
|
||
|
# Name Account
|
||
|
IMAPAccount Personal
|
||
|
Host email.hostname.com
|
||
|
User personal@email.hostname.com
|
||
|
Pass "yourPassword"
|
||
|
# One can use a command which returns the password
|
||
|
# Such as a password manager or a bash script
|
||
|
#PassCmd sh script/path
|
||
|
SSLType IMAPS
|
||
|
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||
|
|
||
|
IMAPStore personal-remote
|
||
|
Account Personal
|
||
|
|
||
|
MaildirStore personal-local
|
||
|
Subfolders Verbatim
|
||
|
Path ~/.mail/
|
||
|
Inbox ~/.mail/Inbox
|
||
|
|
||
|
Channel sync-personal-inbox
|
||
|
Master :personal-remote:"Inbox"
|
||
|
Slave :personal-local:Inbox
|
||
|
Create Slave
|
||
|
SyncState *
|
||
|
CopyArrivalDate yes
|
||
|
|
||
|
Channel sync-personal-archive
|
||
|
Master :personal-remote:"Archive"
|
||
|
Slave :personal-local:Archive
|
||
|
Create Slave
|
||
|
SyncState *
|
||
|
CopyArrivalDate yes
|
||
|
|
||
|
Channel sync-personal-sent
|
||
|
Master :personal-remote:"Sent"
|
||
|
Slave :personal-local:Sent
|
||
|
Create Slave
|
||
|
SyncState *
|
||
|
CopyArrivalDate yes
|
||
|
|
||
|
Channel sync-personal-trash
|
||
|
Master :personal-remote:"Junk"
|
||
|
Slave :personal-local:Trash
|
||
|
Create Slave
|
||
|
SyncState *
|
||
|
CopyArrivalDate yes
|
||
|
|
||
|
# Get all the channels together into a group.
|
||
|
Group Personal
|
||
|
Channel sync-personal-inbox
|
||
|
Channel sync-personal-archive
|
||
|
Channel sync-personal-sent
|
||
|
Channel sync-personal-trash
|
||
|
```
|
||
|
|
||
|
The following will synchronize both ways the following folders:
|
||
|
|
||
|
- Remote "Inbox" with local "Inbox"
|
||
|
- Remote "Archive" with local "Archive"
|
||
|
- Remote "Sent" with local "Sent"
|
||
|
- Remote "Junk" with local "Trash"
|
||
|
|
||
|
Those are the only directories I care about.
|
||
|
|
||
|
With the configuration in place, we can try to sync the emails.
|
||
|
|
||
|
```bash
|
||
|
mbsync -C -a -V
|
||
|
```
|
||
|
|
||
|
|
||
|
## notmuch {#notmuch}
|
||
|
|
||
|
You can read more about [notmuch](https://notmuchmail.org/) on their webpage. Their explanation is interesting to say the least.
|
||
|
|
||
|
What _notmuch_ does, is create a database where it saves all the tags and relevant information for all the emails. This makes it extremely fast to query and do different operations on large numbers of emails.
|
||
|
|
||
|
I use _notmuch_ mostly indirectly through _emacs_, so my configuration is very simple. All I want from _notmuch_ is to tag all **new** emails with the `new` tag.
|
||
|
|
||
|
```conf
|
||
|
# .notmuch-config - Configuration file for the notmuch mail system
|
||
|
#
|
||
|
# For more information about notmuch, see https://notmuchmail.org
|
||
|
|
||
|
# Database configuration
|
||
|
#
|
||
|
# The only value supported here is 'path' which should be the top-level
|
||
|
# directory where your mail currently exists and to where mail will be
|
||
|
# delivered in the future. Files should be individual email messages.
|
||
|
# Notmuch will store its database within a sub-directory of the path
|
||
|
# configured here named ".notmuch".
|
||
|
#
|
||
|
[database]
|
||
|
path=/home/user/.mail/
|
||
|
|
||
|
# User configuration
|
||
|
#
|
||
|
# Here is where you can let notmuch know how you would like to be
|
||
|
# addressed. Valid settings are
|
||
|
#
|
||
|
# name Your full name.
|
||
|
# primary_email Your primary email address.
|
||
|
# other_email A list (separated by ';') of other email addresses
|
||
|
# at which you receive email.
|
||
|
#
|
||
|
# Notmuch will use the various email addresses configured here when
|
||
|
# formatting replies. It will avoid including your own addresses in the
|
||
|
# recipient list of replies, and will set the From address based on the
|
||
|
# address to which the original email was addressed.
|
||
|
#
|
||
|
[user]
|
||
|
name=My Name
|
||
|
primary_email=user@email.com
|
||
|
# other_email=email1@example.com;email2@example.com;
|
||
|
|
||
|
# Configuration for "notmuch new"
|
||
|
#
|
||
|
# The following options are supported here:
|
||
|
#
|
||
|
# tags A list (separated by ';') of the tags that will be
|
||
|
# added to all messages incorporated by "notmuch new".
|
||
|
#
|
||
|
# ignore A list (separated by ';') of file and directory names
|
||
|
# that will not be searched for messages by "notmuch new".
|
||
|
#
|
||
|
# NOTE: *Every* file/directory that goes by one of those
|
||
|
# names will be ignored, independent of its depth/location
|
||
|
# in the mail store.
|
||
|
#
|
||
|
[new]
|
||
|
tags=new;
|
||
|
#tags=unread;inbox;
|
||
|
ignore=
|
||
|
|
||
|
# Search configuration
|
||
|
#
|
||
|
# The following option is supported here:
|
||
|
#
|
||
|
# exclude_tags
|
||
|
# A ;-separated list of tags that will be excluded from
|
||
|
# search results by default. Using an excluded tag in a
|
||
|
# query will override that exclusion.
|
||
|
#
|
||
|
[search]
|
||
|
exclude_tags=deleted;spam;
|
||
|
|
||
|
# Maildir compatibility configuration
|
||
|
#
|
||
|
# The following option is supported here:
|
||
|
#
|
||
|
# synchronize_flags Valid values are true and false.
|
||
|
#
|
||
|
# If true, then the following maildir flags (in message filenames)
|
||
|
# will be synchronized with the corresponding notmuch tags:
|
||
|
#
|
||
|
# Flag Tag
|
||
|
# ---- -------
|
||
|
# D draft
|
||
|
# F flagged
|
||
|
# P passed
|
||
|
# R replied
|
||
|
# S unread (added when 'S' flag is not present)
|
||
|
#
|
||
|
# The "notmuch new" command will notice flag changes in filenames
|
||
|
# and update tags, while the "notmuch tag" and "notmuch restore"
|
||
|
# commands will notice tag changes and update flags in filenames
|
||
|
#
|
||
|
[maildir]
|
||
|
synchronize_flags=true
|
||
|
```
|
||
|
|
||
|
Now that _notmuch_ is configured the way I want it to, I use it as follows.
|
||
|
|
||
|
```bash
|
||
|
notmuch new
|
||
|
```
|
||
|
|
||
|
Yup, that simple.
|
||
|
|
||
|
This will tag all new emails with the `new` tag.
|
||
|
|
||
|
|
||
|
## afew {#afew}
|
||
|
|
||
|
Once all the new emails have been properly tagged with the `new` tag by _notmuch_, _afew_ comes in.
|
||
|
|
||
|
[_afew_](https://github.com/afewmail/afew) is defined as an initial tagging script for _notmuch_. The reason of using it will become evident very soon but let me quote some of what their Github page says.
|
||
|
|
||
|
> It can do basic thing such as adding tags based on email headers or maildir folders, handling killed threads and spam.
|
||
|
>
|
||
|
> In move mode, afew will move mails between maildir folders according to configurable rules that can contain arbitrary notmuch queries to match against any searchable attributes.
|
||
|
|
||
|
This is where the bulk of the configuration is, in all honesty. At this stage, I had to make a decision of how would I like to manage my emails ?
|
||
|
|
||
|
I think it should be simple if I save them as folders on the server as it doesn't support tags. I can derive the basic tags from the folders and keep a backup of my database for all the rest of the tags.
|
||
|
|
||
|
My configuration looks similar to the following.
|
||
|
|
||
|
```conf
|
||
|
# ~/.config/afew/config
|
||
|
[global]
|
||
|
|
||
|
[SpamFilter]
|
||
|
[KillThreadsFilter]
|
||
|
[ListMailsFilter]
|
||
|
[SentMailsFilter]
|
||
|
[ArchiveSentMailsFilter]
|
||
|
sent_tag = sent
|
||
|
|
||
|
[DMARCReportInspectionFilter]
|
||
|
|
||
|
[Filter.0]
|
||
|
message = Tagging Personal Emails
|
||
|
query = 'folder:.mail/'
|
||
|
tags = +personal
|
||
|
|
||
|
[FolderNameFilter.0]
|
||
|
folder_explicit_list = .mail/Inbox .mail/Archive .mail/Drafts .mail/Sent .mail/Trash
|
||
|
folder_transforms = .mail/Inbox:personal .mail/Archive:personal .mail/Drafts:personal .mail/Sent:personal .mail/Trash:personal
|
||
|
folder_lowercases = true
|
||
|
|
||
|
[FolderNameFilter.1]
|
||
|
folder_explicit_list = .mail/Archive
|
||
|
folder_transforms = .mail/Archive:archive
|
||
|
folder_lowercases = true
|
||
|
|
||
|
[FolderNameFilter.2]
|
||
|
folder_explicit_list = .mail/Sent
|
||
|
folder_transforms = .mail/Sent:sent
|
||
|
folder_lowercases = true
|
||
|
|
||
|
[FolderNameFilter.3]
|
||
|
folder_explicit_list = .mail/Trash
|
||
|
folder_transforms = .mail/Trash:deleted
|
||
|
folder_lowercases = true
|
||
|
|
||
|
[Filter.1]
|
||
|
message = Untagged 'inbox' from 'archive'
|
||
|
query = 'tag:archive AND tag:inbox'
|
||
|
tags = -inbox
|
||
|
|
||
|
[MailMover]
|
||
|
folders = .mail/Inbox
|
||
|
rename = True
|
||
|
max_age = 7
|
||
|
.mail/Inbox = 'tag:deleted':.mail/Trash 'tag:archive':.mail/Archive
|
||
|
|
||
|
# what's still new goes into the inbox
|
||
|
[InboxFilter]
|
||
|
```
|
||
|
|
||
|
Basically, I make sure that all the emails, in their folders, are tagged properly. I make sure the emails which need to be moved are moved to their designated folders. The rest is simply the inbox.
|
||
|
|
||
|
<div class="admonition note">
|
||
|
<p class="admonition-title">Note</p>
|
||
|
|
||
|
The **read** / **unread** tag is automatically handled between _notmuch_ and _isync_. It's seemlessly synchronized between the tools.
|
||
|
|
||
|
</div>
|
||
|
|
||
|
With the configuration in place, I run _afew_.
|
||
|
|
||
|
```bash
|
||
|
afew -v -t --new
|
||
|
```
|
||
|
|
||
|
For moving the emails, I use _afew_ as well but I apply it on all emails and not just the ones tagged with `new`.
|
||
|
|
||
|
```bash
|
||
|
afew -v -m --all
|
||
|
```
|
||
|
|
||
|
|
||
|
## msmtp {#msmtp}
|
||
|
|
||
|
[_msmtp_](https://marlam.de/msmtp/) is an SMTP client. It sends email.
|
||
|
|
||
|
The configuration is very simple.
|
||
|
|
||
|
```conf
|
||
|
# Set default values for all following accounts.
|
||
|
defaults
|
||
|
auth on
|
||
|
tls on
|
||
|
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||
|
logfile ~/.msmtp.log
|
||
|
|
||
|
# Mail
|
||
|
account personal
|
||
|
host email.hostname.com
|
||
|
port 587
|
||
|
from personal@email.hostname.com
|
||
|
user personal@email.hostname.com
|
||
|
password yourPassword
|
||
|
# One can use a command which returns the password
|
||
|
# Such as a password manager or a bash script
|
||
|
# passwordeval sh script/path
|
||
|
|
||
|
# Set a default account
|
||
|
account default : personal
|
||
|
```
|
||
|
|
||
|
|
||
|
## Emacs {#emacs}
|
||
|
|
||
|
I use [_Doom_](https://github.com/hlissner/doom-emacs) as a configuration framework for _Emacs_. _notmuch_ comes as a modules which I enabled, but you might want to check the _notmuch_'s _Emacs_ [Documentation](https://notmuchmail.org/notmuch-emacs/) page for help with installation and configuration.
|
||
|
|
||
|
I wanted to configure the _notmuch_ interface a bit to show me what I'm usually interested in.
|
||
|
|
||
|
```elisp
|
||
|
(setq +notmuch-sync-backend 'mbsync)
|
||
|
(setq notmuch-saved-searches '((:name "Unread"
|
||
|
:query "tag:inbox and tag:unread"
|
||
|
:count-query "tag:inbox and tag:unread"
|
||
|
:sort-order newest-first)
|
||
|
(:name "Inbox"
|
||
|
:query "tag:inbox"
|
||
|
:count-query "tag:inbox"
|
||
|
:sort-order newest-first)
|
||
|
(:name "Archive"
|
||
|
:query "tag:archive"
|
||
|
:count-query "tag:archive"
|
||
|
:sort-order newest-first)
|
||
|
(:name "Sent"
|
||
|
:query "tag:sent or tag:replied"
|
||
|
:count-query "tag:sent or tag:replied"
|
||
|
:sort-order newest-first)
|
||
|
(:name "Trash"
|
||
|
:query "tag:deleted"
|
||
|
:count-query "tag:deleted"
|
||
|
:sort-order newest-first))
|
||
|
)
|
||
|
```
|
||
|
|
||
|
Now, all I have to do is simply open the `notmuch` interface in _Emacs_.
|
||
|
|
||
|
|
||
|
## Conclusion {#conclusion}
|
||
|
|
||
|
To put everything together, I wrote a _bash script_ with the commands provided above in series. This script can be called by a **cron** or _even_ **manually** to synchronize emails.
|
||
|
|
||
|
From the _Emacs_ interface I can do pretty much everything I need to do.
|
||
|
|
||
|
Future improvements I have to think about is the best way to do email notifications. There are a lot of different ways I can approach this. I can use notmuch to query for what I want. I could maybe even try querying the information out of the [Xapian](https://xapian.org/) database. But that's food for thought.
|
||
|
|
||
|
I want email to be simple and this makes it simple for me. How are you making email simple for you ?
|