Issue on def OnForward(self, disp, item): in python using win32.com

224 Views Asked by At

I found the code bellow here on stackoverflow with following link: Python Outlook win32 event trigger when email is opened

I'm trying use this code and add the "def OnForward(self, disp, item):" to add a signature on the e-mail that i forward. But the forward does not work well. I will try explain, every time i click on foward it popsup the e-mail on new window, but appear on main outlook window too, and then the "def OnRead(self):" stop working too! i dont know if express myself correctly, but any help will be appreciated

outlook main Window

import win32com.client
import pythoncom

#Handler for Application Object
class Application_Handler(object):
    def OnItemLoad(self, item):
        print('Application::OnItemLoad')

        #Only want to work with MailItems 
        if( item.Class == win32com.client.constants.olMail ): 
            #Get a Dispatch interface to the item
            cli = win32com.client.Dispatch(item)
            #Set up a handler
            handler = win32com.client.WithEvents(cli,MailItem_Handler)
            #Store the MailItem's Dispatch interface for use later
            handler.setDisp(cli)
 
#Handler for MailItem object
class MailItem_Handler(object):
    def setDisp(self,disp):
        self._disp = disp

    def OnOpen(self,item):
        print('MailItem::OnOpen')
    
    def OnRead(self):
        print('MailItem::OnRead')
        subj = self._disp.Subject
        print('Subject:',subj)
        body = self._disp.Body
        print('Body:',body)
    def OnClose(self, item):
        return
        print('---------------MailItem::OnClose-------------------')
        print('-----------------------------------------------------')

    def OnForward(self, disp, item):
        print('---------------MailItem::OnForward-------------------')

        newMail = self._disp.Forward()
        newMail.HTMLBody = self._disp.HTMLBody + 'teste'
        newMail.Display()

        print('-----------------------------------------------------')

outlook = win32com.client.DispatchWithEvents("Outlook.Application", Application_Handler)
#Message loop
pythoncom.PumpMessages()
3

There are 3 best solutions below

5
Eugene Astafiev On

every time i click on foward it popsup the e-mail on new window, but appear on main outlook window too

In the Forward event handler you can find the following code:

newMail = self._disp.Forward()
newMail.HTMLBody = self._disp.HTMLBody + 'teste'
newMail.Display()

Which calls the Forward again and again when the corresponding event is fired. So, the Forward method causes the Forward event fired.

The Forward event is fired when the user selects the Forward action for an item, or when the Forward method is called for the item. So, there is no need to call it anew in the event handler. This is a reaction to the Forward method. The new item being forwarded is passed as a parameter to the event handler.

def OnForward(self, disp, item):
        print('---------------MailItem::OnForward-------------------')

        newMail = item
        newMail.HTMLBody = self._disp.HTMLBody + 'teste'
        
        newMail.Display()

        print('-----------------------------------------------------')
6
DS_London On

EDIT: As @EugeneAstafiev quite correctly points out, the call to Forward() is unnecessary and will duplicate the action that Outlook is taking. There is also no need to call Display().

However, while the signature for the event is correct in that it takes two parameters, it is wrong about the implied types. The 1st argument (after self) is a Dispatch pointer to the new item, the 2nd is a flag which allows the handler to cancel the event.

Should be:

def OnForward(self,newItem,bCancel):
    newItem.HTMLBody = self._disp.HTMLBody + 'teste'

The newItem will be displayed as long as bCancel is not set to True by the event handler. The newItem does not actually get sent until the user clicks on the Send button, or the Send() method is called.

The reference for MailItem and its Events is here.

As an aside, on my tests setting bCancel=True has no effect, and the item is always displayed. My guess is that win32com is not handling the [in,out] reference parameter correctly.

1
Max On

I had a similar problem and found a solution. Indeed win32com is handling this perfectly well. The client side implementation of the event handler function simply has to have the (new) value of the by-ref parameter as an (additional) return value. In my case, the COM server signature required an HRESULT return. By adding a second return value, I was able to manipulate the by-ref parameter as whished.