HOW TO:Rewrite the To address in Transport Agents on a Hub Server

Have you ever tried sending a mail to someone and it end up with someone else! Beware there could be a Transport Agent that's doing this:-).

I ran into an issue where I needed to rewrite the address the mail was being sent to. Not going into too much as to why somebody would want to do this,  I wrote a Transport Agent that would do the needful.

The below sample C# code written in Visual Studio 2005 changes the To address of the mail that is being sent out. There is no conditional logic as of now and the code assumes that there is only one recipient.

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using Microsoft.Exchange.Data.Mime;
using Microsoft.Exchange.Data.Transport;
using Microsoft.Exchange.Data.Transport.Email;
using Microsoft.Exchange.Data.Transport.Routing;

namespace Samples.Agents.MyRoutingAgent
{
    public class MyRoutingAgentFactory :RoutingAgentFactory
    {
        public override RoutingAgent CreateAgent(SmtpServer server)
        {
            return new MyRoutingAgent();
        }
    }

    public class MyRoutingAgent : RoutingAgent 
    {
        private object fileLock = new object();  

        public MyRoutingAgent()
        {
            base.OnSubmittedMessage += new SubmittedMessageEventHandler(MyRoutingAgent_OnSubmittedMessage);
        }

        void MyRoutingAgent_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
        {
            lock (fileLock)
            {
                try
                {
                    string logDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\Log";
                    string logFile = logDir + @"\log.txt";

                    if (!Directory.Exists(logDir))
                    {
                        Directory.CreateDirectory(logDir);
                    }
                    
                    if (!File.Exists(logFile))
                    {
                        File.CreateText(logFile).Close();
                    }

                    using (StreamWriter logWriter = File.AppendText(logFile))
                    {
                        logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);

                        //Alter the P1 headers.The P1 address is used for routing.
                        for(int intCounter=e.MailItem.Recipients.Count-1;intCounter>=0; intCounter--)
                        {
                            logWriter.WriteLine("Original Recipient:" + e.MailItem.Recipients[intCounter].OriginalRecipient);

                            if (e.MailItem.Recipients[intCounter].Address.IsValid)
                            {
                                e.MailItem.Recipients.Remove(e.MailItem.Recipients[intCounter]);

                                if (e.MailItem.Recipients.CanAdd)
                                {
                                    e.MailItem.Recipients.Add(new RoutingAddress("administrator@mycompany.com"));
                                }
                            }
                        }

                        //Alter the P2 headers so that the mail displays the correct recipient display Name
                        EmailRecipientCollection erToRecipientCollection;
                        erToRecipientCollection = e.MailItem.Message.To;

                        logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);
                        foreach (EmailRecipient rec in erToRecipientCollection)
                        {
                            logWriter.WriteLine("Original Display Name:" + rec.DisplayName);
                            logWriter.WriteLine("Original SMTP address:" + rec.SmtpAddress);

                            rec.DisplayName = "Administrator";
                            rec.SmtpAddress = "administrator@mycompany.com";

                            logWriter.WriteLine("Changed to <Administrator>administrator@mycompany.com");

                            }
                        }
                        logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);

                        logWriter.Flush();
                    }
                }
                catch (System.IO.IOException ex)
                {
                    Debug.WriteLine(ex.ToString());
                }
            }
            return;
        }

    }
}

It is IMPORTANT that you change both the P1 and the P2 headers for this to work correctly. To build the Agent successfully you will need to add references to Microsoft.Exchange.Data.Transport and the Microsoft.Exchange.Data.Common namespaces. These dll's can be found in the Program Files\Microsoft\Exchange Server\Public folder.

To Install/Uninstall the Agent on the Hub Server I have created script files that do the job for me(makes life easier).

Install.PS1

 #Copy the agent Dll to the C:\MyAgent folder.
$EXDIR="C:\MyAgent"
Net Stop MSExchangeTransport

Write-Output "Registering agent"
Install-TransportAgent -Name "My Routing Agent Sample" -AssemblyPath $EXDIR\RoutingAgent.dll -TransportAgentFactory Samples.Agents.MyRoutingAgent.MyRoutingAgentFactory

Write-Output "Enabling agent"
Enable-TransportAgent -Identity "My Routing Agent Sample"
Get-TransportAgent -Identity "My Routing Agent Sample"

Net Start MSExchangeTransport

Write-Output "Install Complete. Please exit the Exchange Management Shell."

UnInstall.PS1

  $EXDIR="C:\MyAgent"<br>Net Stop MSExchangeTransport<br>Write-Output "Disabling Agent..."<br>Disable-TransportAgent -Identity "My Routing Agent Sample" -Confirm:$false<br>Write-Output "Uninstalling Agent.."<br>Uninstall-TransportAgent -Identity "My Routing Agent Sample" -Confirm:$false<br>Net Start MsExchangeTransport<br>Write-Output "Uninstall Complete." 


Need more information on Transport Agents?

Transport Agents

https://msdn.microsoft.com/en-us/library/aa579185.aspx

Enjoy!

Comments

  • Anonymous
    September 04, 2009
    The comment has been removed
  • Anonymous
    September 04, 2009
    You can do this on the hub server too.All you have to do is:1)Save the LocalPart  before deleting the recepientstrLocalPart =e.MailItem.Recipients[intCounter].Address.LocalPart2) Delete the recepient3) Add the new email as a new RoutingAddress.e.MailItem.Recipients.Add(new RoutingAddress(strLocalPart + "@othercompany.com"));
  • Anonymous
    September 08, 2009
    akash, here is what i have come up with so far. any suggestions or improvements you think would be more effective?thanks!using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Threading;using System.Text.RegularExpressions;using Microsoft.Exchange.Data.Mime;using Microsoft.Exchange.Data.Transport;using Microsoft.Exchange.Data.Transport.Email;using Microsoft.Exchange.Data.Transport.Routing;namespace Samples.Agents.MyRoutingAgent{   public class MyRoutingAgentFactory :RoutingAgentFactory   {       public override RoutingAgent CreateAgent(SmtpServer server)       {           return new MyRoutingAgent();       }   }   public class MyRoutingAgent : RoutingAgent   {       private object fileLock = new object();         public MyRoutingAgent()       {           base.OnSubmittedMessage += new SubmittedMessageEventHandler(MyRoutingAgent_OnSubmittedMessage);       }       void MyRoutingAgent_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)       {           lock (fileLock)           {               try               {                   string logDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"Log";                   string logFile = logDir + @"log.txt";                   if (!Directory.Exists(logDir))                   {                       Directory.CreateDirectory(logDir);                   }                   if (!File.Exists(logFile))                   {                       File.CreateText(logFile).Close();                   }                   using (StreamWriter logWriter = File.AppendText(logFile))                   {                       logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);                       //Alter the P1 headers.The P1 address is used for routing.                       for(int intCounter=e.MailItem.Recipients.Count-1;intCounter>=0; intCounter--)                       {                           logWriter.WriteLine("Original Recipient:" + e.MailItem.Recipients[intCounter].OriginalRecipient);                           if (e.MailItem.Recipients[intCounter].Address.IsValid)                           {                               //Save the whole email address and local part of the address to strings                               strEmailAddress = e.MailItem.Recipients[intCounter]                               strLocalPart = e.MailItem.Recipients[intCounter].Address.LocalPart                               //Create a regex that finds any emails going to d+@company.fax                               Regex regex_company_fax = new Regex("d+@company.fax");                               //Match using the created regex agains the saved email address string                               Match match_company_fax = regex_company_fax.Match(strEmailAddress);                               //If the match is successful, move on, otherwise exit                               if ( match_company_fax.Success )                               {                                   //The match is successful, remove the old address                                   e.MailItem.Recipients.Remove(e.MailItem.Recipients[intCounter]);                                   if (e.MailItem.Recipients.CanAdd)                                   {                                       //Now add back the new address, using the local part string and adding the new providers domain to it                                       e.MailItem.Recipients.Add(new RoutingAddress(strLocalPart + "@fax_provider.com"));&nbsp;                                  }                               }                           }                       }                       //Alter the P2 headers so that the mail displays the correct recipient display Name                       EmailRecipientCollection erToRecipientCollection;                       erToRecipientCollection = e.MailItem.Message.To;                       logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);                       foreach (EmailRecipient rec in erToRecipientCollection)                       {                           logWriter.WriteLine("Original Display Name:" + rec.DisplayName);                           logWriter.WriteLine("Original SMTP address:" + rec.SmtpAddress);                           rec.DisplayName = "Administrator";                           rec.SmtpAddress = "administrator@mycompany.com";                           logWriter.WriteLine("Changed to <Administrator>administrator@mycompany.com");                           }                       }                       logWriter.Write(Environment.NewLine + "-------------------------------------------------------------------------------" + Environment.NewLine);                       logWriter.Flush();                   }               }               catch (System.IO.IOException ex)               {                   Debug.WriteLine(ex.ToString());               }           }           return;       }   }}
  • Anonymous
    September 08, 2009
    The comment has been removed
  • Anonymous
    May 24, 2010
    Just a quick comment to thankyou for the info on here. Have used it as a base to write a routing agent to force internal to internal mail via SMTP to an external filter (which then rewrites addresses again for redelivery). I'd spent numerous days searching for what I was looking for and then your page popped up!