Using Emacs with Outlook

Originally posted to comp.lang.python on 29 May, 2001...

Motivation

Every so often, I make it a point to try some other language or tool, so as to widen my perspective a bit. For example, I'm an ardent emacs fan, but I've learned vi so that I'm able to edit anywhere (well, on any Unix machine), and so as to appreciate other ways to edit files.

In this same way, I decided to try Microsoft Outlook. I'm an exmh hacker/fan (have been, for years), but thought I'd try Outlook just to see what my business/marketing/managements friends have to deal with. :-)

My one biggest gripe is that you can't use the editor of your choice when you edit your drafts. The Outlook editor is okay... I mean, it's like every other Microsoft editor -- that is, reasonable, but lacking features (like the ability to reflow your text).

So, I decided to give Outlook the ability to use the editor of my choice. I'm also a perl fan, but discovered that what I wanted to do was a lot harder (or at least seemed to be) in perl. So, I turned to python. Python seems to have a lot of nice Win32 support... This is maybe my fifth or sixth small python script, and I'm liking it (python) more and more.

Bottom Line

I wanted to be able to edit my drafts, in Microsoft Outlook, with the editor of my choice. In this case, Emacs. The following script does this for me... You tell Outlook to start a reply, and then you hit the "Edit" button that this script creates. It sucks the text out of Outlook, puts it into Emacs (you need to tweak the paths), then puts it back into Outlook when you're finished.

The Code

That said, here's the script. It's undoubtedly ugly, but the important stuff is there. :-)

import win32com.client
import os
import Tkinter
from Tkconstants import *

def launch():

    # Default to an empty body.

    body = ""

    # Get a handle to Outlook.

    o = win32com.client.Dispatch("Outlook.Application")

    # Work our way down to the reply (a "MailItem").

    insp = o.ActiveInspector()
    if insp == None: return
    item = insp.CurrentItem
    if item == None: return

    # Grab the body.

    body = item.Body

    # Should make this a guaranteed-unique file...

    fh = open("c:/temp/editor.txt", "w")

    # Write the body.  Had to add a try/except because of ASCII
    # encoding problems when the reply is in one of Outlook's more
    # funky formats.

    try:
        fh.write(body)
    except:
        fh.write("")

    fh.close()

    # Launch emacs to edit the file.  Should make this configurable.
    # Note that by default, Emacs seems to come up in Unix mode, and
    # so the ^M characters are visible.  A persistent, bound-to-a-key
    # Emacs macro takes care of that nicely, however.

    os.spawnv(os.P_WAIT,
              "d:/Editors/emacs-20.7/bin/emacs",
              ["d:/Editors/emacs-20.7/bin/emacs", "c:/temp/editor.txt"])

    # Read the result back into memory.

    fh = open("c:/temp/editor.txt", "r")
    body = fh.read()
    fh.close()

    # Store it as the body of the reply.

    item.Body = body


# Create a single button that, when clicked, takes care of the rest.

if __name__=='__main__':

    tk = Tkinter.Tk()

    frame = Tkinter.Frame(tk, relief=RIDGE, borderwidth=2, background="white")
    frame.pack(fill=BOTH, expand=1)

    button = Tkinter.Button(frame, text="Edit", command=launch,
                            background="white")
    button.pack(fill=BOTH, expand=1)

    tk.mainloop()

 


To Do

The thing I'd like to add, still, is the ability to put an icon into the system tray, rather than have it be a free-floating application with a button. The sample code I found was a bit hard to grok (given that I'm not a Windows programmer, nor more than a novice python programmer). If you know how to do that, and would care to add it in, I'd love to hear from you. :-)

Snags

The only issue I've found is that you can't run the script without having run makepy.py first, to make the Outlook library available. The full dynamic dispatch mechanism doesn't work, for some reason.