So I’ve been adviced to use ~/.mailrc for keeping a basic address book in Emacs, for use within gnus for example. I had to resort to the manual to find out how to use the file aliases when I need them, that is when composing a mail. For the record, here’s what I had to do:

;; mails and aliases
(add-hook 'mail-mode-hook 'mail-abbrevs-setup)
(global-set-key (kbd "C-c @") 'mail-abbrev-insert-alias)

That means I prefer hitting C-c @, then typing the alias in the minibuffer (with completion) and there after see the full mail address in my message-mode buffer. This looks like it’ll change over time, but rather than searching how to have a nice inline alias completion ( M-tab maybe, but already used by the window manager), I’ve tackled the problem of maintaining the ~/.mailrc file.

Lazy as I am (or I wouldn’t be using Emacs this much), having to manually select the email region in the buffer, open or switch to the mailrc buffer then paste my new entry, not forgetting to format it with alias foo prefix and checking for alias usage while doing so didn’t strike me as appealing. Oh and don’t forget to add quote where they belong, too.

Too much work that I wanted to automate. Here we go:

;; automate adding mail at point to ~/.mailrc
(defun dim:mailrc-add-entry (alias)
  "read email at point"
  (interactive "Malias: ")
  (let ((address (thing-at-point 'email-address))
	(buffer (find-file-noselect mail-personal-alias-file t)))
    (when address
      (with-current-buffer buffer
	;; we don't support updating existing alias in the file
	(save-excursion
	  (goto-char (point-min))
	  (if (search-forward (concat "alias " alias) nil t)
	      (error "Alias %s is already present in .mailrc" alias)))

	(save-current-buffer
	  (save-excursion
	    (goto-char (point-max))
	    (insert (format "\nalias %s \"%s <%s>\"" alias (cdr address) (car address)))))))))

(global-set-key (kbd "C-c C-@") 'dim:mailrc-add-entry)

Quite there, you’ll notice that I’m using thing-at-point 'email-address, and maybe you already know that emacs23 does not provide this. It provides thing-at-point 'email which will ignore real name and all. For example, given a point somewhere inside the right part of John Doe <[email protected]> the 'email variant of thing-at-point will return [email protected]. In words of one syllabe: not what I want.

So after searching around for a solution, I saw mail-header-parse-address from the API oriented mail-parse librairy, and finaly came up with this dead simple solution which works fine enough for me:

(require 'mail-parse)

(defun thing-at-point-bounds-of-email-address ()
  "return a cons of begin and end position of email address at point, including full name"
  (save-excursion
    (let* ((search-point (point))
	   (start (re-search-backward "[:,]" (line-beginning-position) 'move))
	   (dummy (goto-char search-point))
	   (end   (re-search-forward  "[:,]" (line-end-position) t)))
      (setq start (if start (+ 1 start)
		    (line-beginning-position)))
      (unless end (setq end (line-end-position)))
      (cons start end))))

(defun thing-at-point-email-address ()
  "return full email address at point"
  (let* ((bounds (thing-at-point-bounds-of-email-address))
	 (email-address-text
	  (when bounds (buffer-substring-no-properties (car bounds) (cdr bounds)))))
    (mail-header-parse-address email-address-text)))

(put 'email-address 'bounds-of-thing-at-point 'thing-at-point-bounds-of-email-address)
(put 'email-address 'thing-at-point 'thing-at-point-email-address)

Now, when I receive a mail and want to store an alias for it, I simply place point somewhere in the mail then hit C-c C-@, and voilà my ~/.mailrc is uptodate.

Hope it’ll be useful for someone else, but at least I’m keeping annotated history of the files :)