delphicomoleoutlook-object-model

Outlook Object Model - Detecting if email has been sent


I have the following code in my test Delphi 2006 BDS application:

procedure TForm1.Button1Click(Sender: TObject);
const
  olMailItem = 0;
var
  Outlook: OleVariant;
  vMailItem: variant;
begin
  Outlook := CreateOleObject('Outlook.Application');
  vMailItem := Outlook.CreateItem(olMailItem);

  try
    vMailItem.Recipients.add('anemailaddress@gmail.com');
    vMailItem.Display(True); -- outlook mail message is displayed modally
  except
  end;

  VarClear(Outlook);
end;

I need to be able to detect whether the user sent the email from within the outlook screen. I tried the following code:

if vMailItem.Sent then
 ...

But received the error message 'The item has been moved or deleted'. I presume this is because the mail item has moved to the sent items folder. What is the best way to detect if the user sent the email? Also, if the user did send the email then I would also need to be able to view the email body.

Thanks in advance.


Solution

  • It would seem you have to use the Send Event of the mail item. This would be a lot easier if you were using early binding, put one of the 'outlook[*].pas' files in the '..\OCX\Servers' folder of RAD studio in the 'uses' clause, then:

    uses
      ..., outlook2000;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        OutlookApplication: TOutlookApplication;
        procedure OnMailSend(Sender: TObject; var Cancel: WordBool);
      public
      end;
    
    [...]
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      OutlookApplication := TOutlookApplication.Create(Self);
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      MailItem: _MailItem;
      Mail: TMailItem;
    begin
      MailItem := OutlookApplication.CreateItem(olMailItem) as _MailItem;
    
      Mail := TMailItem.Create(nil);
      try
        Mail.ConnectTo(MailItem);
        Mail.OnSend := OnMailSend;
    
        MailItem.Recipients.Add('username@example.com');
        MailItem.Display(True);
      finally
        Mail.Free;
      end;
    end;
    
    procedure TForm1.OnMailSend(Sender: TObject; var Cancel: WordBool);
    begin
      ShowMessage((Sender as TMailItem).Body);
    end;
     
    


    With late binding, you'd have to do some of the work which the imported wrapper does. The simplest example could be something like this:

     
    type
      TForm1 = class(TForm, IDispatch)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        FCookie: Integer;
        FMailItem: OleVariant;
        procedure MailSent;
      protected
        function QueryInterface(const IID: TGUID; out Obj): HResult; override;
        function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
          Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult;
          stdcall;
      public
      end;
    
    [...]
    
    uses
      comobj;
    
    const
      DIID_ItemEvents: TGUID = '{0006303A-0000-0000-C000-000000000046}';
      SendItemDispID = 61445;
    
    function TForm1.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
      if IsEqualIID(IID, DIID_ItemEvents) and GetInterface(IDispatch, Obj) then
        Result := S_OK
      else
        Result := inherited QueryInterface(IID, Obj);
    end;
    
    function TForm1.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult;
    begin
      Result := S_OK;
      if DispID = SendItemDispID then
        MailSent;
    end;
    
    
    procedure TForm1.Button1Click(Sender: TObject);
    const
      olMailItem = 0;
    var
      Outlook: OleVariant;
      CPContainer: IConnectionPointContainer;
      ConnectionPoint: IConnectionPoint;
    begin
      Outlook := CreateOleObject('Outlook.Application');
      FMailItem := Outlook.CreateItem(olMailItem);
      FMailItem.Recipients.add('username@example.com');
    
      if Supports(FMailItem, IConnectionPointContainer, CPContainer) then begin
        CPContainer.FindConnectionPoint(DIID_ItemEvents, ConnectionPoint);
        if Assigned(ConnectionPoint) then
          ConnectionPoint.Advise(Self, FCookie);
        CPContainer := nil;
      end;
    
      FMailItem.Display(True);
    
      if Assigned(ConnectionPoint) then begin
        ConnectionPoint.Unadvise(FCookie);
        ConnectionPoint := nil;
      end;
    
      VarClear(FMailItem);
      VarClear(Outlook);
    end;
    
    procedure TForm1.MailSent;
    begin
      ShowMessage(FMailItem.Body);
    end;