These days I’m running mu4e, the mail programme that runs on the Emacs operating system (the one with the terrible editor), on the Windows Subsystem for Linux (WSL).

(Previously, see my other mu4e posts, I was using it on Linux or macOS.)

I have also switched from offlineimap to isync’s mbsync for no other reason than it was time to try something new.

In addition, and this is the topic of this post, I’ve switched from nullmailer to Emacs’s built-in smtp and smtp queue functionality for email delivery, because I now prefer the idea of having a second chance to evaluate whether an email should really go out or not.

In short, I compose a few emails, “sending” each of them, but instead of really delivering them to the outgoing mail server, mu4e keeps them in a queue.

In the screenshow below, I have only a single mail in the queue:

As you can see, if I press f, the outgoing email queue will all be delivered.

However, if I have second thoughts about any of the mails, I can remove them from the outgoing queue.

The rest of this post shows how to configure two separate aspects:

  1. General smtp email queuing for mu4e.
  2. Sending out the whole queue in the background using John Wiegley’s async.el

Configure outgoing mail queue.

This part is pretty straight-forward and gets you the queuing behaviour described above.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
;; when switch off queue mode, I still prefer async sending
(use-package async
  :ensure t
  :config (require 'smtpmail-async))

(setq
 send-mail-function 'async-smtpmail-send-it
 message-send-mail-function 'async-smtpmail-send-it
 ;; replace with your email provider's settings
 smtpmail-smtp-server "smtp.fastmail.com"
 smtpmail-smtp-service 465
 smtpmail-stream-type 'ssl
 
 ;; if you need offline mode, set these -- and create the queue dir
 ;; with 'mu mkdir', i.e:
 ;; mu mkdir /home/user/Mail/queue && touch ~/Maildir/queue/.noindex
 ;; https://www.djcbsoftware.nl/code/mu/mu4e/Queuing-mail.html
 smtpmail-queue-mail  t
 smtpmail-queue-dir  (expand-file-name "~/Mail/queue/cur"))

Setup background queue sending.

This section, which is less obvious than the previous one, demonstrates how to move the whole queue sending action to a background Emacs process using the excellent async.el package.

This is convenient, because after triggering the queue send action, I can continue working in Emacs whilst a newly started background Emacs process takes care of delivering all of the queued messages.

As an added bonus, it demonstrates how to use the Emacs Lisp advice-add function to change the behaviour of an existing function.

In other words, the existing smtpmail-send-queued-mail function is looked up when you press f, but the extra advice is also found and applied.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
(defun async-smtpmail-send-queued-mail (sync-func &rest args)
  (message "Starting asynchronous smtpmail-send-queued-mail")
  (async-start
   `(lambda ()
      (require 'smtpmail)
      ;; see smtpmail-async.el - we inject the same variables
      ,(async-inject-variables
        "\\`\\(smtpmail\\|async-smtpmail\\|\\(user-\\)?mail\\)-\\|auth-sources\\|epg\\|nsm"
        nil
        "\\`\\(mail-header-format-function\\|smtpmail-address-buffer\\|mail-mode-abbrev-table\\)")
      ;; if we don't use the above inject we can pass in specific variables like this:
      ;; (setq smtpmail-queue-dir ,smtpmail-queue-dir)
      ;; (setq smtpmail-smtp-server ,smtpmail-smtp-server)
      (,sync-func))
   (lambda (&optional _unused)
     (message "Done sending queued mail in the background."))))

;; https://emacs.stackexchange.com/a/14827/8743 has more, err, advice.
(advice-add #'smtpmail-send-queued-mail :around #'async-smtpmail-send-queued-mail)