MailtoHandler

Web browsers and other applications automatically launch an email program when a user clicks a mailto link. The application is customizable, but emacs would just see the mailto link as a filename to start editing. We can can easily fix that.

Launch emacs and start composing mail

Name this script something like emacsmail.

 #!/bin/bash
 emacsclient -c --eval "(browse-url-mail \"$@\")"  

Old / outdated manual mailto parsing

Emacs has builtin functionality to parse a mailto link (which can include headers like subject and body) and populate the relevant fields in compose mail. Perhaps before this existed, people filled this page with code which did this separately. It makes sense to avoid this now. However, there may be some special behavior you want and this code could help you get it.

Shell script which strips mailto headers and composes mail

The following small shell script is meant to be executable and its purpose is to take a mailto link as its argument and pass it to Emacs. Configure your web browser and operating system so that the script is the default email application. The script uses emacsclient to open a new frame in Emacs session. You can change the command line to suit your needs and Emacs usage. The important part is the --eval "$elisp_expr" option; leave that untouched.

#!/bin/sh
# emacs-mailto-handler

mailto=$1
mailto="mailto:${mailto#mailto:}"
mailto=$(printf '%s\n' "$mailto" | sed -e 's/[\"]/\\&/g')
elisp_expr="(mailto-compose-mail \"$mailto\")"

emacsclient -a "" -c -n --eval "$elisp_expr" \
	'(set-window-dedicated-p (selected-window) t)'

Functions to handle mailto call when you use gnus-posting-styles

Configure mozex addon in firefox to call the script below. by RichardRiley

#!/bin/bash
# gnumail
#mailto=$(printf '%s\n' "$1" | sed -e 's/[\"]/\\&/g') ;; sed substitution that cleans all "\" but leaves "mailto:" before email address if it is there.
mailto=$(printf '%s\n' "$1" | sed -e 's/mailto:/\\/' |sed -e 's/[\"]//g') ;; this cleans both "mailto:" and any occurrence of "\"
elisp_expr=$(printf '(rgr/mailto "%s")' "$mailto")
 
 emacsclient --alternate-editor="" -c -n \
         --eval "$elisp_expr" \
         --eval '(set-window-dedicated-p (selected-window) t)'

Add the following to your .emacs (not your .gnus): it takes care of starting gnus if not done and allows you to configure a default posting style.

(setq gnus-default-mailto-group "INBOX.mail");; configure as appropriate

(defun rgr/mailto (to)
  "Send an email to 'to' but prompting for a posting style if not configured. Starts Gnus if not already running."
  (require 'gnus)
  (unless gnus-active-hashtb (gnus)) ;; Better way??
  (let ((gnus-newsgroup-name
         (if gnus-default-mailto-group gnus-default-mailto-group (completing-read "Use posting style of group: "
                          gnus-active-hashtb nil
                          (gnus-read-active-file-p)))))
    (compose-mail to)))

ErikArneson suggests this alternate function, based on rgr/mailto but using development Gnus:

(defun ela/mailto (to)
  "Send an email to 'to' but prompting for a posting style if not configured. Starts Gnus if not already running."
  (require 'gnus)
  (unless gnus-active-hashtb (gnus)) ;; Better way??
  (let ((gnus-newsgroup-name (or gnus-default-mailto-group 
                                 (completing-read "Use posting style of group: "
                                                  gnus-active-hashtb nil
                                                  (gnus-read-active-file-p)))))
    (gnus-setup-message 'message (message-mail to))))

Emacs Lisp code : Wanderlust

Using emacs-mailto-handler as above, this function can be used to start composition of a new message in Wanderlust:

(defun mailto-compose-mail (mailto-url)
  (if (and (stringp mailto-url)
           (string-match "\\`mailto:" mailto-url))
      (progn
        (require 'rfc2368)
        (let* ((headers (mapcar (lambda (h) (cons (intern (car h)) (cdr h)))
                          (rfc2368-parse-mailto-url mailto-url)))
               (good-headers (remove-if (lambda (h) (member (car h) '(Body))) headers))
               (body (cdr (assoc 'Body headers))))
          (wl-draft good-headers nil nil body)))))

Emacs Lisp code : no gnus-posting-styles

Make the following Emacs Lisp function available for your Emacs. You can just put it in your Emacs init file (~/.emacs) or you can put it in some directory in your load-path and add “(autoload ...)” command in your Emacs init file.

;;;; mailto-compose-mail.el (2010-08-15)

;;;###autoload
(defun mailto-compose-mail (mailto-url)
  "Parse MAILTO-URL and start composing mail."
  (if (and (stringp mailto-url)
           (string-match "\\`mailto:" mailto-url))
      (progn
        (require 'rfc2368)
        (require 'rfc2047)
        (require 'mailheader)

        (let ((hdr-alist (rfc2368-parse-mailto-url mailto-url))
              (body "")
              to subject
              ;; In addition to To, Subject and Body these headers are
              ;; allowed:
              (allowed-xtra-hdrs '(cc bcc in-reply-to)))

          (with-temp-buffer
            ;; Extract body if it's defined
            (when (assoc "Body" hdr-alist)
              (dolist (hdr hdr-alist)
                (when (equal "Body" (car hdr))
                  (insert (format "%s\n" (cdr hdr)))))
              (rfc2047-decode-region (point-min) (point-max))
              (setq body (buffer-substring-no-properties
                          (point-min) (point-max)))
              (erase-buffer))

            ;; Extract headers
            (dolist (hdr hdr-alist)
              (unless (equal "Body" (car hdr))
                (insert (format "%s: %s\n" (car hdr) (cdr hdr)))))
            (rfc2047-decode-region (point-min) (point-max))
            (goto-char (point-min))
            (setq hdr-alist (mail-header-extract-no-properties)))

          (setq to (or (cdr (assq 'to hdr-alist)) "")
                subject (or (cdr (assq 'subject hdr-alist)) "")
                hdr-alist
                (remove nil (mapcar
                             #'(lambda (item)
                                 (when (memq (car item) allowed-xtra-hdrs)
                                   (cons (capitalize (symbol-name (car item)))
                                         (cdr item))))
                             hdr-alist)))

          (compose-mail to subject hdr-alist nil nil
                        (list (lambda (string)
                                (insert string))
                              body))))
    (compose-mail)))

CategoryMail