Anything for sysadmins!


Shared SMTP namespace during cross-forest migration

Exchange 2010 has been released quite some time ago, and I’m finally looking into it. As I’m also moving to a new domain which makes the transition a bit harder, but a name change of the domain is also necessary.

The mail flow will go from several SMTP servers to a mail proxy (Postfix) which has a couple of entries in the virtual file and also relays some domains to Forest B.

During the migration both forests will be used. Both forests will use e-mail addresses. This is often referred to as a shared SMTP namespace. One of the problems with a shared SMTP namespace is that it introduces mail loops if you set both mail servers to non-authorative. Setting 1 server to Authorative will cause problems with the mail flow if that server is also the originating server. Resulting in DNRs being send. I’m my case it’s not feasible to use multiple domains, which is an often mentioned solution. The image below shows my solution to this problem.

Using a custom header in the e-mail messages you can make sure the mails don’t loop (which happens to unresolved recipients). In Forest A the HUB servers are set to add a header X-Loop with the value 1 using transport rules. If the mail is relayed to Forest B and the recipient can’t be resolved there, it relays back to Forest A. The Hub servers there are also configured with a transport rule that drops the message if the header X-Loop is set to 1. Therefore it doesn’t loop and gets dropped. I’ve chosen to drop the message instead of sending a DNR because of backscatter which might get you blacklisted. Same story goes for Forest B only then X-Loop is set to 2.

To make sure that the header is not overwritten between Forests, I’ve set an exclusion on the rule to not set X-Loop if it’s already set.

How to configure the HUB servers

First add the following rule to all HUB servers in Forest A:

  • Go to Organization Configuration -> Hub Transport
  • Go to the Transport Rules tab
  • Add a new Transport Rule
  • Set a name and click next

  • Click next as this applies to all messages on this server. You’ll get a message which lets you confirm that it’s applied to all messages.

  • Check set header with value and set both blue fields to the desired values. In my case I’ve set header to X-Loop and value to 1 (the value of Forest A). Then click next

  • Check Except when the message header contains specific words and set the blue fields to the values defined above with the value of the other forest. In my case I’ve set message header to X-Loop and specific words to 2 (the value of Forest B). Then click next

  • Confirm all the values and click finish

This transport rule sets the header in the message. Now we have to make sure that the message gets dropped when it returns.

I’ll make this a bit shorter as most of the steps are the same as the above one.

  • Create a new transport rule and set it to resemble the following image


You should do the same for the other forest, only then with different values in the headers.

Be Sociable, Share!

Posted by Mischa Oudhof

Comments (0) Trackbacks (4)
  1. Great article but is it possible to explain abit in details step by step how i would go about setting up the send connectors between the two hub servers in both forests for the mail to flow correctly between the two domains. Here is my situation.
    I am in the process of migrating from Exchange 2007 to Exchange 2010. We currently have a resource forest model type of Exchange environment where we have two forests Domain1.local and Domain2.Network. Domain1.local is being used to host Exchange CCR 2007 mailbox while is used for account authentication. We have decided to migrate to Exchange 2010 and use only one forest for both Mailbox and account and decommission Domain1.local forest. We have already installed Exchange 2010 mailbox role, HuB and Edge servers on the forest but we would like to start testing mail flow to this new Exchange using same domain name currently being used in Exchange 2007 environment without changing the MX records to point to the new Edge server until we are ready for the actual migration. There is an existing trust between the two domains. We would like to keep both environments coexist and mail flow to both Mailbox servers but utilize existing 2007 Edge and 2007 HuB roles till we are ready to repoint the MX records. Is there a way to configure the 2007 HUB send connector to check if a mailbox exists in 2007, if not then forward to the 2010 maillbox. Our current MX records for points to the 2007 Edge server and we want to keep that way for now till we know the test is successful on Exchange 2010.

    • The email coming from external should still come in at the Exchange 2007 servers untill you’re absolutely sure that your Exchange 2010 domain is fully functional.

      To make sure that all emails are routed through both domains you should mark all your accepted domains as Internal Relay domains in both environments. Internal Relay domains first check on the Exchange 2007 environment if it can be delivered and if that’s not the case it’ll pass through the Send Connector defined by using the Address Space of the send connector. You should put all your domains in the Address Space of the send connector pointing to your Exchange 2010 environment.

      I only added the transport rules to make sure that email to unknown recipients doesn’t bounce between the 2 domains for a long time before being dropped.

      Lemme know if you need more information

  2. I have three different domains: domain.local, domain.local1 and domain local2 with the same SMTP addresses. How can I manage domain.local to route incoming external e-mail to recipients in other domains? Also how its possible to establish routing between them internaly? thanks.

    • For routing the e-mail internaly, you’ll have to mark those accepted domains as Internal Relay and create send connectors which target that specific domain.

      To make sure that you don’t create a loop in the mail routing (for recipients that don’t exist), you’ll have to create the transport rules as indicated in the post. You’ll just have to create an extra one with Set X-Loop = 3 for the third domain.

      When an e-mail to domain.local is sent, it’ll be received by the server in domain.local. If it doesn’t have the recipient in it’s store, it’ll check the accepted domains finding out it’s an internal relay domain. The hub transport layer adds the X-Loop=1 to the message header and sends it to domain.local1. Domain.local1 does the same, and sends it to domain.local2. Domain.local2 does the same, might store the message if it has the recipient in it’s store, and otherwise, relays it back to domain.local which sees that X-Loop = 1 (which means it’s gone a full circle) and drops the message.

  3. Great article, very creative solution using the hub transport rules.

    How would you handle auto-forwarding? If you do nothing auto-forwarded messages are dropped since they already have the x-loop tag.


    • That is indeed a case that I did not consider, but it did still work. I have no way of telling you how, because we have finalized our migration and have disabled the rules so I can’t trace the messages.

      However if you are still concerned, as I have no arguments to support this theory, you could tell your users that they have to include a rule to add text to their subject and set the transport rule to exclude these. Also you can have the messages go through the loop 2 times or more, which is more complex, but also more reliable.

      Just comment again if you want more info on looping the messages 2 times.

  4. Excellent, exactly the solution I was looking for and very well presented so it was easy to digest.

    Thanks a lot you have made my day.

  5. I was under the impression that there is a better way for doing this:
    To workaround the loop issue (and not being able to do an ldap check for address existence on your internet facing mailserver), isn’t it possible to just keep the domains in both organizations as type Authoritative and configure cross-forest send connectors?

    This way you will never get a loop and use mail enabled users or contacts to represent the users that are present in the other organisation within the shared namespace.

    As email addresses are present in both organizations, ldap queries for address validity will also keep functioning.

    The process is documented here:

    I’ve tested this and it seems to work.

    • When you’re using the mail enable users and contacts you’ll have to specify a different domain to be able to forward it to the other organization. This and keeping track of those mail enabled users and contacts are the biggest culprits. That’s why I opted for the messages to loop without introducing a new SMTP domain into the organization (although you can use the forests domain). Also this makes the migration process more complex as you’ll have to delete and recreate the mail enabled users and contacts on multiple domains.

  6. At first thx for your great post.

    I’m working on a cross forest migration at the moment from Exchange 2007 to Exchange 2010. Yesterday I had the “auto-forwarding” problem Arjan talked about above. Unfortunately I don’t read his comment before configuring the share SMTP namespace, so some users had problems with NDRs.

    I solved the problem by configuring the transport rule to accept the loop 2 times. I set the value “X-Loop” to 3 (old Exchange) and 4 (new Exchange) if the X-Loop value was set before. And the messages won’t get dropped until the new X-Loop value (3 or 4) was set.

    It seems to work now.


  7. If I send email from Forest A to external domain (say, it will set X-Loop=1 to this message. And when i reply back from gmail on the same email, this message header will still contain X-Loop=1.

    So based on transport rules at Forest A, Wont this message be dropped when it hits back the Forest A ?

    I just wanted to clearly understand how does the transport rule differentiates apply rules separately.

  8. Hi Mischa, neat content.
    Got a question though. Can you explain what would be the rule you would add on Forest B?
    Is it like?
    # 1
    Apply rule for all messages.
    Set header “X-Loop” to 2, Except if header “X-Loop” is “1”


    Apply rule for all messages.
    Set header “X-Loop” to 2. (No exceptions)

    If you go by # 1.
    1) UserA in ForestA sends a mail to UserB in ForestB.
    2) Transport rule in ForestA (as clearly stated in the post) would set X-Loop to be “1”
    3) Now, message has value of 1. So, Transport rule on ForestB wont act.
    4) UserB receives the mail with “X-Loop” value to 1.
    5) UserB replies back to UserA.
    6) Transport rule in ForestB would not act on this one as “X-Loop” is 1.
    7) ServerB sends the mail to ServerA
    8) Rule in ForestA will drop the mail as the value of “X-Loop” is 1.

    Guess, i am missing something simple here. But, couldn’t crack it.

    • The X-Loop parameter is purely for detecting if the message has already been to that server. The exception is necesarry to make sure that the value is not overwritten. So you’ll have to go with #1.

      1) UserA in ForestA sends a mail to UserB in ForestB
      2) Transport rules in ForestA sets X-Loop = 1
      3) The messages is sent to ForestB for processing, but doesn’t change the X-Loop value
      4) UserB replies back to UserA with a message with X-Loop = 1
      5) The delivery of the message is first attempted on it’s own ForestB

      The next step is kind of a mistery to me unfortunately, but it doesn’t drop the message but it’s first processed once (I tested this scenario).

      If you want to be sure, you could have another rule setting X-Loop to a different value (3) and have it do another run before it’s dropped.

  9. Hi Mischa,

    Great article, i’m doing shared namespace between exch 2010 and exch 2003, could you please guide me to configure transport rules on exch 2003 side? i’m not sure about transport rules on exch 2003, is it possible?

    Thank you in advance

    • I haven’t used Exchange 2003 for quite some time already. However I checked some technet articles and it seems like the action ‘set header with value’ is also in Exchange 2003. That means you should be able to do the same as in Exchange 2010.

  10. Mischa,

    Good article. I have a similar problem but am not using Exchange 2010 only Exchange 2007 between two forrest’s with a full trust. Would the same steps still apply?

    The new domain has a full system setup but we are only accepting the new email domain on the old system and will be migrating to the new one soon. The boss wants to setup new users on the new system but i keep telling him it’s not yet possible because of the access to email issue with the email domain.



    • Yes, these are actualy quite simple rules and as far as I know these are available in Exchange 2007 as well.

      As long as you’re not accepting the default email domain on the new enviroment you can’t switch to it!

      An option that might be worth exploring, depending on the size of your company, is to create new users on the new system, then create contacts on the old one pointing to the email address of the new system. It’s not pretty and you’ll have to investigate what this does with your internal mailflow, but might make your boss happy.

  11. Mischa,

    Excellent article. Got me the final pieces to be able to do a seemless x-forest migraton from ex27k to ex2k10.

    Thanks again!

  12. Hi Mischa,

    Experienced the Auto forwarding issue added another loop = 3 and 4 and it worked. This solution helped us avoid creating contacts manually, Thanks !!! :@)

  13. Excellent article! One thing I’ve realized is that if someone from the outside sends an e-mail to an invalid e-mail address they wouldn’t get a NDR saying “user does not exist”. Have you found a solution for this?

    • This situation shouldn’t happen. The Exchange organization should never accept the email when the user doesn’t exist. When you do accept the email and the sender address is spoofed, you will be sending a mail back to someone that never send you a mail. This is called backscatter, and is a common way of getting your mail server on blacklists! It’s better to never reply back, then to get added to a blacklist.

      To overcome this problem, the to/cc address should be checked during the connection stage. When the TO header is input by the remote server and the user doesn’t exist, the mail will be refused and the remote server will be notified by an error code.

  14. Hi Mischa

    This was very useful during the migration, but interestingly enough I ended up with a strange issue. Delegates would no longer receive meeting requests.

    I raised a call with MS and paid £199 for the privilege. After 2 days of head scratching, we stopped the X-Loop rule and voila, mail started delivering to delegates again on meeting requests. The MS Exchange guys can’t even work out why it breaks with these rules in place, but it does.

    Just a side effect.


  15. FYI – The order of the rules is critical!!!

    The Delete Rule must be higher priority than the Header Tagging Rule!

    …or it will tag and delete it, before it has a chance to send it.

    I made a few mods to this, here is how I did it.
    Email in -> mailsystem01 (user exists, delivered!)
    Email in -> mailsystem01 (user does not exist, set X-Loop = 1) -> mailsystem02 (user exists, delivered!)
    Email in -> mailsystem01 (user does not exist, set X-Loop = 1) -> mailsystem02 (user does not exist, if X-Loop = 1, then change X-Loop = 3) -> mailsystem01 (if X-Loop = 3, delete it!)

    Email in -> mailsystem02 (user exists, delivered!)
    Email in -> mailsystem02 (user does not exist, set X-Loop = 2) -> mailsystem01 (user exists, delivered!)
    Email in -> mailsystem02 (user does not exist, set X-Loop = 2) -> mailsystem01 (user does not exist, if X-Loop = 2, then change X-Loop = 4) -> mailsystem02 (if X-Loop = 4, delete it!)

    this gives me the chance to allow it to bounce as many times as I want before it kills it.

    Thanks for the basic logic on how to do this!

  16. Hi Mischa,

    I am having 4 forest and using same smtp namespace and enabled Internal relay, but some times getting Internal loop issue, I have tired your method with transport rule to detect loop. but not working. Could you please help.

Leave a comment