Introduction
First of all, let me warn you that I’m not a developer guy, I don’t have a rich development background, so please excuse me if I say things that are not absolutely true (regarding programming, of course) or less technically accurate for all of you programming gurus.
Some organizations choose to add a disclaimer to the end of every message that leaves the internal messaging system to the internet (and sometimes also to every internal message). These disclaimers can have different formats, but generally they have some legal content, stating that the person or group who sends the message holds no responsibility for misusing the contents of the message, and warning any potential recipient to destroy the message if he/she receives it by mistake. Technically speaking you can write whatever you want on the disclaimer and use it for any imaginable means that you can think of.
As disclaimer use grew in popularity, Microsoft decided to provide a way of adding this kind of functionality to Exchange Server. Back in the Exchange 5.5 days, Microsoft developed a specific DLL for this purpose – IMSEXT.DLL – and made it available to the public in general. The use of this DLL was not supported, but at least people had a way of adding disclaimers without buying third-party software.
The use of this DLL involved adding the text in Rich Text Format (RTF) to a specific value in the Windows Registry, so it was not very user friendly.
When Microsoft Exchange 2000 was released it broke that DLL functionality, so Microsoft came up with a new method for adding disclaimers: through the use of SMTP event sinks.
SMTP Event Sinks
At first there was the Exchange 5.5 Event Service. This service was soon replaced with the advent of the new Windows 2000 SMTP service (on which Exchange 200x relies on), which introduced event sinks
Event sinks are used to extend and modify the behavior of the Windows 200x SMTP service.
An SMTP service event is the occurrence of some activity within the SMTP service, such as the transmission or arrival of an SMTP command or the submission of a message into the SMTP service transport component. When a particular event occurs, the SMTP service uses an event dispatcher to notify registered event sinks of the event.
Exchange 200x supports three general category service events:
- Protocol Events: protocol events occur at the SMTP command verb level between the client and the server when commands are either received or transmitted over the network, such as the delivery of a message locally or externally.
- Transport Events: transport events occur when the SMTP service receives a message, and that message passes through the SMTP stack.
- Store Events: store events are used to build procedures that react to events in the Exchange store.
The first two are independent from Exchange, as they rely on the Windows 200x SMTP service.
Disclaimer wizardry
If you want to add a disclaimer to all your outgoing messages there are two Knowledge Base (KB) articles (Q317680 and Q317327) with detailed instructions on how to do that, using either VBScript or building a specific DLL with Visual Basic. They are not difficult to follow, but if you don’t have a programming background (like me) I would recommend that you start with the VBScript one.
What I’m going to explain next is how you can extend the provided samples to add extra functionality. In order not to make this article very long I’ll just provide an example of how to add different disclaimers, based on the sender’s domain.
Let’s imagine the Oil&Vinegar Corporation which has 2 major divisions: Oil and Vinegar. Each division has its own SMTP Domain: oil.pt and vinegar.pt (I’ll use my home country top level domain, PT, for demonstrating purposes, because those domains don’t actually exist at the time I’m writing this). Since those divisions are quite independent, they need different disclaimers for legal reasons.
The challenge here is that the company has a centralized Exchange infrastructure, so the messaging administrator will have to figure out a way of doing this through the use of event sinks.
If we carefully examine the code provided by Microsoft in the two KB articles mentioned above, we notice that the IMessage interface is used to make some decisions. So after doing some research we discover that the IMessage interface implements several methods and properties that can be very useful in this case. The From Property (the e-mail addresses of the principal author or authors of this message) is an excellent candidate to use.
Using the provided code from Microsoft, we can now do some modifications to reach the proposed objective. Let’s see how the modified VBScript and Visual Basic codes look like:
VBSCRIPT
<SCRIPT LANGUAGE=”VBScript”>
Sub ISMTPOnArrival_OnArrival(ByVal Msg, EventStatus)
OILTextDisclaimer = vbCrLf & “DISCLAIMER:” & OIL Division Sample Disclaimer.”
OILHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>OIL Division Sample Disclaimer.”
VINEGARTextDisclaimer = vbCrLf & “DISCLAIMER:” & VINEGAR Division Sample Disclaimer.”
VINEGARHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>VINEGAR Division Sample Disclaimer.”
GENTextDisclaimer = vbCrLf & “DISCLAIMER:” & “Generic Sample Disclaimer.”
GENHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>Generic Sample Disclaimer.”
If Msg.HTMLBody <> “” Then
‘Search for the “</body>” tag and insert our disclaimer before that tag.
pos = InStr(1, Msg.HTMLBody, “</body>”, vbTextCompare)
szPartI = Left(Msg.HTMLBody, pos – 1)
szPartII = Right(Msg.HTMLBody, Len(Msg.HTMLBody) – (pos – 1))
If InStr(1, Msg.From, “@oil.pt”, 1) Then
Msg.HTMLBody = szPartI + OILAMPLER.HTMLBody = szPartI + BICHTMLDisclaimer + szPartII
ElseIf InStr(1, Msg.From, “@vinegar.pt”, 1) Then
Msg.HTMLBody = szPartI + VINEGARHTMLDisclaimer + szPartII
Else
Msg.HTMLBody = szPartI + GENHTMLDisclaimer + szPartII
End If
End If
If Msg.TextBody <> “” Then
If InStr(1, Msg.From, “@oil.pt”, 1) Then
Msg.TextBody = Msg.TextBody & vbCrLf & OILTextDisclaimer & vbCrLf
ElseIf InStr(1, Msg.From, “@vinegar.pt”, 1) Then
Msg.TextBody = Msg.TextBody & vbCrLf & VINEGARTextDisclaimer & vbCrLf
Else
Msg.TextBody = Msg.TextBody & vbCrLf & GENTextDisclaimer & vbCrLf
End If
End If
‘Commit the content changes to the transport ADO Stream object.
Msg.DataSource.Save ‘ Commit the changes into the transport Stream
pEventStatus = cdoRunNextSink
End Sub
</SCRIPT>
VISUAL BASIC
Dim OILTextDisclaimer As String
Dim OILHTMLDisclaimer As String
Dim VINEGARTextDisclaimer As String
Dim VINEGARHTMLDisclaimer As String
Dim GENTextDisclaimer As String
Dim GENHTMLDisclaimer As String
Implements IEventIsCacheable
Implements CDO.ISMTPOnArrival
Private Sub IEventIsCacheable_IsCacheable()
‘Just returns S_OK.
End Sub
Private Sub Class_Initialize()
‘TODO: Replace the sample disclaimer text with your own text.
OILTextDisclaimer = vbCrLf & “DISCLAIMER:” & OIL Division Sample Disclaimer.”
OILHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>OIL Division Sample Disclaimer.”
VINEGARTextDisclaimer = vbCrLf & “DISCLAIMER:” & VINEGAR Division Sample Disclaimer.”
VINEGARHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>VINEGAR Division Sample Disclaimer.”
GENTextDisclaimer = vbCrLf & “DISCLAIMER:” & “Generic Sample Disclaimer.”
GENHTMLDisclaimer = “<p></p><p>DISCLAIMER:<br>Generic Sample Disclaimer.”
End Sub
Private Sub ISMTPOnArrival_OnArrival(ByVal Msg As CDO.IMessage, EventStatus As CDO.CdoEventStatus)
If Msg.HTMLBody <> “” Then
Dim szPartI As String
Dim szPartII As String
Dim pos As Integer
‘Search for the “</body>” tag and insert the disclaimer before that tag.
pos = InStr(1, Msg.HTMLBody, “</body>”, vbTextCompare)
szPartI = Left(Msg.HTMLBody, pos – 1)
szPartII = Right(Msg.HTMLBody, Len(Msg.HTMLBody) – (pos – 1))
If InStr(1, Msg.From, “@oil.pt”, vbTextCompare) Then
Msg.HTMLBody = szPartI + OILAMPLER InStr(1, Msg.From, “@bicHTMLDisclaimer + szPartII
ElseIf InStr(1, Msg.From, “@vinegar.pt”, vbTextCompare) Then
Msg.HTMLBody = szPartI + VINEGARHTMLDisclaimer + szPartII
Else
Msg.HTMLBody = szPartI + GENHTMLDisclaimer + szPartII
End If
End If
If Msg.TextBody <> “” Then
If InStr(1, Msg.From, “@oil.pt”, vbTextCompare) Then
Msg.TextBody = Msg.TextBody & vbCrLf & OILTextDisclaimer & vbCrLf
ElseIf InStr(1, Msg.From, “@vinegar.pt”, vbTextCompare) Then
Msg.TextBody = Msg.TextBody & vbCrLf & VINEGARTextDisclaimer & vbCrLf
Else
Msg.TextBody = Msg.TextBody & vbCrLf & GENTextDisclaimer & vbCrLf
End If
End If
‘Commit the content changes to the transport ADO Stream object.
Msg.DataSource.Save
EventStatus = cdoRunNextSink
End Sub
The final step is registering the event sink. In order to do this you’ll have to use the smtpreg.vbs script provided by Microsoft. From a command prompt run the following commands:
cscript smtpreg.vbs /add 1 onarrival SMTPScriptingHost CDO.SS_SMTPOnArrivalSink “mail from=*”
cscript smtpreg.vbs /setprop 1 onarrival SMTPScriptingHost Sink ScriptName “C:\EventSinkScript.vbs”
(You can omit the “mail from=*” if you want, it will still work).
Please read Q317680 and Q317327 for further details.
Performance issues
Before putting this stuff on a production server (by the way, you should use your external bridge-head server, since all external mail flows through it), you may wonder which of the provided solutions – VBScript or Visual Basic – has more performance.
In order to answer that question I ran a script (see bellow) that sends a total of 5,000 messages, 2,500 from each of the SMTP domains – oil.pt and vinegar.pt.
For i = 0 To 2500
Set objEmail = CreateObject(“CDO.Message”)
objEmail.From = “[email protected]”
objEmail.To = “[email protected]”
objEmail.Subject = “OIL disclaimer test”
‘objEmail.Textbody = “Just a regular message body text…”
objEmail.CreateMHTMLBody (“http://localhost/body.htm”)
objEmail.AddAttachment “file://C:\Disclaimers\attach.dummy”
objEmail.Send
objEmail.From = “[email protected]”
objEmail.To = “[email protected]”
objEmail.Subject = “VINEGAR disclaimer test”
‘objEmail.Textbody = ” Just a regular message body text…”
objEmail.CreateMHTMLBody (“http://localhost/body.htm”)
objEmail.AddAttachment “file://C:\Disclaimers\attach.dummy”
objEmail.Send
wscript.echo i
Next
I ran this script twice, once using VBScript and the second time using the DLL built from Visual Basic. While performing the tests I took some measures using Performance Monitor. I must say that I expected much different results from the ones I got. In my mind the VBScript should be much slower than the DLL.
Let’s take a look at the results:
Figure 1: DLL (Visual Basic)
Figure 2: VBScript
Notice the total time taken: VBScript took 9 minutes to send the 5,000 messages, while Visual Basic DLL spent almost 15 minutes. Besides that we can conclude that both methods are very disk intensive and that VBScript will burn more CPU (but it will do it in less time).
I strongly advise you to make your own measures and do some research if you can improve the DLL compilation process.
Third party products
If you don’t want to bother with developing your own solution, you can always use third party products. I’ll mention just a few: ExClaimer, GFI MailEssentials, MailDisclaimer and mxClaim. I’m sure that you can found some more if you search on the internet. Most of these products will add extra functionality that you may or may not use. GFI MailEssentials will provide you disclaimer functionality for free, after the trial period ends.
Conclusion
From my community experience, the process of adding a disclaimer to Exchange is one of the most asked questions. So I’m hopping that now more people will know how to use it. In this article I also showed you how to extend the code provided as an example by Microsoft. I’m sure that much more functionality can be added, just by using the IMessage methods and properties, so why don’t you give it a try?
NOTE: For single server configurations there is an issue that may prevent the described method from working as expected. Microsoft had a KB article – Q288756: SMTP Transport Event Does Not Fire For MAPI Messages – which was retired because the provided workaround (creating a second SMTP Virtual Server) did not always worked in a reliable way. The problem occurs for mail that is sent by using a MAPI client, such as Outlook, which is not in SMTP format, therefore changes that are made by the event’s code are not persisted.
If you are in this situation, my advice is for you to use a third party product.
Useful Links
How to add a disclaimer to outgoing SMTP messages in Visual Basic script
http://support.microsoft.com/?kbid=317680
How to add a disclaimer to outgoing SMTP messages in Visual Basic
http://support.microsoft.com/?kbid=317327
IMessage Interface
http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_cdo_imessage_interface.asp
Microsoft Windows 2000 SMTP Service Events
http://go.microsoft.com/fwlink/?LinkId=12279
XFOR: Installing Internet Mail Service Extension Imsext.dll
http://support.microsoft.com/?kbid=258206
XIMS: Internet Mail Service Extension Message Text Append and Prepend
http://support.microsoft.com/?kbid=262097