Click here to Skip to main content
Click here to Skip to main content
Go to top

Exchange Domain Mail SMTP Sink

, 1 Nov 2006
Rate this:
Please Sign up or sign in to vote.
How to create a domain mail sink for Exchange Server.

Active Directory Users and Computers - notice @foodcandy.com

Introduction

A while ago, I started running Microsoft Small Business Server with Microsoft Exchange 2003. I use Outlook with RPC over HTTP, synchronize with Exchange on my Smart Phone, and use OWA. I also host a few domains on my server.

When I signup for a service, I want to give service@mydomain.com as my e-mail address, so that I can block spam. It’s easy to add SMTP addresses to Active Directory accounts, but I have accounts on a thousand services! Hence the following question: how do I get *@mydomain.com routed in Exchange?

If you just want to install this sink, download the binaries and run RegisterSink.cmd. Add @domain.com to users that should receive all e-mail @domain.com. Run UnregisterSink to uninstall.

Background

These two articles are an excellent start, but I have more than one domain and I want this to be configurable.

What does this code do?

  • Implement IMailTransportSubmission::OnMessageSubmission to catch submitted e-mail messages.
  • Search for an Active Directory user that has an exactly matching mail or proxy address.
  • Search for an Active Directory user that has a matching @domain.com mail or proxy address.
  • Route e-mail accordingly.
  • Log routing events to the event log.

Implementation Details

Please note that the samples below are stripped of error checking. Please see the actual source code attached.

First, I had to follow the details in Writing Managed Sinks for SMTP and Transport Events and create the managed proxy objects to receive SMTP events.

Code to connect to Active Directory code is widely available. The slightly tricky parts are connecting to the RootDSE and finding the Users node.

//
// Root DSE and the Users LDAP path
//
 
mRootDSE = new DirectoryEntry(
 "LDAP://" + (DomainName.Length > 0 ? DomainName + "/" : string.Empty) +
 "RootDSE");
 
mUsersLDAPPath = "LDAP://" + 
 (DomainName.Length > 0 ? DomainName + "/" : string.Empty) + 
 "CN=Users," + RootDSE.Properties["defaultNamingContext"].Value;

When an e-mail arrives, it will be potentially re-routed. A new list of recipients must be created.

void IMailTransportSubmission.OnMessageSubmission(
 MailMsg message,
 IMailTransportNotify notify,
 IntPtr context)
{
 Message Msg = new Message(message);
 RecipsAdd NewRecipients = Msg.AllocNewList();
 bool fReRouted = false;
 
 foreach (Recip Recipient in Msg.Recips)
 {
     fReRouted |= ReRoute(Recipient, Msg, NewRecipients);
 }
 
 if (fReRouted)
 {
     Msg.WriteList(NewRecipients);
 }
 
 Marshal.ReleaseComObject(message);
}

And the meat of the re-routing:

private bool ReRoute(Recip Recipient, Message Msg, 
                     RecipsAdd NewRecipients)
{
     ActiveDirectory Directory = new ActiveDirectory();
 
     string[] SearcherPropertiesToLoad = { "cn", "mail", 
                                     "proxyAddresses" };
 
     DirectorySearcher Searcher = new DirectorySearcher(
      new DirectoryEntry(Directory.UsersLDAPPath),
      "(&(objectCategory=person)(objectClass=user)(| 
      (proxyAddresses=*smtp:@" + 
      Recipient.SMTPAddressDomain.ToLower() + 
      "*)(proxyAddresses=*smtp:" + 
      Recipient.SMTPAddress + "*)))",
      SearcherPropertiesToLoad);
 
     SearchResultCollection SearchResults = Searcher.FindAll();
 
     if (SearchResults.Count == 0) return false;
 
     foreach (SearchResult SearchResult in SearchResults)
     {
      foreach (string ProxyAddressProperty in 
               SearchResult.Properties["proxyAddresses"]) 
      {
       string ProxyAddress = ProxyAddressProperty.ToLower();
       if ("smtp:" + Recipient.SMTPAddress.ToLower() == 
                                           ProxyAddress)
       {
        // there's an address that matches
        // exactly, add him to the re-routing
        // list because there might be other
        // recipients that don't match and
        // will require routing
        NewRecipients.AddSMTPRecipient(
               Recipient.SMTPAddress, null);
        return false;
       }
      }
     }
 
     foreach (SearchResult SearchResult in SearchResults)
     {
      foreach (string ProxyAddressProperty in 
               SearchResult.Properties["proxyAddresses"])
      {
       string ProxyAddress = ProxyAddressProperty.ToLower();
 
       // this is necessary to avoid matching
       // @foo.com with @foo.com.bar
       if ("smtp:@" + Recipient.SMTPAddressDomain.ToLower() == 
                                                  ProxyAddress)
       {
        string RoutedSMTPAddress = 
               SearchResult.Properties["mail"][0].ToString();
 
        NewRecipients.AddSMTPRecipient(RoutedSMTPAddress, null);
        return true;
       }
      }
     }
 
     return false;
 }

That's it. This was overall a simple task, and should, frankly, ship with Microsoft Exchange. This code can probably be easily extended to support regular expressions and other fancy things.

History

  • 10/24/2006: initial release.

License

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

Share

About the Author

dB.
Team Leader Application Security Inc., www.appsecinc.com
United States United States
Daniel Doubrovkine has been in software engineering for twelve years and is currently development manager at Application Security Inc. in New York City. He has been involved in many software ventures, including Xo3 and Vestris Inc, was a development lead at Microsoft Corp. in Redmond, and director of Engineering at Visible Path Corp. in New York City. Daniel also builds and runs a foodie website, http://www.foodcandy.com.

Comments and Discussions

 
GeneralMy vote of 5 PinprofessionalAmir Mohammad Nasrollahi7-Aug-13 22:12 
Nice
QuestionCreate domains is the same? PinmemberFelipe.Gonzalez20-Nov-07 13:25 
AnswerRe: Create domains is the same? PinmemberdB.21-Nov-07 2:30 
Question?!?!?!?! PinmemberHillai9-May-07 2:06 
AnswerRe: ?!?!?!?! PinmemberdB.9-May-07 2:30 
QuestionNewRecipients? PinmemberPletzky7-Nov-06 20:07 
AnswerRe: NewRecipients? PinmemberdB.8-Nov-06 2:13 
GeneralRe: NewRecipients? PinmemberPletzky8-Nov-06 6:03 
Generalbest solution Pinmembermikedepetris6-Nov-06 22:56 
GeneralRe: best solution PinmemberdB.7-Nov-06 2:59 
GeneralRe: best solution Pinmembermeraydin4-Sep-07 10:20 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140926.1 | Last Updated 1 Nov 2006
Article Copyright 2006 by dB.
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid