none
Custom Transport Agent for Address Rewrite RRS feed

  • Question

  • Hi All, 

    I have done a lot of research on writing a code for custom Transport Agent.

    What I need to achieve is that one of Linux server sends an email @linux.com through our Exchange system here and I'd like the receiver will get @domain.com instead of @linux.com. Because there are a couple users in that domain, so whoever sends from this linux.com will get changed (@domain.com) at the destination. 

    From my research and modify the codes from number of websites

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using Microsoft.Exchange.Data.Transport;
    using Microsoft.Exchange.Data.Transport.Email;
    using Microsoft.Exchange.Data.Transport.Smtp;
    using Microsoft.Exchange.Data.Transport.Routing;
    using Microsoft.Exchange.Data.Common;


    namespace RoutingAgentOverride
    {
        public class SampleRoutingAgentFactory : RoutingAgentFactory
        {
            public override RoutingAgent CreateAgent(SmtpServer server)
            {
                RoutingAgent myAgent = new ownRoutingAgent();

                return myAgent;
            }
        }
    }
    public class ownRoutingAgent : RoutingAgent
    {
        public ownRoutingAgent()
        {
            //subscribe to different events
            base.OnResolvedMessage += new ResolvedMessageEventHandler(ownRoutingAgent_OnResolvedMessage);
        }

        void ownRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e)
        {
            try
            {

                if (e.MailItem.FromAddress.DomainPart.Contains("linux.com"))
                {
                    e.MailItem.FromAddress = new RoutingAddress("Localpart", "domain.com");
                    e.MailItem.Message.From.SmtpAddress = "localpart" + "@" + "domain.com";
                    e.MailItem.Message.Sender.SmtpAddress = "localpart" + "@" + "domain.com";


                }
            }

            catch 
            {

            }
        }

    }

    I have not tested, would it work?

    Thanks


    Wednesday, June 12, 2013 5:04 AM

All replies

  • The OnResolvedMessage Event is what you would use if you want to reroute a message to a particular user. For what you want to do you should use a SmtpReceiveAgent similar to http://blogs.technet.com/b/jasoning/archive/2011/08/17/icalendar-property-rewrite.aspx.

    The other option is depending on what Mail server your running on the Linux server you can do the address rewriting there eg with PostFix from memory its just a few lines in a Config file. Doing at the source is generally better then doing it in transit on the Exchange Server.

    Cheers
    Glen

    Thursday, June 13, 2013 7:21 AM
  • Thank you Glen for your help

    I am aware of that we could do the address rewriting in Linux, unfortunately it is not our "domain", I cannot touch it. 

    I did test my code, it worked .. half way :(. it displayed localpart@domain.com exactly like that the UPN part is correct but the username is wrong because of its string "localpart". How can I make it variable? so the username would be attached to his/ her email such as smith@domain.com.

    Thank you

    Friday, June 14, 2013 12:30 PM
  • Hi 

    Does anyone know how to make "LocalPart" as a variable then pass it on where we want it to be? 

    I have done C++ before but it was 15 years ago :(. Please shed me some light on it. 

    Thanks and Regards

    Monday, June 17, 2013 2:56 AM
  • Is the current localPart of the From Address before you rewrite it okay ? You should just be able to use

    String EmailPrefix = e.MailItem.Message.From.LocalPart;
    e.MailItem.FromAddress = new RoutingAddress(EmailPrefix , "domain.com");
    e.MailItem.Message.From.SmtpAddress = EmailPrefix  + "@" + "domain.com";
    e.MailItem.Message.Sender.SmtpAddress = EmailPrefix  + "@" + "domain.com";
    Cheers
    Glen

    Monday, June 17, 2013 6:45 AM
  • Thank you Glen,

    That is similar to what I have tried

    String EmailPrefix = e.MailItem.FromAddress.LocalPart;

    And the rest the same. But it did not send to my Inbox. 

    I tried yours i.e. e.MailItem.Message.From.LocalPart, the LocalPart is not in library (Error).

    Sorry I don't get your question.

    Without the variable we defined above and make "EmailPrefix" as a string type then I got it sent to my inbox with EmailPrefix@domain.com. 

    Regards,

    Monday, June 17, 2013 12:19 PM
  • e.MailItem.Message.Sender.SmtpAddress

    Should contain the current email address before rewrite have you tried using that ? eg

    if (e.MailItem.Message.Sender.SmtpAddress.Contains("@"))
    {
         string[] SplitArray =e.MailItem.Message.Sender.SmtpAddress.Split('@');
         String EmailPrefix = SplitArray[0];
    }

    >> And the rest the same. But it did not send to my Inbox

    ?? your rewriting the FromAddress that's not going to affect the delivery

    Glen

    Tuesday, June 18, 2013 5:26 AM
  • Hi Glen,

    Once again much appreciated.

    I think I got it work with your code this time. 

    Because we have 2 Exchange server 2003 and 2010 (Hybrid environment), currently the Agent I just installed on Exchange server 2010 so all EX2010 users receive with the new one e.g. smith@domain.com, but not EX2003 users, how can I install the custom Agent on Exchange 2003?

    Thanks and Regards

    Wednesday, June 19, 2013 4:39 AM
  • Umm... sorry to jump in late on this one but 2003 is a completely different environment - you can't install a 2007/2010 transport agent on 2003.

    You'll need a 2000/2003 (COM) Event sink for this. Similar problem but a completely different solution.

    Do you really want to go down this path... or upgrade your other server to 2007 (or 2010) ?? (hint hint)

    Note: There are also 3rd party applications that can do this address rewrite for you...

    Regards,

    Scott Quinn


    Scott Quinn | C# developer & messaging specialist (for hire). Contact me at http://au.linkedin.com/in/scottquinn

    Wednesday, June 19, 2013 11:13 AM
  • Hi Scott and Glen,

    Thank you for your help and responses. 

    At the end I managed to route all incoming emails to Exchange 2010 so the Transport Agent applies before they are sent to the recipient. So all good now.

    Once again much appreciated.

    Regards

    Thursday, June 20, 2013 9:28 PM
  • Hi, this code might be bring me a big step towards solving my problem. But could anyone please give me a hint on how to register the code with or include it in the transport of my exchange 2013 standard? Thanks a lot jan
    Saturday, June 22, 2013 12:59 PM
  • Its pretty much the same process as in 2010 see http://blogs.technet.com/b/exchange/archive/2013/01/21/how-to-write-an-exchange-2013-transport-agent.aspx for a detailed explaintion of the changes.

    Cheers
    Glen

    Monday, June 24, 2013 7:06 AM
  • Thanks for the answer. I found a solution. A short summary with some mor links will follow shortly.

    Monday, June 24, 2013 8:10 PM
  • I found a solution for Exchange 2013 CU1 using C# in a .net 4 library. The library I created with VS express web.  It is far from beeing perfect but does what is needed for now. Errorhandling as well as reporting and so on need to be improved.

    I further wonder whether binding it to the hub (-TransportService Hub ) is a good idea.

    Besides this thread http://blog.c7solutions.com/2012/10/creating-simple-exchange-server.html was of great help to me.

    I registert it by the following code in the Exchange Shell. Name and TransportAgentFactory need to match the naming in the Library. If not you will get the error: Error: The TransportAgentFactory type "xxxxx.yyyyy" doesn't exist. The TransportAgentFactory type must be the Microsoft .NET class type of the transport agent factory. or something alike.

    Install-TransportAgent -Name "RoutingAgentOverride" -AssemblyPath "C:\fromrewrite\TransportAgent.dll" -TransportAgentFactory "RoutingAgentOverride.SampleRoutingAgentFactory"  -TransportService Hub 
    
    Enable-TransportAgent "RoutingAgentOverride" 
    
    Restart-Service MSExchangeTransport
    
    IISRESET

    The code used for the library is

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Mail; using System.Net.Mime; \\the following to be included from the exchange folder public and need to math exactly to the exchange version using Microsoft.Exchange.Data.Transport; using Microsoft.Exchange.Data.Transport.Email; using Microsoft.Exchange.Data.Transport.Smtp; using Microsoft.Exchange.Data.Transport.Routing; using Microsoft.Exchange.Data.Common; namespace RoutingAgentOverride { public class SampleRoutingAgentFactory : RoutingAgentFactory { public override RoutingAgent CreateAgent(SmtpServer server) { RoutingAgent myAgent = new ownRoutingAgent(); return myAgent; } } }


    //the rewrite is done here: public class ownRoutingAgent : RoutingAgent { public ownRoutingAgent() { //subscribe to (different) events base.OnResolvedMessage += new ResolvedMessageEventHandler(ownRoutingAgent_OnResolvedMessage); } void ownRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e) { try { // Logger("Start processing email '" + e.MailItem.Message.Subject + " from " + e.MailItem.FromAddress); //not every email shall be rewritten - so here are some ifs to sort them out if (e.MailItem.FromAddress.DomainPart.Contains("xxx.yy")) //at the beginning I sometimes missed the difference betwen DomainPart and LocalPart { if (e.MailItem.FromAddress.LocalPart.Contains("HealthMailbox")) { } // used to exclude handling of some emssages that I do not know much about which is why I considered binding it to the hub might not be a good idea. else { if (!e.MailItem.FromAddress.LocalPart.Contains("AAA")) { if (!e.MailItem.FromAddress.LocalPart.Contains("BBB")) { if (!e.MailItem.FromAddress.LocalPart.Contains("CCC")) { if (!e.MailItem.FromAddress.LocalPart.Contains("aaa")) { if (!e.MailItem.FromAddress.LocalPart.Contains("bbb")) { if (e.MailItem.Recipients.Count == 1 && e.MailItem.Recipients.ElementAt(0).Address.DomainPart.Contains("xxx.yy")) { } else if (!e.MailItem.FromAddress.LocalPart.Contains("cc")) {

    \\

    Logger("rewriting mail '" + e.MailItem.Message.Subject + " from " + e.MailItem.FromAddress); e.MailItem.FromAddress = new RoutingAddress("info", "xxx.yy"); e.MailItem.Message.From.SmtpAddress = "info" + "@" + "xxx.yy"; e.MailItem.Message.Sender.SmtpAddress = "info" + "@" + "xxx.yy"; e.MailItem.Message.From.DisplayName = "My NAME"; e.MailItem.Message.Sender.DisplayName = "MY NAME"; Logger("rewritten to " + e.MailItem.FromAddress); } else { Logger("rewriting mail '" + e.MailItem.Message.Subject + " from " + e.MailItem.FromAddress); e.MailItem.FromAddress = new RoutingAddress("personal", "xxx.yy"); e.MailItem.Message.From.SmtpAddress = "personal" + "@" + "xxx.yy"; e.MailItem.Message.Sender.SmtpAddress = "personal" + "@" + "xxx.yy"; e.MailItem.Message.From.DisplayName = "My Name - Personal und Buchhaltung"; e.MailItem.Message.Sender.DisplayName = "My Name - Personal und Buchhaltung"; Logger("rewritten to " + e.MailItem.FromAddress); } } } } } } } } } catch { Logger("FEHLER"); sendmail("Fehler beim rewrite einer Nachricht"); Logger("Adresse lautet to " + e.MailItem.FromAddress); //string esubject = e.MailItem.Message.Subject; //sendmail("Fehler beim rewrite einer Nachricht am " + e.MailItem.Message.Date.ToString("yyyy-MM-dd_HH:mm:ss")); // + e.MailItem.Message.Date.ToString("yyyy-MM-dd_HH:mm:ss")); } } void sendmail(string message) { try { SmtpClient client = new SmtpClient(); client.Port = 26; //most likely you will need port 25 here client.Host = "192.168.0.2"; client.EnableSsl = false; client.Timeout = 10000; client.DeliveryMethod = SmtpDeliveryMethod.Network; client.UseDefaultCredentials = true; //client.Credentials = new System.Net.NetworkCredential("USERNAME", ""); MailMessage mm = new MailMessage("a@b.de", "c@d.de", "Fehler beim from rewrite im TransportAgent des Exchange Servers", message); mm.BodyEncoding = UTF8Encoding.UTF8; mm.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure; client.Send(mm); } catch { } } void Logger(String lines) { // Write the string to a file.append mode is enabled so that the log // lines get appended try { System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\fromrewrite\\fromrewrite.log", true); file.WriteLine(DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss") + lines); file.Close(); } catch { } } }



    Monday, June 24, 2013 9:59 PM