Version 13 of tcom Allows Emacs as Editor for MS Outlook

Updated 2004-01-08 09:43:54

MNO Playing around with the tcom extension after the inspiration of some Python code at http://disgruntled-programmer.com/notes/emacs-with-outlook.html , I came up with the following:-

It basically allows a running NTEmacs editor to grab the text of an email reply/forward etc. from Outlook and edit it in Emacs. It is then possible to transfer the edited text back to the outlook window and send it from there.

Currently only tested with Outlook 2000, ActiveTcl 8.4.3 and NTEmacs 21.3.1 under Windows 2000. I have no idea if it will work with Outlook 98, Outlook Express etc.

PLEASE READ THE LAST POINT UNDER "KNOWN ISSUES" BELOW BEFORE USING THIS CODE!

Pre-requisites

Installation

  • put the outlookedit.el lisp file somewhere in your load-path and add a (require 'outlookedit) into your .emacs file
  • place the two Tcl scripts onto your system and edit the locations in the outlookedit.el file

Usage

  • select a message in Outlook and click "Reply" (or "Reply to all" etc.)
  • switch to your NTEmacs window and press C-c o e (that is Control-C followed by "o" then "e" - mnemonic: Outlook Edit)
  • the message text should now appear in an Emacs buffer
  • edit in the emacs buffer
  • press C-c o s (mnemonic Outlook Save)
  • the edited text should now replace the text in the outlook window
  • (optionally) select "Format->Plain Text" to switch the message format back to plain text (see Known issues below for an explanation)
  • press Send as usual

Known Issues

  • Outlook 2000 (contrary to its documentation) renders the edited message as Rich Text regardless of the original format or the users specified preferred format. Outlook 2002 is reported to fix this by introducing a BodyFormat parameter.
  • If you change the configuration of active Outlook windows between grabbing the text and saving it back to Outlook you will probably overwrite the wrong text. You have been warned! Don't blame me!

The Code

The Emacs-Lisp file outlookedit.el

 ;;; outlookedit.el
 ;; use a couple of Tcl scripts to invoke my Tcl scripts to do COM
 ;; related actions on Outlook to get and replace text in the
 ;; reply/compose boxes allowing it to be edited in Emacs
 ;;
 (defvar mno-get-outlook-body 
   "tclsh C:\\Userdata\\Tcl\\grabOutlookMessage.tcl")
 (defvar mno-put-outlook-body 
   "tclsh C:\\Userdata\\Tcl\\putMessageInOutlook.tcl")
 (defvar mno-outlook-default-justification 'full)  

 (global-set-key "\C-coe" 'mno-edit-outlook-message)
 (global-set-key "\C-cos" 'mno-save-outlook-message)

 (defun mno-edit-outlook-message ()
   "* Slurp an outlook message into a new buffer ready for editing 

 The message must be in the active Outlook window.  Typically the
 user would press the Reply or Reply-all button in Outlook then
 switch to Emacs and invoke \\[mno-edit-outlook-message]

 Once all edits are done, the function mno-save-outlook-message
 (invoked via \\[mno-save-outlook-message]) can be used to send the
 newly edited text back into the Outlook window.  It is important that
 the same Outlook window is current in outlook as was current when the
 edit was started when this command is invoked."
   (interactive)
   (save-excursion
     (let ((buf (get-buffer-create "*Outlook Message*"))
           (body (shell-command-to-string mno-get-outlook-body)))
       (switch-to-buffer buf)
       (message-mode) ; enables automagic reflowing of text in quoted
                      ; sections
       (setq default-justification mno-outlook-default-justification)
       (setq body (replace-regexp-in-string "\r" "" body))
       (delete-region (point-min) (point-max))
       (insert body)
       (goto-char (point-min))))) 


 (defun mno-save-outlook-message ()
   "* Send the outlook message buffer contents back to Outlook current window 

 Unfortunately, Outlook 2000 then renders this text as Rich Text format
 rather than plain text, overriding any user preference for plain text.
 The user then needs to select Format->Plain text in the outlook
 compose window to reverse this.

 Outlook 2002 apparently has a BodyFormat parameter to control this."
   (interactive)
   (save-excursion
     (let ((buf (get-buffer "*Outlook Message*")))
       (set-buffer buf)
       (shell-command-on-region (point-min) (point-max) mno-put-outlook-body)
       (set-buffer-modified-p 'nil) ; now kill-buffer won't complain!
       (kill-buffer "*Outlook Message*")))) 

 (provide 'outlookedit)
 ;;;end of file outlookedit.el

The grab and put functions used above. First putMessageInOutlook.tcl:-

 #!/bin/sh
 # Emacs please open this in -*-Tcl-*- mode
 # do not remove this backslash! -> \
     exec tclsh $1 ${1+"$@"}
 #
 # loosely based on Python code from 
 # http://disgruntled-programmer.com/notes/emacs-with-outlook.html
 #
 package require tcom

 set body [read stdin]
 #
 # find Outlook:-
 if { [catch {::tcom::ref getactiveobject Outlook.Application} o] } {
     puts "Couldn't find Outlook via COM: $o"
     exit 1
 }
 # get the current item:-
 if { [catch {$o -get ActiveInspector} a] } {
     puts "Couldn't get the ActiveInspector for Outlook via COM: $a"
     exit 2
 }
 if { [catch {$a -get CurrentItem} i] } {
     puts "Couldn't get the CurrentItem for Outlook via COM: $i"
     exit 3
 }   
 # and finally replace its body
 if { [catch {$i -set Body $body} err] } {
     puts "Couldn't replace the Body via COM: $err"
     exit 4
 }
 # The following (untested) might convert back from RTF in Outlook 2002
 catch {$i -set BodyFormat 1}
 # that's it

and second, grabOutlookMessage.tcl:-

 #!/bin/sh
 # Emacs please open this in -*-Tcl-*- mode
 # do not remove this backslash! -> \
     exec tclsh $1 ${1+"$@"}
 #
 # loosely based on Python code from 
 # http://disgruntled-programmer.com/notes/emacs-with-outlook.html
 #
 package require tcom
 #
 # find Outlook:-
 if { [catch {::tcom::ref getactiveobject Outlook.Application} o] } {
     puts "Couldn't find Outlook via COM: $o"
     exit 1
 }
 # get the current item:-
 if { [catch {$o -get ActiveInspector} a] } {
     puts "Couldn't get the ActiveInspector for Outlook via COM: $a"
     exit 2
 }
 if { [catch {$a -get CurrentItem} i] } {
     puts "Couldn't get the CurrentItem for Outlook via COM: $i"
     exit 3
 }   
 # and finally slurp its body
 if { [catch {$i -get Body} body] } {
     puts "Couldn't retrieve body from CurrentItem via COM: $body"
     exit 4
 }
 #
 # spew it out to stdout
 #
 puts $body
 # that's it

Stefan Vogel 7 Jan 04:

Seems to me that the tcl-scripts are swapped (Fixed - ecw). I think the code for "grabOutlookMessage.tcl" should be "putMessageInOutlook.tcl" and vice versa. Furthermore the elisp-line (message-mode) complains about a missing mailheader (maybe that's only my problem, because I never really configured my emacs (on Windows) for mails). I simply removed this line.

But ... wow ... this is way cool. That's what I always wished to do. Get rid of this lousy MS-Outlook-Editor (it's not even worth to be called an editor).


Ephrem Christopher Walborn[L1 ] - 20040107

The tcl-scripts were indeed swapped, but I've fixed it. This works beautifully with XP and Office XP, which is great since I just got the word today that I'm no longer to use anything but Outlook for my work e-mail.

The next thing I did, once I got this working, was to write a quick batch script to avoid having to do C-coe:

    c:\emacs\bin\gnudoit.exe (mno-edit-outlook-message)

Drag & drop it onto the shortcuts bar in outlook... it'd be even better if it could be a button on the e-mail message form and also switch focus to emacs.

Outlook does now allow me to drag&drop a batch-file anywhere. How did you do this?