2009-01-14

mutt inside emacs

There are some emacs-native programs for e-mail, such as gnus, vm and a couple of others. I never really got into them for some reason; I found them rather hard to set up and a bit counter-intuitive. Maybe I should give them another try, but for the last decade, I've been using the mutt console e-mail client - even with graphical alternatives like Evolution and Thunderbird available.

mutt is not perfect -- you cannot read older e-mails when composing a new one (without starting a new instance) and the macro language is a joke compared to elisp. Still, because it's totally keyboard-driven, I'm really efficient with mutt. Side note: if you need quick searching capability which can be integrated with mutt, see my mu search tool.

Mutt does not have a built-in editor -- instead, it relies on an external program. Obviously, I use emacs for that. Now, I don't want to start a new emacs for each new message that I write; instead I make use of the emacs server functionality. Practically, we can start an emacs server by adding to .emacs:

(server-start)
Now, we can open files in the existing emacs by calling emacsclient instead of emacs; and tell mutt to use that editor. Put in your .muttrc:
set editor="emacsclient +8 %s -a emacs"
This opens new messages in an existing emacs, and put the cursor on line 8 (after the mail headers). If no emacs is running yet, a new one will be started, due to the '-a'-argument.

This solution will work nicely, but requires you to start mutt in a console, and start emacs in a separate window. I prefer, however, to run everything inside emacs. This can easily be done - please look at the 'running console programs inside emacs'-entry again, to create a short-cut.

Now, when editing e-mail messages, it's nice to use one the special modes for that; they provide some interesting 'syntax highlighting' to your mail. You can use mail-mode, or my favorite, post-mode. To automatically use it, download and install it, and add some code to your .emacs:

(autoload 'post-mode "post" "mode for e-mail" t)
(add-to-list 'auto-mode-alist 
             '("\\.*mutt-*\\|.article\\|\\.followup" 
                . post-mode))
This will automatically load post-mode when editing a message from mutt (and for some other programs). You might also want to set up some other things when editing mails, using a hook:
(add-hook 'post-mode-hook 
  (lambda()
    (auto-fill-mode t)    
    (setq fill-column 72)    ; rfc 1855 for usenet messages
    (require 'footnote-mode) 
    (footmode-mode t)
    (require 'boxquote)))
Obviously, you need to install the boxquote and footnode modes, if you want to use those.

Final note: this same setup works nicely for the slrn news reader as well; just use the set editor_command= in your .slrnrc.

12 comments:

20y.hu said...

Instead of server-start, why not simply start emacs in daemon mode with 'emacs --daemon'.

Anonymous said...

20y.hu: When speaking about "emacs --deamon" it would be a good idea to mention that it is only available in the development version of Emacs. So the answer to your "why not" question might be that the feature doesn't exist in any released Emacs version.

20y.hu said...

Yup, you're right. I'm just always wondering that Emacs 23 has so many great features I cannot switch back to an older release :)

susja said...

hi djcb,
I wanted to set any email client inside Xemacs. First tried your recommendations from "mutt inside emacs" but it didn't work for me. I tried to connect to my SMTP yahoo server outgoing.yahoo.verizon.net that runs on port 25.
Then I put this in .xemacs :
(setq message-send-mail-function 'smtpmail-send-it
send-mail-function 'smtpmail-send-it
smtpmail-starttls-credentials '(("outgoing.yahoo.verizon.net" 25 nil nil))
smtpmail-auth-credentials '(("outgoing.yahoo.verizon.net" 25 nil nil))
smtpmail-default-smtp-server "outgoing.yahoo.verizon.net"
smtpmail-smtp-server "outgoing.yahoo.verizon.net"
smtpmail-smtp-service 25
smtpmail-debug-info t
smtpmail-debug-verb t )
When I composed mail and sent it first asked me for password ( I think it's a good sign ) but then failed to connect to SMTP with this error:
Debugger entered--Lisp error: (wrong-type-argument stringp nil)
base64-encode-string(nil)
smtpmail-try-auth-methods(#network connection "SMTP" (25 . "outgoing.yahoo.verizon.net") state:run> (8bitmime (auth login plain xymcookie)) "outgoing.yahoo.verizon.net" 25)
byte-code("..." [host n name supported-extensions process response-code get-buffer-create format "*trace of SMTP session to %s*" t erase-buffer smtpmail-open-stream throw done nil set-process-filter smtpmail-process-filter featurep mule file-coding set-process-coding-system no-conversion-unix make-local-variable smtpmail-read-point smtpmail-read-response 400 smtpmail-send-command "EHLO %s" smtpmail-fqdn "HELO %s" mapcar #compiled-function (s) "...(5)" [s intern] 2> split-string 4 "[ ]" 1 (verb xvrb 8bitmime onex xone expn size dsn etrn enhancedstatuscodes help xusr auth=login auth starttls) message "Unknown extension %s" smtpmail-find-credentials starttls process-id "STARTTLS" starttls-negotiate smtpmail-try-auth-methods onex xone "ONEX" verb xvrb ...] 8)
smtpmail-via-smtp(("evoldman@us.ibm.com") #buffer " smtpmail temp">)
smtpmail-send-it()
#compiled-function nil "...(117)" [noninteractive send-mail-function inhibit-read-only mail-send-actions opoint buffer-file-name y-or-n-p "Send buffer contents as mail message? " buffer-modified-p "Message already sent; resend? " t mail-header-end looking-at "[ ]\\|.*:\\|$" push-mark error "Invalid header line (maybe a continuation line lacks initial whitespace)" 1 expand-abbrev run-hooks mail-send-hook message "Sending..." nil (byte-code "Á@@@A\"‡" ... 3) (...) "Sending...done" set-buffer-modified-p delete-auto-save-file-if-necessary format "Save file %s? " save-buffer] 5 ("c:\\Program Files\\XEmacs\\xemacs-packages\\lisp\\mail-lib\\sendmail.elc" . 22079) nil>()
call-interactively(mail-send)
Any idea what I did wrong?
Thanks

djcb said...

@susja: i have no idea. i don't use the emacs smtpmail package, nor xemacs.

also - when running mut inside emacs, you set up in mutt, not in emacs.
mutt.org has a lot of documentation.

Zoltán Nagy said...

I didn't know about these handy modes, thanks. A note: footnote is misspelled in the second code listing (footmode-mode t) and the long link at the end (footnode mode). Might I suggest another great mode, flyspell-mode? ;) (Sarcasm unintended)

Ershad said...

Could you please say about the function/operations offered by post.el? Thanks.

djcb said...

@Ershad: http://post-mode.sourceforge.net/

it gives some different colors to mail header, quote text and so on.

Wolf said...

I know this is an old post, but hopefully you'll see this comment.

I'm trying to run mutt within emacs. I've tried using both ansi-term and multi-term. mutt loads fine, but whenever I press a key to perform any action, the cursor jumps to the end of the line, which emacs then centres in the frame, so that I can only see the right half of mutt. This only seems to happen with mutt, not any other terminal application. I don't suppose you have any idea what might cause this or how to fix it?

Thanks

djcb said...

@Wolf: both ansi-term and multi-term work for me. It sounds like some unwanted interaction between emacs and the terminal.

You can check AnsiTermHints; or maybe check if there is something in your shell setup.

Wolf said...

@djcb: I hadn't thought it might be a shell issue, but after your suggestion I took a look at my .bashrc (installed by default by Debian) and found this line:

shopt -s checkwinsize

I commented it out, sourced the file, and voila, mutt works properly within emacs now!

Thanks!

djcb said...

@Wolf: nice to hear. Now you can try my mu e-mail search engine which integrates with mutt :-)