Ultimate MS Outlook Editor

matthew's picture

At my work, I'm required to use Microsoft Outlook for exchanging email with my co-workers. At home, I use Mutt on FreeBSD, and have grown to really love the lightning-fast responsiveness, immunity to virusses, and easy scriptability of this tiny text-based mail reader.

I'm going to tell you one solution, just so I can tell you another one :)

It's possible to use Mutt with Microsoft Exchange:

  • Set up IMAP on your Exchange server. This was already done here.
  • Install a copy of Cygwin, including Python.
  • Either set up Mutt to access IMAP on Exchange directly, or do what I prefer to do: download and set up offlineimap. This IMAP-to-Maildir synchronization utility is excellent.
    1. First, you need to run the "rebaseall" utility so that Python doesn't dump with traceback when you try to run offlineimap. You can't rebaseall if you're trying to do it from an rxvt window -- you need to be using the cmd-based Cygwin shell for it to finish without an error.
    2. Then you need make sure your .offlineimaprc file specifies "Curses.Blinkenlights" as the first available interface -- the TK interface, on Win32, just hangs.
  • You can't use offlineimap on a non-managed Cygwin mount. The reason is that the Maildir specification uses the ":" character, which is a big no-no in Windows-land. The solution is to use this command:
    $ mount -f -s -b -o managed "d:/tmp/mail" "/home/of/mail"
    
    substituting the windows-path directory you wish to use for mail for the "d:/tmp/mail" above, and the mount point you wish to put it on instead of "/home/of/mail".
  • Once you have IMAP-to-Maildir synchronization going to your local PC, then you're good to go with offline IMAP stuff and Mutt. Follow the usual directions for configuring Mutt to use the Maildir you've set up, paying particular attention to choice of outbound mailer (probably ssmtp).
Obviously, though I'm a big fan of Mutt, that seemed like a lot of work. Lucky me, I chanced across a script that, with minor modifications, gave me the primary thing I loved about using Mutt: being able to use vim as my text editor. I'm just much faster using that than any other editor, and it's ubiquitous on UNIX systems, either in a more-primitive incarnation of "vi", or in some version.

So I installed Python and the Win32 extensions for Python, then linked this script on my quickbar in Windows, conveniently right next to Outlook:

#!/bin/env python
'''
outlook.pyw (OutLook editor launcher) -- allows one to edit an open e-mail
      mesg from Outlook using Emacs or *Vi* rather than "Notepad--".  :-)
      NOTE:  requires Python 1.6 and newer (use of string methods)

created by John Klassa (klassa at employees.org) on 2001 May 29
updated by Wesley Chun (cyberweb at rocketmail.com) on 2002 Feb 28

$Id: outlook.pyw,v 0.2 2002/08/28 18:04:06 wesc Exp wesc $
'''

from os import spawnv, P_WAIT, unlink
from tempfile import mktemp
from Tkinter import Tk, Button, Frame, Label
from Tkconstants import *
from win32com.client import Dispatch

def launch():
    '''launch() spawns your favorite editor to edit the Outlook compose 
    window (either new or reply), then returns that data to Outlook...
    change the 'ed' variable to switch editors.'''

    # Get a handle to Outlook.
    o = 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 message body in the reply.
    body = item.Body

    # Write the body... need to "encode" the string because Outlook uses
    # Unicode with bunch of unprintables (ASCII chars > 128).  Also, since
    # we are going from DOS2UNIX2DOS, we have the \r\n vs \n issue, re-
    # sulting in those fabulous ^M characters.  A persistent, bound-to-a-
    # key Emacs macro takes care of that nicely, but the solution imple-
    # mented here is to just wipe the '\r's now, then add them back when
    # we reread this file back before returning the body to Outlook.
    tmp = mktemp()                  # generate a unique tmp filename
    fh = open(tmp, "w")
    fh.write(body.encode('ascii', 'ignore').replace('\r\n', '\n'))
    fh.close()

    # Launch editor to edit the file (should make this configurable).
    #ed = r"d:\emacs-20.7\bin\emacs"            # emacs editor binary
    ed = r"c:\vim\vim62\gvim.exe"   # *vi*  editor binary
    spawnv(P_WAIT, ed, [ed, tmp])

    # Read edited file back into memory, restore '\r's, and kill tmp file.
    fh = open(tmp)
    body = fh.read().replace('\n', '\r\n')
    fh.close()
    unlink(tmp)

    # Store it as the body of the reply.  Note that we are merely
    # sending this data back to Outlook -- it does not prevent MS from
    # mucking with your message.  For example, it may add your signature
    # again, or it may remove newlines.  MS software... what can you do?
    item.Body = body

# Create the Tk(inter) GUI app with the appropriate label and buttons.
if __name__=='__main__':
    tk = Tk()
    f = Frame(tk, relief=RIDGE, borderwidth=2).pack()
    Label(f, text="Outlook Edit Launcher v0.2").pack()
    Button(f, text="Edit", fg='blue', command=launch).pack(fill=BOTH)
    Button(f, text="Quit", fg='red', command=tk.quit).pack(fill=BOTH)
    tk.mainloop()

I now click Outlook, then click my outlook.py script. I minimize the annoying black cmd window that comes up (anybody know how to get rid of this?), and I now have a little Python/TK window with a convenient "edit" button on it. When I compose a message in LookOut, I click this "edit" button, and up pops gvim 6.2, ready for me to type the message. When I'm done typing it, I just write-quit out of gvim, and the text pops up in my Outlook compose window.

Convenient! Well, for a UNIX-geek at least.

Anyway, I'm still torn. Do I really need to use Outlook here? Realistically, I have maybe one meeting a week that I need to keep track of, and that's easily done in my Palm. Maybe I should just use Mutt in Cygwin on a managed mount? Who knows, but both are valid choices. And in a world where MS wants you to only use MS products, and those products are funkily generic and slow, it's nice to have choices.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

I was thinking of having the

I was thinking of having the external editor launch automatically on each new message, but I need to type the addresses & subject first and I may also want to edit replies in Emacs, so autolaunch would probably be more trouble than it's worth.

So I'll use the link you sent to add a hotkey.

weed's picture

You're close

Try it the other way:

Click the emacs button: determine the temp file emacs is using.
open that one in vi (don't use the button, just open vi manually) and see if the text is in there.

If you hit the Project1.LaunchVIM button and then hit the Project1.LaunchEmacs button on the same message, it should open 2 different tmp files. Otherwise VIM and Emacs would fight over the one tmp file. However, there might be some issues with opening both editors at the same time I don't see right now...

Post the modified code you're using to launch emacs and let me look it over

As for the bug, you need to do this:

Dim ffile
Set ffile = fso.GetFile(tfolder.Path & "\" & tname)
If ffile.Size > 0
Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close
End if
ffile.Close

And ixnay on the andapay oviemays, kayoay? ;)

My $.02
Weed

My $.02
Weed

Outlook / Editor wars

Matthew,

Yes, knowing both would be nice, but I'm a salesman, not an IT or programmer, so the fact that I can even spell emacs is overkill for my role.

This kind of brings up a discussion of use cases. You are "Ace Sysadmin," Microsoft designs for "Ignorant Newbie, and I'm "Technically-Inclined Productivity-Obsessed Power User." I'm capable of changing my path, writing autohotkey scripts & batch files, learning shortcuts, etc. But I really don't have skills to do all that you mention in a finite amount of time without screwing stuff up.

But I'm really surprised to say this: After hating and resisting Outlook my entire career, I realize it can become a pretty good "Integrated Productivity Environment," so much that I'm devoting one of my monitors to it. Here's how:

1. Apply David Allen's whitepaper "GTD in Outlook."
(this also kind of clarified a lot of GTD principles that weren't clear from the book)
I have some minor tweaks, but he gives a good "base install."

2. Install Speedfiler from Claritude. Speedfiler gives me the filing & navigation power that even Thunderbird (which I used for the last 1.5 years ago) and PINE lack. Even QuickMove didn't really help that much with TB.

Speedfiler can be used on both incoming & outgoing messages, and provides the interactive substring search that I have always dreamed of. Outlook has Ctrl-Shift-V to move a message and Ctrl-Y to go to a folder. Speedfiler replaces the crappy graphical browser with a substring search. So I can move a message to my _@Action-NonSales folder with:
Ctrl-Shift-V nons

And go to a folder at _Reference/Tier1/Asian/Denso with:
^y den

SpeedFiler kicks butt.

more on use cases...

BTW, I'm not singling out computer professionals: I recently upgraded to Quicken 2007 from 2000. My main motivation was to automate as much as possible so that I would actually start keeping financial records again (and do so FASTER than my grandmother's paper checkbook, which could not be said of my all-manual Quicken 2000). When I ask friends for help, they fall into two categories:

1. People who don't use Quicken.

2. Accountants. Quicken is their *hobby* and they have never used & don't understand the WebConnect or DirectConnect. They say "Oh, I've never tried any of that online stuff; I just enter all my transactions manually. I log in and check my credit cards every morning, too. Look at my calculator watch: I paid $39.47 for it in 1985."

Emacs always opens a blank file...

New message, type "Weed enjoys Family Friendly entertainment"
Click Project1.LaunchEmacs
Emacs launches and edits C:\TEMP\radD281D.tmp , which is blank

Click Project1.LaunchVIM
Vim launches, edits C:\temp\rad9F783.tmp

I don't think it has anything to do with dueling two editors: Emacs *never* has the right file.

My ill-informed brainstorms:
1. Emacs' method of opening files has a race condition, where Windows starts using a different filename before it fully opens????

2. Emacs' method of frontslash / backslash translation screws things up?

Here's the full text of my emacs code:
Option Explicit

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
lpStartupInfo As STARTUPINFO, lpProcessInformation As _
PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _
hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&

Sub LaunchEmacs()

'Dim windir As String

'windir = Environ("WinDir")

'Shell (windir & "\system32\cscript.exe " & windir & "\system32\launchEmacs.vbs")

Const TemporaryFolder = 2
Const EmacsLocation = "C:\apps\emacs-22.1\bin\runemacs.exe"

Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

Set ol = Application

Set insp = ol.ActiveInspector
If insp Is Nothing Then
Exit Sub
End If
Set item = insp.CurrentItem
If item Is Nothing Then
Exit Sub
End If

body = CStr(item.body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName
Set tfile = tfolder.CreateTextFile(tname)
tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Close

ExecCmd EmacsLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close

fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Public Sub ExecCmd(cmdline$)

Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim ReturnValue As Integer

' Initialize the STARTUPINFO structure:
start.cb = Len(start)

' Start the shelled application:
ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

' Wait for the shelled application to finish:
Do
ReturnValue = WaitForSingleObject(proc.hProcess, 0)
DoEvents
Loop Until ReturnValue <> 258

ReturnValue = CloseHandle(proc.hProcess)

End Sub

-----------------------------------------------
Option Explicit

Private Sub launch()

Const TemporaryFolder = 2

Dim ws, ol, insp, item, body, fso, tempfile, tfolder, tname, tfile

Set ol = CreateObject("Outlook.Application")

Set insp = ol.ActiveInspector
If insp Is Nothing then
Exit Sub
End if
Set item = insp.CurrentItem
If item Is Nothing then
Exit Sub
End if

body = CStr(item.Body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName
Set tfile = tfolder.CreateTextFile(tname)
tfile.Write( Replace( body, Chr(13) & Chr(10), Chr(10) ) )
tfile.Close()

Set ws = WScript.CreateObject("WScript.Shell")
Wsh.Echo( "C:\apps\emacs-22.1\bin\runemacs.exe " & tfolder.Path & "\" & tname )
ws.Run "c:\apps\emacs-22.1\bin\runemacs.exe " & tfolder.Path & "\" & tname ,4, true

Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1 )
item.body = Replace( tfile.ReadAll, Chr(10), Chr(13) & Chr(10) )
tfile.close()

fso.DeleteFile( tfolder.Path & "\" & tname )

End Sub

Call launch()

weed's picture

Can't use ws.run

Try this code:

*** BEGIN SNIP ***

Option Explicit

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
lpStartupInfo As STARTUPINFO, lpProcessInformation As _
PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _
hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&

Sub LaunchVIM()

Const TemporaryFolder = 2
Const VIMLocation = "C:\Program Files\Vim\vim70\gvim.exe"

Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

Set ol = Application

Set insp = ol.ActiveInspector
If insp Is Nothing Then
Exit Sub
End If
Set item = insp.CurrentItem
If item Is Nothing Then
Exit Sub
End If

body = CStr(item.body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName

Set tfile = tfolder.CreateTextFile(tname)
tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Close

ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

Dim ffile
Set ffile = fso.GetFile( tname )
If ffile.Size > 0 Then
Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close
End if
ffile.Close
fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Sub LaunchEmacs()

Const TemporaryFolder = 2
Const EmacsLocation = "C:\apps\emacs-22.1\bin\runemacs.exe"

Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

Set ol = Application

Set insp = ol.ActiveInspector
If insp Is Nothing Then
Exit Sub
End If
Set item = insp.CurrentItem
If item Is Nothing Then
Exit Sub
End If

body = CStr(item.body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName

Set tfile = tfolder.CreateTextFile(tname)
tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Close

ExecCmd EmacsLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

Dim ffile
Set ffile = fso.GetFile( tname )
If ffile.Size > 0 Then
Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close
End if
ffile.Close
fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Public Sub ExecCmd(cmdline$)

Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim ReturnValue As Integer

' Initialize the STARTUPINFO structure:
start.cb = Len(start)

' Start the shelled application:
ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

' Wait for the shelled application to finish:
Do
ReturnValue = WaitForSingleObject(proc.hProcess, 0)
DoEvents
Loop Until ReturnValue 258

ReturnValue = CloseHandle(proc.hProcess)

End Sub

**** END SNIP *****

That whole launch() function will never work: You can't use ws.run because it doesn't wait until the process ends to return to the calling function. Refer to the original post and see how I used CreateProcessA to call it synchonously. What happens when you use ws.run is that emacs is launched and then outlook just runs the rest of the code before emacs is ever opened.

My $.02
Weed

My $.02
Weed

Good news:After making some

Good news:
After making some minor fixes:
VIM can read text that was in Outlook & insert text.
Emacs can read text that was in Outlook !!

But in both cases, ffile.close is making a big problem: Run-time error 438 "object doesn't support this property or method," whether inside or outside the IF statement; deleting it completely doesn't work either.

Here is current code (note the <> operators on the do...until EOF check, some tabbing on the IF statements, putting the file path in the file opening statements, and (sorry) adjustments for my path:

Option Explicit

Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function CreateProcessA Lib "kernel32" (ByVal _
lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _
lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _
lpStartupInfo As STARTUPINFO, lpProcessInformation As _
PROCESS_INFORMATION) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal _
hObject As Long) As Long

Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const INFINITE = -1&

Sub LaunchVIM()

Const TemporaryFolder = 2
Const VIMLocation = "C:\apps\Vim\vim71\gvim.exe"

Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

Set ol = Application

Set insp = ol.ActiveInspector
If insp Is Nothing Then
Exit Sub
End If
Set item = insp.CurrentItem
If item Is Nothing Then
Exit Sub
End If

body = CStr(item.body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName

Set tfile = tfolder.CreateTextFile(tname)
tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Close

ExecCmd VIMLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

Dim ffile
Set ffile = fso.GetFile(tfolder.Path & "\" & tname)
If ffile.Size > 0 Then
Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close
End If

ffile.Close

fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Sub LaunchEmacs()

Const TemporaryFolder = 2
Const EmacsLocation = "C:\apps\emacs-22.1\bin\runemacs.exe"

Dim ol, insp, item, body, fso, tempfile, tfolder, tname, tfile, appRef, x

Set ol = Application

Set insp = ol.ActiveInspector
If insp Is Nothing Then
Exit Sub
End If
Set item = insp.CurrentItem
If item Is Nothing Then
Exit Sub
End If

body = CStr(item.body)

Set fso = CreateObject("Scripting.FileSystemObject")
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = fso.GetTempName

Set tfile = tfolder.CreateTextFile(tname)
tfile.Write (Replace(body, Chr(13) & Chr(10), Chr(10)))
tfile.Close

ExecCmd EmacsLocation & " " & Chr(34) & tfolder.Path & "\" & tname & Chr(34)

Dim ffile
Set ffile = fso.GetFile(tfolder.Path & "\" & tname)
If ffile.Size > 0 Then
Set tfile = fso.OpenTextFile(tfolder.Path & "\" & tname, 1)
item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))
tfile.Close
End If

ffile.Close

fso.DeleteFile (tfolder.Path & "\" & tname)

End Sub

Public Sub ExecCmd(cmdline$)

Dim proc As PROCESS_INFORMATION
Dim start As STARTUPINFO
Dim ReturnValue As Integer

' Initialize the STARTUPINFO structure:
start.cb = Len(start)

' Start the shelled application:
ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _
NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)

' Wait for the shelled application to finish:
Do
ReturnValue = WaitForSingleObject(proc.hProcess, 0)
DoEvents
Loop Until ReturnValue <> 258

ReturnValue = CloseHandle(proc.hProcess)

End Sub

end of code

weed's picture

Duh

The <> is because of the whole HTML tag thing, I guess that's why they were left out.

Replace the

ffile.close

with

Set ffile = Nothing

My $.02
Weed

My $.02
Weed

Now we're back to Square 1

So now VIM works perfectly (including handling zero-length files), but Emacs doesn't get text from or push text to Outlook.

* Commenting out the Set command doesn't help
* If I put the ffile.Close back in, I get the VB error, but at least emacs can read (but not write) the text.

weed's picture

No commenting

We're not commenting anything.

REPLACE the line:

ffile.Close

with

Set ffile = Nothing

My $.02
Weed

My $.02
Weed

Yes, I did that

Weed, thanks for sticking with me: I did the replacement exactly as you said. VIM works, even with zero-length files, but emacs doesn't.

The point is that the ffile.close version at least got text into emacs, but the new current version doesn't even do that.

Commenting was just my own step at debugging.

weed's picture

So Simple

So I decided to download emacs and test it out.

The problem is that you're calling runemacs.exe. The way my code works is that is launches the process, waits for it to exit, then reads the temp file to see what changes have been made. However, runemacs.exe is just a launcher for emacs.exe. So runemacs.exe starts, launches emacs.exe, and then exits. So my code sees that runemacs.exe has exited, reads the contents of the tmp file, and goes along its merry way. All before the actual emacs window has time to pop up on your screen.

The fix is to modify the Emacs_Location to run emacs.exe, not runemacs.exe. I don't know if this breaks anything else, but it fixes the immediate problem.

My $.02
Weed

My $.02
Weed

Yay!

Wow, thanks Weed!
The only change that I needed to make was to get rid of the cr/lf issue on the output, i.e., replace:

item.body = Replace(tfile.ReadAll, Chr(10), Chr(13) & Chr(10))

with:

item.body = tfile.ReadAll

Sorry about not knowing much about emacs invocation...runemacs is nice because it gets rid of an extra shell window that emacs leaves. I am aware of other programs/command s like gnuclient that also invoke emacs.

There may be things that addpm does also, but I installed a previous version on another computer and still usually got the extra black box.

And as far as hotkeys, I suspect that a refinement would be to map the desired key to an autohotkey script that would: get the position of the current message and get emacs to launch in roughly the same position. But I can probably figure that part out.

This is really cool; thanks, Weed!

EDIT by matthew: <pre> tags changed to <blockquote> due to threading issues.

weed's picture

Yer welcome

My $.02
Weed

My $.02
Weed

matthew's picture

The extra box...

If you look closely at my descriptions for running vim, you'll see that in early versions I had a similar text-box issue hanging out in the background. In my case, I just got used to it until Weed happily provided a workaround.

Weed is teh ubar sysadmin.

I believe that using "emacsclient" (included in the bin directory of your emacs package) rather than "runemacs" will preserve the benefit of runemacs without forking the emacs process (it will wait for emacs to exit before it exits). Downside: if you have multiple emacs windows running, it will wait for ctrl-x# or the last window to exit before it closes.

--
Matthew P. Barnson

--
Matthew P. Barnson

emacsclient

emacsclient was on my list of stuff to look up about the invocation issue. But I'll trade the black box for the ability to not clobber my other emacs window.

Instead of going to the current insertion point, something that I'd find more useful is even simpler (and I can't believe it's not in Outlook): a command to go to the body/notes of a message, appointment, or task.

The number of times to hit tab between the "subject" and body varies between the different categories of item.

It would be nice to hit alt-. or something and go to the body, but I guess there's not much need to do so with emacs enabled.

And I did successfully assign this macro to alt-/ (one of the few keys that is not used by a default Outlook macro), and it works in appointments and tasks as well as email.

Good contens, its works

Good content, it works Great
Thanks for all of your work on it.

Best Regards,
Bangkok Travel