none
Exchange 2013 Sender Base Routing RRS feed

  • Question

  • Hi,

    I am trying to configure Sender Based Routing following this Article (http://www.tuescher.net/Exchange-Sender-Based-Routing/e13.html#chapter6 ), but what i see that is happening is that when i configure to reroute all mails from ms_admin@domain.com.uy to domain.sbr, it looks like is using domain.sbr domain to do the dns checking and of course it does not exist, so i get a undeliverable message in return.

    If i try sending an email from any other user that will use the regular Send Connector it will work perfectly. Even if i change the configuration file to another user, the user with the dns problem, will start using the "Default" send connector and will work fine.

    i believe the way that is scripted is sending the emails with the changed fake domain, (which it should only be used for the selection of the send connector only, not to actually send the email)

    at the bottom i will attach the code, if anybody could help me spot or recommend a change to correct it. it will be much appreciated.

    Delivery has failed to these recipients or groups:

    testmail@gmail.com (testmail@gmail.com)
    The domain name in the email address is incorrect. Check the address.






    This is the email that is getting bouced:


    Diagnostic information for administrators:

    Generating server: EXCH2013.domain.com


    testmail@gmail.com
     Remote Server returned '554 5.4.4 SMTPSEND.DNS.NonExistentDomain; nonexistent domain'


    Original message headers:
    Received: from EXCH2013.domain.com.uy (2002:900:f9::900:f9) by
     EXCH2013.domain.com.uy (2002:900:f9::900:f9) with Microsoft SMTP Server (TLS)
     id 15.0.1210.3; Wed, 26 Oct 2016 17:32:44 -0300
    Received: from EXCH2013.domain.com.uy ([fe80::54e:cad4:d1ff:a8da]) by
     EXCH2013.domain.com.uy ([fe80::54e:cad4:d1ff:a8da%12]) with mapi id
     15.00.1210.000; Wed, 26 Oct 2016 17:32:44 -0300
    From: Name Lastname <ms_admin@domain.com.uy>
    To: "testmail@gmail.com" <testmail@gmail.com>
    Subject: prueba con ABP
    Thread-Topic: prueba con ABP
    Thread-Index: AQHSL8gatvRIUOVqj06h8wCfqoMLsQ==
    Date: Wed, 26 Oct 2016 20:32:43 +0000
    Message-ID: <1477513963759.71004@domain.com.uy>
    Accept-Language: en-US
    Content-Language: en-US
    X-MS-Has-Attach:
    X-MS-TNEF-Correlator:
    x-ms-exchange-transport-fromentityheader: Hosted
    x-originating-ip: [::1]
    Content-Type: multipart/alternative;
          boundary="_000_147751396375971004domaincomuy_"
    MIME-Version: 1.0

    ---------------------------------------------------------


    • Moved by Bill_Stewart Tuesday, November 1, 2016 3:01 PM Move to more appropriate forum
    Tuesday, November 1, 2016 2:24 PM

All replies

  • Since it didnt fit on one article, here is the code:

    http://www.tuescher.net/Exchange-Sender-Based-Routing/resources/CustomSBRRoutingAgent-E13.cs.txt 

    // This is an Exchange 2013 custom transport agent for sender based re-routing, created by Martin Tuescher
    // As it is here, it needs a Send Connector configured to route mails to override domains that has equal or
    // lower costs than the Default Send Connector for "*".

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Text;
    using Microsoft.Win32;

    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 Microsoft.Exchange.SBR
    {
        /// <summary>
        // Run when installing the assembly, this function sets up the required application event logging registry keys
        /// </summary>
        [RunInstaller(true)]
        public class SbrRoutingAgentEventLogInstaller : Installer
        {
            private EventLogInstaller SbrEventLogInstaller;

            public SbrRoutingAgentEventLogInstaller()
            {
                SbrEventLogInstaller = new EventLogInstaller(); // Create an instance of an EventLogInstaller.
                SbrEventLogInstaller.Source = "Microsoft.Exchange.SBR"; // Set the source name of the event log.
                SbrEventLogInstaller.Log = "Application"; // Set the event log that the source writes entries to.
                Installers.Add(SbrEventLogInstaller); // Add routingeventLogInstaller to the Installer collection.

                RegistryKey newRegKey = Registry.LocalMachine.CreateSubKey("System\\CurrentControlSet\\Services\\MSExchangeSbrAgent\\Diagnostics");
                newRegKey.SetValue("General", 0);
            }
        }

        public sealed class SbrRoutingAgentFactory : RoutingAgentFactory
        {
            public override RoutingAgent CreateAgent(SmtpServer server)
            {
                RoutingAgent myAgent = new OwnRoutingAgent();
                return myAgent;
            }
        }

        public class OwnRoutingAgent : RoutingAgent
        {
            private int eventLogLevel = -1;     // Don't log if the proper keys aren't setup because this could cause problems later.
            private RegistryKey eventLogRegKey;

            private Dictionary<String, String> _RoutingTable;
            private String OverrideSettingsFileName = Environment.GetEnvironmentVariable("ExchangeInstallPath", EnvironmentVariableTarget.Machine) + @"TransportRoles\agents\Custom\Microsoft.Exchange.SBR.OverrideSettings.config";

            private String[] _InternalDomains;
            private String InternalDomainsFileName = Environment.GetEnvironmentVariable("ExchangeInstallPath", EnvironmentVariableTarget.Machine) + @"TransportRoles\agents\Custom\Microsoft.Exchange.SBR.InternalDomains.config";

            private String[] _IgnoreAuthAsValues;
            private String IgnoreAuthAsFileName = Environment.GetEnvironmentVariable("ExchangeInstallPath", EnvironmentVariableTarget.Machine) + @"TransportRoles\agents\Custom\Microsoft.Exchange.SBR.IgnoreAuthAs.config";

            public OwnRoutingAgent()
            {
                // Read EventLogLevel from Registry
                this.eventLogRegKey = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\services\\MSExchangeSbrAgent\\Diagnostics");
                if (this.eventLogRegKey != null)
                {
                    if (eventLogRegKey.GetValue("General") != null)
                    {
                        this.eventLogLevel = ((int)eventLogRegKey.GetValue("General"));

                        if (eventLogLevel >= 6) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Event logging set to level " + this.eventLogLevel.ToString() + ".");
                    }
                }

                //subscribe to different events
                base.OnResolvedMessage += new ResolvedMessageEventHandler(ownRoutingAgent_OnResolvedMessage);

                _IgnoreAuthAsValues = File
                                      .ReadAllLines(IgnoreAuthAsFileName)
                                      .Where(line => !String.IsNullOrEmpty(line))
                                      .Where(line => !line.StartsWith("#"))
                                      .Select(line => line.ToLower())
                                      .ToArray();   // assumes line has 1 element, no error check
                
                _InternalDomains = File
                                   .ReadAllLines(InternalDomainsFileName)
                                   .Where(line => !String.IsNullOrEmpty(line))
                                   .Where(line => !line.StartsWith("#"))
                                   .Select(line => line.ToLower())
                                   .ToArray();

                _RoutingTable = File
                                .ReadAllLines(OverrideSettingsFileName)
                                .Where(line => !String.IsNullOrEmpty(line))
                                .Where(line => !line.StartsWith("#"))
                                .Select(line => line.ToLower())
                                .Select(line => line.Split(';'))
                                .ToDictionary(items => items[0], items => items[1]); // assumes line has 2 elements, no error check
            }

            private void ownRoutingAgent_OnResolvedMessage(ResolvedMessageEventSource source, QueuedMessageEventArgs e)
            {
                try
                {
                    var routingOverrideDomainPart = "";
                    var senderFullEmailAddress = e.MailItem.FromAddress.ToString().ToLower(); // get full sender email address
                    var senderOnlyDomainPart = e.MailItem.FromAddress.DomainPart.ToLower(); // get domain part of sender email address
                    var emailMessageId = e.MailItem.Message.MessageId.ToString();
                    var emailMessageSubject = e.MailItem.Message.Subject.ToString();
                    Microsoft.Exchange.Data.Mime.Header emailMessageOrgAuthAs;
                    emailMessageOrgAuthAs = e.MailItem.Message.MimeDocument.RootPart.Headers.FindFirst("X-MS-Exchange-Organization-AuthAs");

                    if (eventLogLevel >= 5) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Entering OnResolved for message " + emailMessageId + " (\"" + emailMessageSubject + "\").", EventLogEntryType.Information, 1);

                    if (!_IgnoreAuthAsValues.Contains(emailMessageOrgAuthAs.Value.ToString().ToLower()))
                    {
                        // X-MS-Exchange-Organization-AuthAs value not found in ignore table (typically "Internal") so we start processing the mail
                        if (!_RoutingTable.ContainsKey(senderOnlyDomainPart) && !_RoutingTable.ContainsKey(senderFullEmailAddress))
                        {
                            // Nothing to reroute, quit
                            if (eventLogLevel >= 5) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Exiting OnResolved for message " + emailMessageId + " (\"" + emailMessageSubject + "\"):\nSender email domain or address not found in rerouting table.\nSBR agent is not processing this mail.", EventLogEntryType.Information, 8);
                            return;
                        }

                        int rerouteCount = 0;

                        if (_RoutingTable.ContainsKey(senderOnlyDomainPart))
                        {
                            // sender email domain is in rerouting table
                            if (eventLogLevel >= 3) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Sender email domain " + senderOnlyDomainPart + " for message " + emailMessageId + " (\"" + emailMessageSubject + "\") is in rerouting table.", EventLogEntryType.Information, 2);
                            routingOverrideDomainPart = _RoutingTable[senderOnlyDomainPart];
                        }

                        if (_RoutingTable.ContainsKey(senderFullEmailAddress))
                        {
                            // sender email address is in rerouting table
                            if (eventLogLevel >= 3) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Sender email address " + senderFullEmailAddress + " for message " + emailMessageId + " (\"" + emailMessageSubject + "\") is in rerouting table.", EventLogEntryType.Information, 2);
                            routingOverrideDomainPart = _RoutingTable[senderFullEmailAddress];
                        }

                        var myRoutingOverride = new RoutingDomain(routingOverrideDomainPart);
                        var recipientsToOverride = e.MailItem
                                                    .Recipients
                                                    .Where(rec => !_InternalDomains.Contains(rec.Address.DomainPart.ToLower()));

                        foreach (EnvelopeRecipient recp in recipientsToOverride)
                        {
                            if (eventLogLevel >= 2) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Overriding recipient " + recp.Address.ToString() + " on " + emailMessageId + " (\"" + emailMessageSubject + "\").", EventLogEntryType.Information, 4);
                            RoutingOverride newRoute = new RoutingOverride(myRoutingOverride, DeliveryQueueDomain.UseOverrideDomain);
                            source.SetRoutingOverride(recp, newRoute);
                            rerouteCount++;
                        }

                        if (eventLogLevel >= 1) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Statistics for message " + emailMessageId + " (\"" + emailMessageSubject + "\"):\n" + rerouteCount.ToString() + " recipients  were rerouted.", EventLogEntryType.Information, 5);
                        if (eventLogLevel >= 4) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Exiting OnResolved for message " + emailMessageId + " (\"" + emailMessageSubject + "\").", EventLogEntryType.Information, 8);
                    }
                    else
                    {
                        // X-MS-Exchange-Organization-AuthAs value found in ignore table
                        if (eventLogLevel >= 4) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Exiting OnResolved for message " + emailMessageId + " (\"" + emailMessageSubject + "\"):\nX-MS-Exchange-Organization-AuthAs header \"" + emailMessageOrgAuthAs.Value.ToString().ToLower() + "\" found in ignore table.\nSBR agent is not processing this mail.", EventLogEntryType.Information, 8);
                        return;
                    }
                }
                catch (Exception except)
                {
                    if (eventLogLevel >= 3) EventLog.WriteEntry("Microsoft.Exchange.SBR", "Exception (OnResolved): " + except.Message + "\n" + except.StackTrace, EventLogEntryType.Information, 10);
                }
            }
        }
    }

    Thanks a lot in Advance !!

    Tuesday, November 1, 2016 2:25 PM
  • It looks okay I would suggest you enable pipeline tracing and Message Tracking and then trace a message that is sent through eg to see if its being processed by your Agent (or maybe another agent is causing issues) and then have a look at the tracking logs to see what happens when the server tries to forward it to the smarthost etc . Those two things should be able to point at the time in the Transport pipeline where the NDR is being generated which might give you more information on why its failing.

    Cheers
    Glen

    Thursday, November 3, 2016 1:37 AM