email

Email templates in mu4e with yasnippet

This is the second in a series of posts on using mu4e for email in emacs. When I moved from thunderbird to mu4e, there were some thunderbird extensions that I missed. One was quicktext which I used to create simple email templates for common sorts of emails. This is easily replicated in emacs using yasnippet.

As a simple example, I made a snippet to expand the key all into

Hi all,

Cheers,

Ben

The snippet is

# -*- mode: snippet -*-
# name: hi all
# key: all
# --
Hi all,

$0

Cheers,
 Ben

This snippet is saved in the message-mode subdirectory of my snippets directory, since message-mode is the major mode for email composition in mu4e.

We can be a bit smarter than this with a snippet that takes the name of the email recipient and adds that to the template. The following is close to binchen’s instructions with a few small modifications. There are two parts to this: a snippet that expands out as normal, and a lisp function that it calls when it expands to extract the recipient’s name.

First, the lisp function

;; function to return first name of email recipients
;; used by yasnippet
;; inspired by
;;http://blog.binchen.org/posts/how-to-use-yasnippets-to-produce-email-templates-in-emacs.html
(defun bjm/mu4e-get-names-for-yasnippet ()
  "Return comma separated string of names for an email"
  (interactive)
  (let ((email-name "") str email-string email-list email-name2 tmpname)
    (save-excursion
      (goto-char (point-min))
      ;; first line in email could be some hidden line containing NO to field
      (setq str (buffer-substring-no-properties (point-min) (point-max))))
    ;; take name from TO field - match series of names
    (when (string-match "^To: \"?\\(.+\\)" str)
      (setq email-string (match-string 1 str)))
    ;;split to list by comma
    (setq email-list (split-string email-string " *, *"))
    ;;loop over emails
    (dolist (tmpstr email-list)
      ;;get first word of email string
      (setq tmpname (car (split-string tmpstr " ")))
      ;;remove whitespace or ""
      (setq tmpname (replace-regexp-in-string "[ \"]" "" tmpname))
      ;;join to string
      (setq email-name
            (concat email-name ", " tmpname)))
    ;;remove initial comma
    (setq email-name (replace-regexp-in-string "^, " "" email-name))

    ;;see if we want to use the name in the FROM field
    ;;get name in FROM field if available, but only if there is only
    ;;one name in TO field
    (if (< (length email-list) 2)
        (when (string-match "^\\([^ ,\n]+\\).+writes:$" str)
          (progn (setq email-name2 (match-string 1 str))
                 ;;prefer name in FROM field if TO field has "@"
                 (when (string-match "@" email-name)
                   (setq email-name email-name2))
                 )))
    email-name))

This function takes the first name of the email recipient from the “To:” field of the message. It also looks for a name in the “Joe Bloggs writes:” text that mu4e generates when you reply to an email. This is populated from the “From:” field of the email being replied to and sometimes gives a better match for the name. The function compares the two name strings and prefers the “To:” name unless it contains an “@” in which case it chooses the “From:” name (this is the addition I made to binchen‘s version). You could make this more sophisticated but it works pretty well for me as is.

Now we need a snippet to expand:

# -*- mode: snippet -*-
# name: dear name
# key: dear
# --
Dear ${1:`(bjm/mu4e-get-names-for-yasnippet)`},

$0

Best wishes,
 Ben

Note how our function is straightforwardly called by the snippet to give “Dear NAME”.

Hopefully this gives you some ideas of how to make useful email templates with yasnippet. In future posts I’ll talk about how I have added attachment reminders and delayed sending features to mu4e.

Update 11/3/2016

I updated the code to give a comma separated list of names in the case of more than one recipient.

Advertisement

Master your inbox with mu4e and org-mode

In the following I will put forward my philosophy on handling emails and then show how this is realised in emacs using mu4e and org-mode.

I couple of years ago I read an article by the economist Tim Harford which hugely influenced the way I handle my emails. The ideas in the article are not unique but they really struck a chord with me. My email philosophy can be distilled down to one key concept:

your inbox is not a todo list

Like many people I used to keep emails in my inbox as a way of reminding me of something I needed to do, but the fact is that an inbox is a rubbish todo list.

I also had folders for putting emails in and I would occasionally have a painful cleanout of my towering inbox, agonising over which folder to put an email in, or whether I should create a new folder for it. No more! As long as your email programme has a good search, then it is quicker to search than to use a filing system.

Now when I check my emails, I do one of the following

  • delete if it is rubbish
  • read and delete if it is not something I’ll need to revisit
  • read and archive if it is something I might need to look up again
  • reply and archive if it is something that will take less than a couple of minutes to reply to and I have the time
  • add to todo list and archive if it is something that requires an action or just needs a longer reply than I have time to write

To use this system effectively, all you really need is: (i) an email client with a good search function so you can archive all mail in the same folder and not worry about filing it neatly, and (ii) a good system for adding tasks from your emails to a todo list.

The mu4e email client in emacs, combined with org-mode for todo organisation is the perfect way to do both of these things. There is very good documentation on how to set up mu4e on the project web page, including configuring it to work well with gmail, so I won’t go over that here. What I will say is that mu4e is built on mu, a powerful email indexer so it has all of your search needs covered.

Apart from searching, mu4e integrates very well with org-mode to make it seamless to generate todo items from emails. To set this up, add the following to your emacs config file

;;store org-mode links to messages
(require 'org-mu4e)
;;store link to message if in header view, not to header query
(setq org-mu4e-link-query-in-headers-mode nil)

Now update your org-mode capture template to something like this

(setq org-capture-templates
      '(("t" "todo" entry (file+headline "~/todo.org" "Tasks")
         "* TODO [#A] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")))

This looks like the version we had before, but the extra %a adds a link to the file you are visiting when you invoke the capture template.

The beauty of this is that hitting C-c c t now generates a todo item that contains a link to the email you are currently viewing. So you have zero friction in creating a todo item to e.g. reply to an email by a certain deadline, and you can happily archive that email knowing that clicking the link in the todo item will take you directly back to it.

I moved from thunderbird to mu4e a couple of months ago and really haven’t looked back. The things I missed at first were some of the extensions I was using to: create email templates; remind me about attachments; and add a delay to outgoing email so that I could have an “undo send” functionality. Happily I’ve found solutions to all of these in mu4e and I’ll be covering them in future posts.

Use emacs for thunderbird emails

Some people use emacs as their email client with e.g. gnus, wanderlust or mu4e. I am not quite hardcore enough for that, and do my emailing in Thunderbird. I don’t have to give up on emacs completely when sending emails though. Using the external editor extension for Thunderbird, I can quickly compose your email in emacs and then send it in Thunderbird.

To use it, install the extension in Thunderbird, and then in its preferences, set the text editor path to your emacsclient with a -c option. For example, on my Mac, this is

/Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9/emacsclient -c

See this post about using emacsclient if you are not sure about that.

Now, when composing a mail in Thunderbird, I can click the emacs button that has appeared on the tool bar of the compose window (if it is not there, right click and add it from the list), or just hit Command-E. This launches an emacs window with the email text ready to go. Type in your text and when you are done, hit C-x C-c to save and close the window. Your emacs text should now be in your Thunderbird compose window.

One last point is that I like to use org-mode style structures in my emails, so I add the following to my emacs config file to tell emacs to open .eml files in org-mode.

;;use org mode for eml files (useful for thunderbird plugin)
(add-to-list 'auto-mode-alist '("\\.eml\\'" . org-mode))