Art  Delphi  Automation  History  Home  Politics  Email me Default Colours  Printable Colours

Automating Microsoft Outlook

Contents


Sources of information

Web sites

MAPI FAQ
Berend de Boer's Delphi page
Outlook from Delphi article by Bill Todd

For catching Outlook events, or general COM concepts, see also
Binh Ly's tutorials

For other (non-Delphi) Outlook help, see
The Outlook & Exchange Solutions Centre
Microsoft's guide to Outlook's object model
MS Visual Basic Programmer's Guide
Microsoft Developer's Network


How do I ... ?

The code in these examples was written with Outlook 98. If you're using Outlook 97 or Outlook 2000, you may find some differences.
Back to top

>>>>>How to start Outlook<<<<<

There are several different ways to start Outlook from your Delphi app.

You'll notice that just starting up the Outlook application is not enough to get going - you also have to get the namespace and call its Logon method, like this:

    NmSpace.Logon('', '', False, False);

I've used this line in the following code snippets, but note that you may have to supply different arguments to this method if you have user profiles set up on your computer. The Logon method takes four parameters: the first two, Profile and Password, are self-explanatory. The third, ShowDialog, lets you display a logon dialog for the user. If the fourth, NewSession, is set to True, a new MAPI session is started, rather than connecting to an existing one.

Bear in mind that when you've logged on you still won't see Outlook - until you display a folder, as shown in the following examples.

Using Delphi 5's components

Drop an OutlookApplication component on your form. When you want Outlook to start, use its Connect method:

  var
    NmSpace: NameSpace;
    Folder: MAPIFolder;
  ...
    OutlookApplication1.Connect;
    NmSpace := OutlookApplication1.GetNamespace('MAPI');
    NmSpace.Logon('', '', False, False);
    Folder := NmSpace.GetDefaultFolder(olFolderInbox);
    Folder.Display;

Because of the need to log on to the MAPI namespace when you start, there isn't much point in setting the OutlookApplication's AutoConnect property to True. And setting the ConnectKind property to ckRunningOrNew is fairly pointless, too - when you automate Outlook, you'll always get a new instance of it - although Outlook itself will use an existing MAPI session, if there is one.

Once Outlook has started, you can connect other components, such as a TMailItem, using the ConnectTo method. Here's an example:

  MailItem1.ConnectTo(OutlookApplication1.CreateItem(olMailItem) as MailItem); 


Opening Outlook (early binding)

Before you can use this method, you must have imported the Outlook type library (unless you have Delphi 5).

One way of starting Outlook is to try the GetActiveObject call, to get a running instance of Outlook, but put a call to CoApplication.Create in an except clause. But except clauses are slow, and can cause problems within the IDE for people who like Break On Exceptions set to True. The following code removes the need for a try...except clause, by avoiding using OleCheck on GetActiveObject in the case when Outlook is not running.

uses Windows, ComObj, ActiveX, 
            Outlook_TLB;  // Outlook8; for D5 users    
 
var 
  Outlook: _Application;  // OutlookApplication; for D5 users
  Unknown: IUnknown; 
  Result: HResult; 
  NmSpace: NameSpace;
  Folder: MAPIFolder;
begin 
  {$IFDEF VER120}      // Delphi 4
  Outlook := CoApplication_.Create;
  {$ELSE}              // Delphi 5
  Outlook := CoOutlookApplication.Create;
  {$ENDIF}  

  NmSpace := Outlook.GetNamespace('MAPI');
  NmSpace.Logon('', '', False, False);
  Folder := NmSpace.GetDefaultFolder(olFolderInbox);
  Folder.Display;
  ...

Without using the type library

Automation is so much easier and faster using type libraries (early binding) that you should avoid managing without if at all possible. But if you really can't, here's how to get started:

var 
  Outlook, NmSpace, Folder: OleVariant; 
begin 
  Outlook := CreateOleObject('Outlook.Application');    
  NmSpace := Outlook.GetNamespace('MAPI');
  NmSpace.Logon(EmptyParam, EmptyParam, False, True);
  Folder := NmSpace.GetDefaultFolder(olFolderInbox);
  Folder.Display;
 
Back to 'HowDoI'

>>>>>How to close Outlook<<<<<

Assuming your Outlook application variable is called Outlook, and the namespace variable you logged on with (see How to start Outlook) is NmSpace:

  NmSpace.Logoff;
  Outlook.Quit;
  Outlook.Disconnect;    // Using the D5 components
  { or }
  Outlook := nil;        // Early binding with interfaces  
  { or }
  Outlook := Unassigned; // Late binding with variants
Back to 'HowDoI'

>>>>>How to compose an email<<<<<

In early binding:

var
  MI: MailItem;
begin
  MI := Outlook.CreateItem(olMailItem) as MailItem;
  MI.Recipients.Add('Debs@djpate.freeserve.co.uk');
  MI.Subject := 'Greetings, O gorgeous one';
  MI.Body := 'Your web pages fill me with delight';
  MI.Attachments.Add('C:\CreditCardNo.txt', EmptyParam, EmptyParam, EmptyParam);
  MI.Send;

In late binding, MI has to be a variant, and it's constructed like this:

const
  olMailItem = 0;
var
  MI: Variant;
begin
  MI := Outlook.CreateItem(olMailItem);

The rest of the code is the same as in early binding.

In Outlook 98, you can also send HTML-formatted emails, by assigning the HTML as a string to the MailItem's HTMLBody property instead of the Body property. But this isn't possible with Outlook 97, and so can't be done with the D5 component either, unless you import the type library for Outlook 98 (MSOutl85.olb).

Unfortunately there doesn't seem to be any way to send true RTF-formatted emails.

Back to 'HowDoI'

>>>>>How to send and receive email<<<<<

This code activates the Tools|Send and Receive|All accounts menu item:

uses Office_TLB; // Office97 for D5 users
var
  ToolsMenu: CommandBar;
  SendRecMenuItem, AllAccs: CommandBarControl;
begin
  ToolsMenu := (Outlook.ActiveExplorer.CommandBars as CommandBars).Item['Tools'];
  
  // D5 users can omit the underscore after 'Controls' in the next two lines
  SendRecMenuItem := ToolsMenu.Controls_['Send and Receive'];
  AllAccs := (SendRecMenuItem.Control as CommandBarPopup).Controls_['All Accounts'];
  AllAccs.Execute;

If you're using Outlook 2000, you'll have to change 'Send and Receive', perhaps to 'Send/Receive'. (I've had one report that this works, one that it doesn't - perhaps there are spaces around the '/'? Any clarification of this would be very welcome! Pointless menu changes don't make automation any easier...)

Back to 'HowDoI'

>>>>>How to check for unread email<<<<<

  var
    Inbox: MAPIFolder;
    NewMail: boolean;
  ...
    Inbox := NmSpace.GetDefaultFolder(olFolderInbox);
    NewMail := (Inbox.UnreadItemCount > 0);
    if NewMail then
      ShowMessage(Format('Unread items in Inbox: %d', [Inbox.UnreadItemCount]));

The constant olFolderInbox is defined in Outlook_TLB as $00000006.

Back to 'HowDoI'

>>>>>How to check for unsent email<<<<<

  var
    Outbox: MAPIFolder;
    UnsentMail: integer;
  ...
    Outbox := NmSpace.GetDefaultFolder(olFolderOutbox);
    UnsentMail := Outbox.Items.Count;
    if (UnsentMail > 0) then
      ShowMessage(Format('Unsent items in Outbox: %d', [UnsentMail]));

The constant olFolderOutbox is defined in Outlook_TLB as $00000004.

Back to 'HowDoI'

Sample code to download