Old notmuch emacs mail system

Table of Contents

1 Description

This page archives my system for checking mail for an old version of notmuch. I did not update notmuch for a long time so I am unsure when the setup described here broke.

Newer versions of notmuch automatically does what is described on this page. For my current mail setup, see Emacs, notmuch, offlineimap and Gmail email system.

2 News

  • 1. Feb 2014 : initial page

3 Emacs notmuch offlineimap gmail

This setup assumes you have followed the previous steps:

  • Send mail through gmail using Emacs
  • Gnubiff

3.1 Usage

My process for reading new mail is:

  • Notice Gnubiff dancing tux icon
  • Open notmuch searching for mails tagged as 'inbox' (key: C-c c n)
  • Open each mail, read them, reply and archive them as:

    • personal (key: m p)
    • uni (key: m u)
    • deleted (key: m d)

    Archiving mails moves them from the gmail inbox directory to inbox/personal, inbox/uni or [Gmail]/Trash.

    Change archiving options by changing the variable 'my-notmuch-move-options'.

  • Go back to the inbox search (key: q)
  • When there are no more new mails, exit notmuch (key: q) This automatically runs offlineimap, which updates the mail moves to gmail. This also stop Gnubiff from showing the dancing tux, as there are no longer any mail in Gmail's inbox directory.

My process for reading old mail is:

  • Open notmuch main menu (key: C-c c g)
  • Write in search string. I also have have some saved searches consisting of 'from:foo@example.org'.

My process for sending mail is:

  • Find old mail and press 'r' to reply.
  • Or make a new mail using (C-x m) (<tab> completes addresses fetched from old mails).

3.2 Initial setup

3.2.1 offlineimap

sudo apt-get install offlineimap

New file ~/.offlineimaprc:

accounts = Gmail
maxsyncaccounts = 1

[Account Gmail]
localrepository = Local
remoterepository = Remote

[Repository Local]
type = Maildir
localfolders = ~/mail
sep = .    

[Repository Remote]
type = IMAP
remotehost = imap.gmail.com
remoteuser = your_username@gmail.com
remotepass = your_gmail_password
ssl = yes
maxconnections = 1
realdelete = no

3.2.2 notmuch

Install from git:

cd ~/emacs.d
git clone git://notmuchmail.org/git/notmuch
cd notmuch
sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev
sudo make install
notmuch setup

Specify Maildir location as ~/mail.

notmuch new

I then tag mails to match my Gmail folders. I only have two tags: INBOX/personal and INBOX/uni.

notmuch tag +uni folder:inbox/uni
notmuch tag +personal folder:inbox/personal
notmuch tag +inbox folder:inbox and not folder:inbox/uni and not folder:inbox/personal
notmuch tag +spam folder:spam
notmuch tag +sent folder:sent

3.3 Continued updates

Change appropriate line in ~/.notmuch-config:


New file ~/bin/notmuch-my-new:

notmuch new

notmuch tag +sent -new folder:sent and tag:new

notmuch tag +spam -new folder:spam and tag:new

notmuch tag +inbox -new tag:new
chmod +x ~/bin/notmuch-my-new

Now change the Gnubiff "When new mail, run command" to:

offlineimap && notmuch-my-new

3.4 Emacs

Download offlineimap.el into ~/.emacs.d.

This script have been tested with notmuch version 0.11.1+229~gd50171.

Add to ~/.emacs:

(add-to-list 'load-path "~/.emacs.d")
(require 'offlineimap)
(require 'notmuch)

(setq mm-text-html-renderer 'w3m) ;; html2text causes tagging to stop working
(setq notmuch-fcc-dirs nil) ; Gmail saves sent mails by itself

(define-key notmuch-show-mode-map (kbd "RET") 'goto-address-at-point)

(global-set-key (kbd "C-c c g") 'notmuch)
(global-set-key (kbd "C-c c n") (lambda ()
                                  (notmuch-search "tag:inbox")))
(define-key notmuch-search-mode-map "q" (lambda ()
(define-key notmuch-show-mode-map "q" 
  (lambda ()
    (if (and (eq major-mode 'notmuch-search-mode)
             (< (buffer-size) 1024))

(setq notmuch-saved-searches 
      '(("inbox" . "tag:inbox")))

(defvar my-notmuch-mail-path (expand-file-name "~/mail")
  "Location of local Maildir.")

(defvar my-notmuch-move-options '(("personal" "INBOX.personal" "p")
                                  ("uni" "INBOX.uni" "u")
                                  ("trash" "[Gmail].Trash" "d"))
  "List of synced notmuch labels and Maildir folders. The format
    is '(notmuch-tag Maildir-folder key-binding). Key-binding
    is \"m x\" when viewing a message where x is the key-binding
    from the format.")

(defvar my-notmuch-remove-tags-on-move 
  (append (mapcar 'car my-notmuch-move-options)
  "Which tags to remove from messages when moving them.")

(define-key notmuch-show-mode-map (kbd "m") nil)
(require 'cl)
(dolist (opt my-notmuch-move-options)
  (lexical-let ((tag (car opt))
                (binding (car (cdr (cdr opt)))))
    (define-key notmuch-show-mode-map (concat "m" binding)
      (function (lambda ()
                  (my-notmuch-move tag))))))

(defun my-notmuch-do-move (tag folder)
  (let ((from (shell-quote-argument (notmuch-show-get-filename)))
        (to (shell-quote-argument folder)))
    (shell-command (concat "ln " from " " to))
    (shell-command (concat "rm " from))
    (dolist (cur-tag my-notmuch-remove-tags-on-move)
      (notmuch-show-tag-message (concat "-" cur-tag)))
    (notmuch-show-tag-message (concat "+" tag))))
(defun my-notmuch-move (&optional in-tag)
  (let* ((tag (or in-tag
                  (completing-read "Move message to: "
                                   (mapcar 'car my-notmuch-move-options))))
         (folder (cadr (assoc tag my-notmuch-move-options)))
         (full-folder (concat my-notmuch-mail-path "/" folder "/cur/")))
    (if (null folder)
        (error "Unknown tag: %s" tag)
      (my-notmuch-do-move tag full-folder))))

Download nottoomuch-addresses into ~/bin.

Fetch addresses from mails:

./~/bin/nottoomuch-addresses --update

Should probably add as a cron job as well.

Add to ~/.emacs:

(require 'notmuch-address)
(setq notmuch-address-command "~/bin/nottoomuch-addresses.sh")

Adds TAB-completion in "To:" field when composing mails.

Author: Dan Amlund Thomsen

Created: 2019-05-09 Thu 19:53