InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

HOWTO: Customize Delivery Status Notifications generated by Microsoft Exchange

More Information

As this blog points out, it is sometimes necessary to control the generation of delivery status notifications, for example if the Exchange Server is responsible for multiple domains. In this case, Exchange uses the default SMTP domain as the sender for DSNs.

The blog entry briefly describes the necessary steps but it turns out that the entire process of registering the sink is poorly documented. Additionally diffculties arose because I wanted to implement the sink with managed code.

Also Microsoft offers an example on how to implement managed transport event sinks and also includes the necessary type libraries, this library lacks the necesssary interface definitions required for the OnSyncGenerateDSN event sink.

This implementation changes the domain for the DSN to the domain of the first recipient of the original mal.

Solution

The first step was to generate a type library which contains the interface definitions for the event sink. To do this, I modified the smtpevent.idl file, which is included in the Platform SDK. The modified version is attached to this article.

I compiled the modified smtpevent.idl with the MIDL compiler and created an interop assembly with the Type library import utility (tlbimp.exe).

Unfortunately, some of the methods are incorrectly marshalled, and thus, can't be used. So, the next step is to decompile the generated assembly with ildasm.exe, correct the definition of the methods and recompile the source with the ilasm.exe compiler. The modified interop dll is also attached to this article.

The implemention of the actual interface is the most easy part of the entire process. The only method that has to be implemented is the IDSNGenerationSink.OnSyncGenerateDSN:

    1 public void OnSyncGenerateDSN(ISMTPServer pISMTPServer, IDSNSubmission pIDSNSubmission, IMailMsgProperties pIMsg, IMailMsgPropertyBag pIDSNProperties, IDSNRecipientIterator pIRecipIter)

    2 {

    3     StringBuilder sb;

    4     IMailMsgRecipientsBase recipients;

    5     string domain;

    6 

    7     Trace.WriteLine("[DSNRewriter] OnSyncGenerateDSN called");

    8     try

    9     {

   10         recipients = (IMailMsgRecipientsBase)pIMsg;

   11 

   12         sb = new StringBuilder(512);

   13         try

   14         {

   15             recipients.Item(0, (uint)_CAT_ADDRESS_TYPE.CAT_SMTP, 512, sb);

   16             domain = sb.ToString();

   17             domain = domain.Substring(domain.IndexOf("@") + 1);

   18 

   19             Trace.WriteLine("[DSNRewriter] Domain of first recipient is: " + domain);

   20 

   21             Trace.WriteLine("[DSNRewriter] Setting default domain to " + domain);

   22             pIDSNProperties.PutStringA((uint)eDSNProperties.DSNPROP_SZ_DEFAULTDOMAIN, domain);

   23             Trace.WriteLine("[DSNRewriter] Done");

   24         }

   25         catch (Exception ex)

   26         {

   27             Trace.WriteLine("[DSNRewriter] The following exceptions occured: " + ex.ToString());

   28         }

   29 

   30     }

   31     catch (Exception ex)

   32     {

   33         Trace.WriteLine("[DSNRewriter] Failed. Exception: " + ex.ToString());

   34     }

   35 }

This implementation sets the domain for the DSN to the domain of the first recipient of the original message.

After the code has been compiled to an assembly it must be registered on the Exchange server with the regasm.exe utility.

The final step is the registration of the event sink within the store. Again, Microsoft offers a script which handles registration, unregistration and enumeration of SMTP event sinks. And again, this script lacks the functionality to register DSN related event sinks. A modified version of this script is also attached to this article.

To register the event sink run the modified smtpevent.vbs with the following parameters:

    1 csript smtpevent.vbs /add 1 dsngenerationsink dsnrewriter dsnrewriter.dsnrewriter ehlo=*

This installs the event sink on the first SMTP virtual server.

To uninstall the event sink, run the following command:

    1 cscript smtpevent.vbs /remove 1 dsngenerationsink dsnrewriter

Remarks

  • If you want to modify the interop DLLs or the implementation of the event sink, you must sign them with a strong name. Use the sn.exe utility to create one. The attached binary is signed with a key that is, for obvious reasons, not included in the attached files.
  • The example implementation does not write any log files. Trace output is, however, written to the Windows debug interface. You can use DebugView from Sysinternals to view this trace output.

Downloads

SMTPInterop.zip (64,375 Bytes)
Modified interop files
Binaries.zip (17,054 Bytes)
Binary of the described implementation
DsnRewriter.zip (56,221 Bytes)
Sourcecode as Visual Studio 2003 Project
SMTPEventScript.zip (6,775 Bytes)
Modified SMTPEvent.vbs management script

Technorati:

Posted by Henning Krause on Sunday, June 26, 2005 12:00 AM, last modified on Monday, December 26, 2005 12:00 PM
Permalink | Post RSSRSS comment feed

Comments (1) -

On 8/29/2008 3:56:29 PM rednael wrote:

rednael

To all who need more information on writing managed event sinks (for IIS SMTP or Exchange), please take a look at my blog.
http://blog.rednael.com/

There is a very in depth article on How to write a custom authentication sink (using the AUTH command). It addresses various problems that are solved when writing event sinks.

For example, how do you read input lines after the AUTH command is processed.
And how do you use the property bags within a session.
And more...

Also, there is a list of registry settings for IIS SMTP (as well as Exchange 2000/2003), with which you can influence the behavior of the SMTP server.

Enjoy...