Sending non-ASCII text in emails with Emacs and VM

I use Emacs to do a lot of work, not only editing files. For example all my email reading and writing I do with Emacs, as well as reading Usenet newsgroups. For email I use VM (viewmail) rather than the standard RMAIL.

One problem that popped up when we got the Euro as a currency was that VM couldn’t deal properly with non-ASCII characters when sending email. When a mixture of different character sets was present in a message a Japanese coding was chosen that most email reader don’t understand. Because I wanted to send emails with the €-sign I cooked up some code to make this work. The code was inspired by similar code in Gnus, the Emacs Usenet reader. (Some people also use gnus for their email but I prefer VM for that.)

Here is the code, which you can put in your .emacs file:
The variable vm-coding-system-priorities is a list of encodings that emacs should try in that order. The first that can encode all characters in the message will be chosen.
This code has been tested on Gnu Emacs versions 21 and 22. I have no idea whether it will work on other versions. Use it on your own risk.


(defun vm-sort-coding-systems-predicate (a b)
  (> (length (memq a vm-coding-system-priorities))
     (length (memq b vm-coding-system-priorities))))

(setq vm-coding-system-priorities
      '(iso-latin-1 iso-latin-9 mule-utf-8 mac-roman)
      mm-coding-system-priorities vm-coding-system-priorities)

; The next line is for a noautoload vm.elc. Otherwise use "vm-mime".
;(eval-after-load "vm"
; The next line is for an autoload (default) vm.elc. Otherwise use "vm".
(eval-after-load "vm-mime"
'(defun vm-determine-proper-charset (beg end)
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      (catch 'done
	(goto-char (point-min))
	(if (or vm-xemacs-mule-p
		(and vm-fsfemacs-mule-p enable-multibyte-characters))
	    (let ((charsets (delq 'compound-text (find-coding-systems-region
					  (point-min) (point-max)))))
	      (cond ((equal charsets '(undecided))
		     "us-ascii")
		    (t
		     (setq charsets
			   (sort charsets 'vm-sort-coding-systems-predicate))
		     (while charsets
		       (let ((cs (coding-system-get (pop charsets) 'mime-charset)))
			 (if cs
			     (throw 'done (symbol-name cs))))))))
	  (and (re-search-forward "[^\000-\177]" nil t)
	       (throw 'done (or vm-mime-8bit-composition-charset
				"iso-8859-1")))
	  (throw 'done vm-mime-7bit-composition-charset)))))))