Click here to Skip to main content
13,558,778 members
Click here to Skip to main content
Add your own
alternative version


30 bookmarked
Posted 2 Feb 2007

Developing Managed Event Sinks for Exchange Server Using Visual Basic.Net

, 2 Feb 2007
Rate this:
Please Sign up or sign in to vote.
Developing Managed Event Sinks for Exchange Server using VB.Net


I use Event Sinks with Exchange Server 2003 frequently. Most of these were written in VB6 and I wanted to begin migrating them over to .Net and use Visual Studio 2005 as the development tool. In searching for coding help I encountered the article Developing Managed Event Sinks/Hooks for Exchange Server Store using C# by Logu Krishnan here at The Code Project. Although written in C# it was very illuminating as to the process required. The steps to do this project in VB.Net are not drastically different but they do require some differences. When I searched other areas for code samples, I never found any that did as good a job as Logu Krishnan had done with his article.

Exchange Store Events

This article focuses on Asynchronous Events. Specifically the events are OnSyncSave and OnSyncDelete. The article by Logu Krishnan previously referenced has an excellent description of Exchange Store Events.

The Purpose of the Sink

This sink is designed to be implemented against a mail enabled public folder. It fires each time a message is saved or deleted in the folder. The code extracts any attachments from the message, saves them to a target network location, copies the message to a sub folder named "Processed" and then deletes it from the original folder. I have not included the code for actually processing the attachment but it is fairly straightforward and I do a variety of tasks with the attachments based on the purpose of the folder. I have included detailed steps to create and implement the sink.

Create the Project

Create your project using the Windows Class Library template. I have named this project EventSinkNet.

Mark for COM Interop

Be sure to mark the project to Register for Comp Interop by clicking on Project from the menu, choosing EventSinkNet Properties, selecting the Compile tab on the left and clicking on Register for COM Interop at the bottom.

Copy Required Files to Project

  • Copy adodb.dll (file version 7.10.3077.0) from \Program Files\Microsoft.NET\Primary Interop.Assemblies to project directory.
  • Copy codex.dll (Microsoft CDO for Microsoft Exchange Library - file version 6.5.7650.29) from \Program Files\Common Files\Microsoft Shared\CDO\cdoex.dll. This was on my Exchange Server.
  • Copy exoledb.dll (Microsoft Exchange OLEDB Server - file version 6.5.7651.60) from \exchsrvr\bin\exoledb.dll). This was on my Exchange Server.
  • Copy exevtsnk.tlb (Type Library - Size 11,976 bytes) from \Program Files\Exchange SDK\SDK\Support\OLEDB\exevtsnk.tlb

Create Strong Name Keys

Use the Visual Studio Command Prompt and navigate to the project folder. Create the strong name keys with the following commands.

  1. sn.exe -k adodb.key
  2. sn.exe -k cdoex.key
  3. sn.exe -k exoledb.key
  4. sn.exe -k exevtsnk.key

Create Interop Assemblies

  • Open the Visual Studio 2005 Command Prompt and navigate to the project folder.
  • Key in the following command to create the exoledb assembly
    tlbimp exoledb.dll /keyfile:exoledb.key /out:interop.exoledb.dll

    The output from the command may be reflect the following error but can be ignored

  • Key in the following command to create the cdoex assembly

    tlbimp cdoex.dll /keyfile:cdoex.key /out:interop.cdoex.dll

    The output from the command should reflect the following

  • Key in the following command to create the exevtsnk assembly

    tlbimp exevtsnk.dll /keyfile:exevtsnk.key /out:interop.exevtsnk.dll

    The output from the command may be reflect the following error but can be ignored

Add References to Your Project

Add references to the four dll's that are in your project directory.

Add a reference to System.EnterpriseServices

Your reference section in you Solution Explorer should appear as follows

Modify the AssemblyInfo.vb File

Add the following to the top of the file

Imports System.EnterpriseServices

Insert the following lines

[Assembly: AssemblyKeyFile(
[Assembly: AssemblyKeyName(
[Assembly: ApplicationActivation(ActivationOption.Server)>
[Assembly: ApplicationName(

The Code

The sink acts on each message after it is saved to the store. It opens each message and extracts each attachment to a file on a network share. It then copies the message to a subfolder named "Processed" and deletes the original message.

Option Explicit On
Option Strict On

'Add project references to the System.EnterpriseServices, 
'ADODB, Interop.Exoledb, and SignedExevtsnk .NET components.
Imports System.IO
Imports System.EnterpriseServices
Imports Exoledb = Interop.Exoledb
Imports ExevtsnkLib = Interop.Exevtsnk
Imports CDO = Interop.cdoex
Imports ADODB

Namespace EvSink
    Public Class ASyncEvents
        Inherits ServicedComponent
        Implements Exoledb.IExStoreAsyncEvents

        ' Logfile path.
        Private Const LOGFILE As String = "C:\\evtlog.txt"
        Private Const WORKPATH As String = "\\apps00\

        Public Sub OnDelete(ByVal pEventInfo As interop
            .exoledb.IExStoreEventInfo, _
            ByVal bstrURLItem As String, ByVal lFlags 
            As Integer) _
            Implements interop.exoledb.IExStoreAsyncEvents
            ' do something here 
        End Sub

        Public Sub OnSave(ByVal pEventInfo As interop
            .exoledb.IExStoreEventInfo, _
            ByVal bstrURLItem As String, ByVal lFlags 
            As Integer) _
            Implements interop.exoledb.IExStoreAsyncEvents
            Dim sr As StreamWriter
            Dim msg As CDO.IMessage = New CDO.Message
            Dim atch As CDO.IBodyPart

            Dim rec As ADODB.Record
            Dim i As Integer
            Dim sURLSuffix As String
            Dim sURLPrefix As String
            Dim sURLItemTo As String
            Dim sAtch As String

            ' Open the log file, append text to file.
            sr = File.AppendText(LOGFILE)
            sr.WriteLine("In onsave")
            ' Parse out the components of the URL
            i = InStrRev(bstrURLItem, "/", -1, 
            sURLSuffix = Right(bstrURLItem, Len(
                bstrURLItem) - i)
            sURLPrefix = Left(bstrURLItem, i)
            sURLItemTo = sURLPrefix & "processed/" & 

            ' Get the message
                msg.DataSource.Open(bstrURLItem, _
                             Nothing, _
                             ConnectModeEnum.adModeRead, _
                                .adFailIfNotExists, _
                                .adOpenSource, _
                             Nothing, Nothing)
                sr.WriteLine("Opened message")
                ' process it
                If msg.Attachments.Count > 0 Then
                    For Each atch In msg.Attachments
                        sAtch = atch.FileName
                        atch.SaveToFile(WORKPATH & sAtch)
                        sr.WriteLine("Saved as: " & sAtch)

                End If
                ' save it to processed folder
                sr.WriteLine("Saved to: " & sURLItemTo)
                atch = Nothing
                msg = Nothing

                ' delete it
                rec = New ADODB.Record
                rec.Open(sURLPrefix, , ConnectModeEnum
                sr.WriteLine("Deleted record")
            Catch ex As Exception
                sr.WriteLine("Record Delete Exception 
                    message: " & ex.Message)
            End Try
        End Sub
    End Class
End Namespace

Create a Key Pair for the DLL

sn -k EventSinkNet.snk

Compile and Copy

I had to manually copy the adodb.dll to my Debug folder. Now copy the files from your Debug or Release folder to a folder on the Exchange Server.

Register the Assembly

On the Exchange Server, open a command prompt in the folder containing the sink. Run the regasm.exe command as shown below. The command should indicate "Types registered successfully".

Regasm.exe EventSinkNet.dll /codebase 

Create the Component Service

Open the Administrative Tools/Component Services to install the dll. I create an empty application named "EventSinkNet" and clicked through the default options. I assigned a user to the Application Identity account to run the sink.

Install the Component

I then installed the component by select the Component Folder under the new component named "EventSinkNet" and choosing the "New" option under the properties. I selected "Import component(s) that are already registered" and located the component named EventSinkNet.EvSink.ASyncEvents.

Register the Sink

The sink can be registered to any Exchange folder. A script file like the one below can be used to register the sink or you can use Exchange Explorer with comes with the Exchange SDK.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Andy McNiece
Web Developer
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralRe: I need help please Pin
Andy McNiece23-Jul-07 6:52
memberAndy McNiece23-Jul-07 6:52 
GeneralRe: I need help please - (answer from kizzik) Pin
boaz.jan23-Jul-07 11:00
memberboaz.jan23-Jul-07 11:00 
GeneralRe: I need help please - (answer from kizzik) Pin
Andy McNiece24-Jul-07 6:11
memberAndy McNiece24-Jul-07 6:11 
GeneralRe: I need help please - (answer from kizzik) Pin
boaz.jan24-Jul-07 7:24
memberboaz.jan24-Jul-07 7:24 
GeneralRe: I need help please - (answer from kizzik) Pin
Andy McNiece24-Jul-07 7:40
memberAndy McNiece24-Jul-07 7:40 
GeneralRe: I need help please - (answer from kizzik) Pin
boaz.jan24-Jul-07 8:43
memberboaz.jan24-Jul-07 8:43 
GeneralRe: I need help please - (answer from kizzik) Pin
galets14-Sep-07 8:45
membergalets14-Sep-07 8:45 
I have similar issue. I'm trying to register an event sink for OnSave on all mailboxes. I can do it individually with "-m DEEP" switch, and I can also register it on system mailbox with "-m DEEP" switch, but it won't get trigered. I suspect I need to use the "-m ANY", but this produces me following error:

C:\MyTest\2007\exsink\batch>cscript regevent.vbs add "onsave;ondelete" ExSink.ExchangeEventSink.1 "f
BF7}/StoreEvents/GlobalEvents/ExSink" -m ANY
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

New Event Binding created:
Event: onsave;ondelete
Sink: ExSink.ExchangeEventSink.1
FullBindingUrl: file://./backofficestorage/ADMIN/SILVERWARE.LOCAL/MBX/SystemMailbox{65B3C39C-E0D3-4D

Error Commiting Transaction : -2141913020 Event Registration failure: The %1 specified contains an i
nvalid matchscope value.


GeneralRe: I need help please - (answer from kizzik) Pin
galets14-Sep-07 12:36
membergalets14-Sep-07 12:36 
GeneralRe: I need help please - (answer from kizzik) Pin
Dabu125-Jan-08 1:19
memberDabu125-Jan-08 1:19 
GeneralOnSave Event Sink Pin
dbristow23-Apr-07 5:12
memberdbristow23-Apr-07 5:12 
GeneralRe: OnSave Event Sink Pin
Andy McNiece23-Apr-07 12:49
memberAndy McNiece23-Apr-07 12:49 
GeneralRe: OnSave Event Sink Pin
dbristow23-Apr-07 21:26
memberdbristow23-Apr-07 21:26 
Generalhrm Pin
scorpydude11-Feb-07 12:15
memberscorpydude11-Feb-07 12:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03-2016 | 2.8.180515.1 | Last Updated 2 Feb 2007
Article Copyright 2007 by Andy McNiece
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid