Welcome!

Microsoft Cloud Authors: Pat Romanski, Andreas Grabner, Nick Basinger, Kevin Benedict, Liz McMillan

Related Topics: Microsoft Cloud

Microsoft Cloud: Article

Developing for Outlook with the .NET Framework

It's for more than just your e-mail!

Microsoft Outlook has an object model that's useful for automating any of the objects that it manages. Items like calendar entries, e-mails and tasks are well designed, but sometimes they don't provide all the functionality that we'd like. For instance, Outlook doesn't provide an easy way to assign a different e-mail background for each of your contacts. Thankfully, Outlook exposes its object model so you can build your own extensions to it. Unfortunately, because it has such a well-designed extensible object model, it's the target of a hoard of viruses and is therefore protected with a security model. This article is designed to help you understand some of the problems involved in developing for Outlook with the .NET Framework, as well as give you some pointers to helpful articles for future development.

Creating Your First Outlook Plug-in
Creating plug-ins for Outlook is identical to creating plug-ins for any other Office application. Follow these steps to create your application:

  1. Start up Visual Studio.NET 2003
  2. Expand the "Other Projects Folder" and select the "Extensibility Projects" folder
  3. Select "Shared Add-In" as the project type
  4. Give the Project a name (e.g., OutlookAutomation), and make sure you have the "Create Directory For Solution" checkbox checked
  5. Click OK, and follow the steps in the wizard
  6. When prompted, uncheck all the "Hosts" except for "Microsoft Outlook"
  7. Give your application a name and description. These values will appear in the "Add-ins" section of Outlook
  8. Finally, make sure to check "I would like my Add-in to load when the host application loads" and finish the wizard.
Once you finish the wizard, you will have created two projects. The first project has the name you specified in Step 4, and is where all your code will go. The second is an installation project for your Outlook Add-in that will register your application with Outlook every time you rebuild and execute your application. It will make it easier for you to distribute your application to other people.

The entry point for your application is in the Connect class. This class implements the Extensibility.IDTExtensibility2 interface. This interface must be implemented for a class to be an Add-in to another application. This doesn't mean every class in your application must implement this interface. In fact, the Connect class should be the only class that implements this interface in your application. When your plug-in is registered with the application that will launch it, the application is told which object will be instantiated, and there can only be one.

To make sure everything is ready to go, place a breakpoint inside the OnConnection routine, and try to run the application. Outlook should launch, and then should pause (after a few seconds) at that breakpoint. If Outlook doesn't launch, and some other application like Visual Studio does, then you need to change the "Start Application" inside the "Configuration Properties/Debug" section of your project properties to the path and file name of Outlook.

The Outlook Security Model
When you try and run your Add-in, Outlook is launched. The first thing Outlook does when it launches is discover what Add-ins it's supposed to create, and then creates them. To run your Add-in, an instance of your Connect class will be created, and then each method in the Extensibility.IDTExtensibility2 interface will be called in a particular order. The only ones that I use, and probably the only ones you will use, are the OnConnection and OnBeginShutdown methods.

When Outlook calls OnConnection, it will pass on the most important object your Add-in will use: the Application object representing the Outlook Application. This object is important because this is the only instance of the Application class your Add-in is allowed to use. Most objects in the Outlook model have an Application property that gets a pointer to the Application object. If you use any of these properties to get at the Application object, your Add-in will be shut down because Outlook can't tell if your Add-in has authorized access. It can't tell the difference between your Add-in and some VB Script.

The first thing I do once a project is up is to open my Solution Explorer, right-click on "references" in the main project, click "add reference" and add a reference to the "Microsoft Outlook Objects" COM library. This makes the Outlook objects easier to get and manipulate in code. Then I create a static Application property (shared in Visual Basic) on the Connect object that exposes an Outlook.Application object. Then I change the OnConnection routine to store the application parameter in that property. This way, any other class in my project that needs access to the Application object has easy access to it:

//In constructor

Garbage Collection Gone Bad
Outlook is mostly used to send and receive e-mails. To get our code to register for events, such as when a new e-mail message is being created, we need to use Inspectors. An Inspector is a window that appears when you create a new Outlook object interactively. The Application object has a property called "Inspectors" that contains a list of all the currently open inspectors as well as an event that is raised when a new inspector is created: NewInspector. This event is easy to register for:

But, this event is raised whenever an item is opened, not just when a new item is created, so we need some filtering code to ensure that the new item is a new e-mail:

Notice that I catch any exceptions raised in this event handler. If Outlook finds your Add-in throws exceptions, it will disable it. So, in every routine that handles an event raised by Outlook, I put a try-catch block to ensure my application continues to operate.

Now, run your application (using the debugger) and create a new e-mail item. You will find that it will output "New Mail Item!" to the console. Close that Inspector, and create another mail item. No new text will be written to the console.

What happened? The Garbage Collector collected the delegate registered for the event. This problem is caused by a combination of the COM Callable Wrapper (CCW) generated by the .NET Runtime for interoperability with Outlook and the way we referenced the NewInspector event. When the Inspectors collection is accessed from the Application object, Outlook hands back an Inspectors object that the .NET Runtime tracks through a Runtime Callable Wrapper (RCW). Then when the application registers for the NewInspector event, a delegate is added to that event through a CCW. When the first event is raised, the delegate is called as expected. Unfortunately, as soon as the Runtime notices that the event has finished it runs the garbage collector; it cleans up the instance of the Inspectors class originally handed to the Runtime because there's no longer a reference to it. As a result, the delegate that points to the event handler is also cleaned up, and you no longer receive the event. This is illustrated in Figure 1. To fix this, the registration code in Snippet 2 needs to be changed to Snippet 4. Now the event will always be raised whenever a new e-mail is created.

Unfortunately, the Inspectors object is not the only place that this problem can occur. Any object that you register for an event on, but don't keep a reference to, can fail to raise the events you expect. To overcome this, I suggest a coding structure that keeps a reference to every Outlook object that gets returned by any de-reference of another Outlook object existing item. To do this we can create a series of wrappers that keeps track of a single instance of an Outlook object. Accompanying this article is an EmailWrapper class that I use to track all e-mails that I have open. Listing 5 shows code from my EmailWarapper constructor.

Notice that the two lines of code that register for events are substantially different. There's a problem with many of the objects exposed by Outlook; many classes in the Office object model have methods and events with exactly the same name. When the RCW definitions are generated for the office objects, the TlbImp tool (Type Library Importer) favors the methods in the definition. Thankfully, the TlbImp tool provides a way to get at the events: in this case the ItemEvents_Event interface that lists all the events exposed by that object. I can cast to this interface, and then register for the event I want.

More Outlook Security Model Pickiness
Starting with Outlook 97 Service Pack 2, Outlook got very picky about the objects that attach to it and use its objects. This is meant to help prevent scripts and viruses from spreading themselves through Outlook. But this security system gets in the way of legitimate applications that want to use the Outlook object model for constructive reasons. Luckily, there are some ways around the security system.

If you are producing add-ins for a corporate environment then there's a very straightforward solution. Create a COM shim to your add-in. You can look up the details for how to do this on msdn.microsoft.com, but be careful how you use it. A shim can be used in a corporate environment if the corporation has an Exchange server that specifies the security settings of each client. The Exchange server can be told that your particular shim is a valid add-in, and the shim will pass all of its calls to your .NET add-in. But be warned. Read the warnings associated with the shim carefully, otherwise you may make Outlook less secure.

If you are developing Add-ins for home users, who don't use an Exchange server to configure their client's security settings, then you should buy a program called "Outlook Redemption" (www.dimastr.com/redemption/). Because the Outlook security model only applies to the COM connectivity of Outlook, this allows you to connect through the MAPI protocol.

Outlook communicates with an Exchange server through MAPI, and everything that Outlook exposes through COM is also exposed through MAPI. Unfortunately, MAPI is a difficult protocol to learn and use and is usually developed through C and C++. However, Outlook Redemption communicates with Outlook through MAPI and exposes its actions through COM. This allows you to code as if you were interacting directly with Outlook through COM, but since it's really communicating through MAPI, Outlook doesn't stop your application because of security concerns.

The reason Outlook isn't concerned about MAPI-based automation is because it's difficult to build and use MAPI applications and most (if not all) virus writers would like to create and use the easy COM-based object model. If you are really courageous, you could learn MAPI so that you can write code that interfaces with Outlook directly, avoiding these security issues, but I wouldn't recommend it.

Conclusion
Outlook has a powerful object system, but its security system and COM/.NET interoperation get in the way of producing useful automation applications. The security system can be worked with through a shim or with "Outlook Redemption." By always having references to all the COM objects you get from Outlook, you can avoid problems that garbage collection can cause to surface. Knowing about these problems before you create .NET add-ins can help you avoid headaches during development and deployment.

More Stories By Richard Arthur

Richard Arthur is currently an instructor of C# at Northface University (www.northface.edu) in Salt Lake City, Utah. He has gained extensive experience doing Automation of MS Office products through VBA and COM at previous jobs.
In his spare time he learns about the inner workings of many current and future .NET Technologies, including Windows Forms, ASP.NET, Generics, P/Invoke, and COM Interoperability.
If anyone has any questions regarding this article, please contact Richard at [email protected]

Comments (1)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


IoT & Smart Cities Stories
Moroccanoil®, the global leader in oil-infused beauty, is thrilled to announce the NEW Moroccanoil Color Depositing Masks, a collection of dual-benefit hair masks that deposit pure pigments while providing the treatment benefits of a deep conditioning mask. The collection consists of seven curated shades for commitment-free, beautifully-colored hair that looks and feels healthy.
The textured-hair category is inarguably the hottest in the haircare space today. This has been driven by the proliferation of founder brands started by curly and coily consumers and savvy consumers who increasingly want products specifically for their texture type. This trend is underscored by the latest insights from NaturallyCurly's 2018 TextureTrends report, released today. According to the 2018 TextureTrends Report, more than 80 percent of women with curly and coily hair say they purcha...
The textured-hair category is inarguably the hottest in the haircare space today. This has been driven by the proliferation of founder brands started by curly and coily consumers and savvy consumers who increasingly want products specifically for their texture type. This trend is underscored by the latest insights from NaturallyCurly's 2018 TextureTrends report, released today. According to the 2018 TextureTrends Report, more than 80 percent of women with curly and coily hair say they purcha...
We all love the many benefits of natural plant oils, used as a deap treatment before shampooing, at home or at the beach, but is there an all-in-one solution for everyday intensive nutrition and modern styling?I am passionate about the benefits of natural extracts with tried-and-tested results, which I have used to develop my own brand (lemon for its acid ph, wheat germ for its fortifying action…). I wanted a product which combined caring and styling effects, and which could be used after shampo...
The platform combines the strengths of Singtel's extensive, intelligent network capabilities with Microsoft's cloud expertise to create a unique solution that sets new standards for IoT applications," said Mr Diomedes Kastanis, Head of IoT at Singtel. "Our solution provides speed, transparency and flexibility, paving the way for a more pervasive use of IoT to accelerate enterprises' digitalisation efforts. AI-powered intelligent connectivity over Microsoft Azure will be the fastest connected pat...
There are many examples of disruption in consumer space – Uber disrupting the cab industry, Airbnb disrupting the hospitality industry and so on; but have you wondered who is disrupting support and operations? AISERA helps make businesses and customers successful by offering consumer-like user experience for support and operations. We have built the world’s first AI-driven IT / HR / Cloud / Customer Support and Operations solution.
Codete accelerates their clients growth through technological expertise and experience. Codite team works with organizations to meet the challenges that digitalization presents. Their clients include digital start-ups as well as established enterprises in the IT industry. To stay competitive in a highly innovative IT industry, strong R&D departments and bold spin-off initiatives is a must. Codete Data Science and Software Architects teams help corporate clients to stay up to date with the mod...
At CloudEXPO Silicon Valley, June 24-26, 2019, Digital Transformation (DX) is a major focus with expanded DevOpsSUMMIT and FinTechEXPO programs within the DXWorldEXPO agenda. Successful transformation requires a laser focus on being data-driven and on using all the tools available that enable transformation if they plan to survive over the long term. A total of 88% of Fortune 500 companies from a generation ago are now out of business. Only 12% still survive. Similar percentages are found throug...
Druva is the global leader in Cloud Data Protection and Management, delivering the industry's first data management-as-a-service solution that aggregates data from endpoints, servers and cloud applications and leverages the public cloud to offer a single pane of glass to enable data protection, governance and intelligence-dramatically increasing the availability and visibility of business critical information, while reducing the risk, cost and complexity of managing and protecting it. Druva's...
BMC has unmatched experience in IT management, supporting 92 of the Forbes Global 100, and earning recognition as an ITSM Gartner Magic Quadrant Leader for five years running. Our solutions offer speed, agility, and efficiency to tackle business challenges in the areas of service management, automation, operations, and the mainframe.