
Selective mail routing during enterprise mergers
Selective mail or Domain Based routing lets an organization present one corporate email identity/address while different recipient domains underneath continue to coexist and operate across separate messaging and hygiene platforms. In this pattern, Exchange Online mail routing becomes the control plane for a shared SMTP namespace, with recipient-scoped rules and connectors determining the routing path.
Microsoft documents Internal Relay accepted domains as the model for domains where recipients can exist in Microsoft 365 or on another mail system and the mail flow rule action that routes messages through a specified outbound connector, which is the control used here to route defined recipient domains safely during coexistence.
Maynor in the Cloud / Beyond the Tenant
Shared SMTP namespaces, scoped connectors, and coexistence across two hygiene platforms.
The problem with a public announcement date
The business is going to announce the new brand when the business is ready. The messaging team rarely gets to pick that date. The challenge is getting one corporate email identity live while the two predecessor environments continue to run underneath it.
On the public announcement day, customers, regulators, members, or patients expect to see one organization: one email domain and one brand in the From line.
Underneath that new identity, you may still have two Active Directory forests, two Exchange organizations, two hygiene platforms, separate accepted domains and MX records, and a collection of applications relaying mail through endpoints that were never fully documented.
Those risks carry very different weight. A branding delay is noticeable, but a mail-flow outage is a real operational incident — and in a regulated environment, it can quickly become a much bigger business and compliance issue.
So I keep the objective narrow: present the new identity, avoid unnecessary changes to the delivery path, and make every change reversible.
Why the obvious plans don’t survive
Cut everything over at once. Move MX, hygiene, mailboxes, and application relay in the same window and troubleshooting becomes guesswork. If mail stops, you have changed DNS, filtering, connectors, and recipient routing at the same time.
Migrate the mailboxes first. Architecturally, that is cleaner. Operationally, a large mailbox migration usually runs in waves, while the brand date is fixed.
Consolidate onto one hygiene platform on day one. That sounds appealing, but both platforms usually carry years of tuning, exceptions, allow lists, and business-specific policy. Folding a security-platform migration into the same cutover adds another failure domain when the goal should be reducing them.
The shape of the design
Use Exchange Online as the single ingress point for the new corporate domain, then route by recipient domain using mail flow rules and transport-rule-scoped connectors.
The corporate domain’s MX points to Exchange Online and the domain is configured as Internal Relay during coexistence. Known cloud recipients deliver locally; recipients that are not hosted in Microsoft 365 can be relayed through the appropriate connector. Users receive the new corporate address as primary SMTP while the legacy address remains as an alias. For non-migrated users, a reliable recipient attribute can be used to select the correct routing rule and connector.
Every routing rule also needs loop prevention. If the message is returning from a trusted hygiene or on-premises path, the routing rule must not send it straight back out again.
The legacy domains can keep their existing MX records during the transition, so mail sent to legacy addresses follows the established path until those domains are retired.
Figure 1. Current state — two organizations, two hygiene platforms, one shared tenant
Figure 2. Transitional state — one rebranded corporate domain, split by two legacy recipient domains
The decisions behind it
Route on the recipient, not the sender. External senders do not carry your organizational attributes, and sender-based logic becomes ambiguous very quickly. Recipient-based routing works, but it makes directory quality a hard dependency: the attribute you route on has to be present, synchronized, and predictable.
Accept once, then split. That introduces an extra hop, so it will show up in headers and traces. Support teams need to know that this is expected. Trying to split the same namespace with competing MX targets is not a routing strategy; MX preference is designed for server selection and failover, not deterministic recipient steering.
Internal Relay, not Authoritative. During coexistence, an Authoritative domain expects Exchange Online to know every valid recipient and rejects unknown recipients. Internal Relay is designed for a shared namespace where some recipients live outside Microsoft 365, provided the connector back to that environment is configured correctly. Treat it as a transitional state and remove it when coexistence is over.
Getting the security teams aligned
Two hygiene platforms usually means two security teams, each with years of tuning and a strong opinion about which platform should survive.
I would keep the hygiene consolidation out of the announcement-day cutover. The immediate goal is to make sure both platforms can coexist and route mail safely. Deciding which platform ultimately stays can happen as a separate workstream once the merger is stable.
What the teams do need to agree on is operational: who owns the first trace when a message goes missing, a common header for rerouted mail, how return traffic is recognized, one joint incident bridge, and enough trace retention across all systems to investigate issues after the fact.
The custom routing header is worth standardizing. It gives both platforms and every engineer running a trace a deterministic marker that the message already took the merger route.
How routing actually resolves
The important part is understanding which decisions are controlled by Exchange Online and which are controlled by the connector or the rule. For an inbound message to a shared Internal Relay domain, I validate the path in this order:
- Inbound connector. Confirm which connector matched the sending IP or TLS identity. That tells you which source Exchange Online trusted for the connection.
- Accepted domain. Internal Relay allows the namespace to contain both Microsoft 365 recipients and recipients hosted elsewhere.
- Recipient resolution. If the recipient exists in Exchange Online, normal recipient routing applies. If the recipient is not hosted in Microsoft 365, the connector design for the Internal Relay namespace has to provide a valid onward path.
- Mail flow rules. Rules are evaluated in priority order. Because multiple rules can match the same message, routing rules should be mutually exclusive and should normally stop further rule processing once the correct connector has been selected.
- Connector selection. The RouteMessageOutboundConnector action sends the message through the named outbound connector. I pair that action with the routing marker and StopRuleProcessing so another lower-priority rule cannot act on the same message.
- Outbound connector. The configured smart host, TLS settings, and certificate validation determine the next hop.
The practical point is simple: priority matters, but priority alone is not enough. If two routing rules can match, make the conditions mutually exclusive and stop processing after a routing decision. Loop prevention also belongs in each routing rule so it is evaluated every time the message is considered for that path.
Figure 3. Recipient-scoped routing decision tree
The accepted domain set
The domain type is one of the most important controls in this design.
| Domain | Type | Purpose |
|---|---|---|
| Corporate domain | InternalRelay | The published identity; MX points here |
| Legacy domain A | InternalRelay | Retained as alias; own MX to hygiene A |
| Legacy domain B | InternalRelay | Retained as alias; own MX to hygiene B |
| tenant.mail.onmicrosoft.com | Authoritative | Hybrid routing address; never published |
| tenant.onmicrosoft.com | Authoritative | Default tenant domain |
Set the corporate domain to Authoritative before all recipients are represented correctly and you can create broad non-delivery for users who still live outside Microsoft 365. That is completely avoidable during coexistence.
Internal Relay also requires a working connector to the environment that hosts the unresolved recipients. Without that onward route, those users will not receive mail. I validate the connector and the recipient representation before changing MX.
Directory-Based Edge Blocking behaves differently as well. Authoritative domains can reject invalid recipients at the service edge. With Internal Relay, Exchange Online cannot assume that an unknown cloud recipient is invalid because that recipient may exist in the other environment. That is another reason to keep Internal Relay limited to the coexistence window.
A note on centralized mail transport
The Hybrid Configuration Wizard can enable Centralized Mail Transport, which routes outbound Exchange Online mail back through the on-premises organization.
In a split coexistence design, I avoid enabling CMT by default. It is a tenant-wide routing choice, so using it to satisfy one predecessor’s requirement can pull unrelated outbound mail through infrastructure owned by the other side. It also adds another routing layer to troubleshoot alongside the scoped connector rules.
If only one domain needs a specific outbound inspection path, I would rather scope that requirement to the domain with a dedicated rule and connector.
Envelope versus header
Two things are often mixed together here. The visible sender is the RFC 5322 From header. The SMTP envelope sender is the RFC 5321 MAIL FROM address used for the return path and evaluated by SPF. They can be different, so test both.
For user mail, I prefer changing the primary SMTP address instead of rewriting the message in transport. Exchange then builds new outbound mail with the corporate address as the user’s normal identity, replies come back to the new accepted domain, and you avoid unnecessary manipulation of signed message headers. SPF and DKIM still depend on the actual outbound path and the DNS/signing configuration for the new domain, so those controls need to be validated as part of cutover.
I reserve transport rewriting for applications or legacy systems that cannot be reconfigured cleanly.
| External sender | Exchange Online | Transport rules | Hygiene platform | Recipient mailbox |
|---|---|---|---|---|
| 1. RCPT TO: user@newcorp.example | 2. Accepted-domain lookup + recipient resolution | |||
| 3. Match recipient rule + stamp loop-prevention header | ||||
| 4. Route through scoped outbound connector | Inspection path | |||
| 5. Return after hygiene scan | Header preserved | |||
| 6. Deliver | Recipient mailbox | |||
| 7. Reply uses new corporate From / Reply-To address |
Figure 4. Corporate SMTP routing sequence across a shared namespace
The things that behave differently
A few cases need their own test instead of being assumed to behave like a normal user mailbox.
Replies follow Reply-To when it is present; otherwise the visible From address normally drives the reply. With the corporate address as the user’s primary identity, that return traffic enters through the new corporate namespace.
Forwarding rules and contacts created before the merger may still reference legacy addresses. They continue to work only while those legacy domains and objects remain routable, so they need to be part of the retirement plan.
NDR behavior follows the SMTP envelope and the system that ultimately generates the failure. If an application or relay still submits with a legacy envelope sender, the bounce can still return to that legacy identity.
Applications are different because many of them use a hard-coded sender and a fixed relay endpoint. A mailbox address change does nothing for an application that never uses the mailbox.
Distribution groups need special treatment. Recipient AD-attribute conditions such as RecipientADAttributeContainsWords are evaluated for individual recipients and do not work against distribution groups. Do not assume a mixed-membership group will automatically split into the correct hygiene paths based on member attributes. Test the group path separately and, where necessary, redesign the routing condition around a supported group or recipient model.
Figure 5. Multi-hygiene connector topology
A message here can cross three trace surfaces. The MessageId is the join key. Preserve it, never generate a new one through a re-injection path, and cross-platform tracing stays possible.
A message in this design may cross three trace surfaces. I use the Internet Message-ID as the common correlation key wherever the platforms preserve it, then confirm each hop with Exchange Online trace events and the Received headers.
| Event | What it tells you |
|---|---|
| RECEIVE / connector details | Which inbound path accepted the message and which connector metadata is present |
| TRANSPORTRULE | Which mail flow rules matched and what actions were recorded |
| SEND | The message left Exchange Online; correlate the target and connector details |
| DELIVER | Local mailbox delivery |
| EXPAND | Distribution group expansion event, when applicable |
| DEFER | Delivery was deferred; inspect the detail for the actual reason |
| FAIL | Delivery failed; use the enhanced status and detail to identify why |
Read the Exchange Online trace in time order and reconstruct the path from the events that are actually present.
Headers give you the second half of the story. A message that left Exchange Online for a hygiene platform and then returned should show that round trip in the Received chain, plus the custom routing marker. If the marker exists but the return hop does not, the investigation moves to the hygiene platform. If the marker is absent, start with the rule conditions and connector selection in Exchange Online.
What goes wrong
| Symptom | Likely cause | First check |
|---|---|---|
| Mail loop, hop count exceeded | Loop-prevention exception missing or in the wrong rule | Confirm the exception is inside the routing rule |
| NDR: recipient not found | Corporate domain set authoritative too early | Accepted domain type |
| Mail delivered but not scanned | Rule condition not matching the recipient attribute | The attribute value on the recipient object |
| TLS failure to hygiene platform | Certificate subject mismatch or expiry | Connector TLS domain against the presented certificate |
| Internal mail taking an external hop | FromScope NotInOrganization missing | Add the scope condition |
| Replies going to the legacy address | Address added but not promoted | Confirm the address is primary, not secondary |
| Message queued then expired | Internal Relay path has no valid onward connector or target | Accepted domain, connector scope, and smart-host reachability |
| Both rules fired on one message | Routing conditions overlap or rule processing was not stopped | Make the conditions mutually exclusive and use StopRuleProcessing |
| Mail scanned twice | Loop-prevention header stripped in transit | Confirm the hygiene platform preserves custom headers |
One more reason not to use a loose UPN match: RecipientADAttributeContainsWords is a word-based match, not a suffix-aware routing primitive. If you need deterministic namespace routing, use an attribute and condition that cannot overlap, or use RecipientADAttributeMatchesPatterns with an anchored pattern. The goal is to make it impossible for two routing rules to match the same recipient.
Validating and backing out
I run the test matrix before every migration wave, including the cases that look obvious.
| Sender | Recipient | Expected path |
|---|---|---|
| External | Migrated user, corporate address | Ingress, local delivery |
| External | Non-migrated user A, corporate address | Ingress, connector A, on to on-premises |
| External | Non-migrated user B, corporate address | Ingress, connector B, on to on-premises |
| External | Any user, legacy address | Legacy MX path, unchanged |
| Domain A user | Domain B user | Internal, no external hop |
| Migrated user | External | Outbound, corporate address in From: |
| Application | Internal and external | Relay connector, legacy identity |
| Distribution group | Mixed membership | Separate group-specific test; do not assume member attributes drive routing |
| Hygiene platform | Returning message | Accepted, rules skipped |
| External | Invalid recipient | Expected NDR behaviour confirmed; no mail loop or backscatter surprise |
Rollback, in increasing order of impact:
- Disable the affected mail flow rule. Fastest and least invasive; it removes only the scoped routing decision.
- Revert the primary SMTP address for the wave if the identity change itself is causing the issue. The legacy address should still exist as an alias during the rollback window.
- Disable or bypass the affected connector only with a documented alternate path. Do not assume Exchange Online will fall back safely; connector scope and recipient routing determine what happens next.
- Revert MX only as a last resort. DNS rollback is the slowest option because cache and propagation are outside your direct control.
Before cutover, lower the corporate domain’s MX TTL far enough in advance for the previous TTL to age out. The exact number is less important than making sure the old cached value has expired before you depend on a faster rollback.
Closing
The design works when the basics are right: the accepted-domain type, deterministic and loop-safe routing rules, tested connectors, and a rollback the team has already rehearsed. If those are boring on cutover day, that is a success.
Implementation examples
Connectors
IsTransportRuleScoped keeps an outbound connector from being selected by normal recipient-domain routing; the connector is used when a mail flow rule explicitly selects it. For inbound trust, certificate or IP restrictions should match the actual security model of the sending platform and should be tested before production cutover.
Connect-ExchangeOnlineNew-OutboundConnector -Name "Route to Hygiene A" ` -ConnectorType Partner -UseMXRecord $false ` -SmartHosts "gateway-a.hygiene.example" ` -TlsSettings CertificateValidation -TlsDomain "*.hygiene.example" ` -IsTransportRuleScoped $true -Enabled $trueNew-OutboundConnector -Name "Route to Hygiene B" ` -ConnectorType OnPremises -UseMXRecord $false ` -SmartHosts "10.50.10.25" ` -TlsSettings EncryptionOnly ` -IsTransportRuleScoped $true -Enabled $trueNew-InboundConnector -Name "From Hygiene A" ` -ConnectorType Partner -SenderDomains * -RequireTls $true ` -TlsSenderCertificateName "*.hygiene.example" ` -RestrictDomainsToCertificate $true -Enabled $trueNew-InboundConnector -Name "From On-Premises B" ` -ConnectorType OnPremises -SenderDomains * ` -SenderIPAddresses "203.0.113.16/28" -RequireTls $true -Enabled $true
The routing rules
New-TransportRule -Name "Corporate to Hygiene A" ` -RecipientAddressMatchesPatterns "@corporate\.com$" ` -RecipientADAttributeMatchesPatterns "UserLogonName:@legacydomain-a\.com$" ` -FromScope NotInOrganization ` -ExceptIfHeaderContainsMessageHeader "X-InterOrg-Routed" ` -ExceptIfHeaderContainsWords "Corporate" ` -RouteMessageOutboundConnector "Route to Hygiene A" ` -SetHeaderName "X-InterOrg-Routed" -SetHeaderValue "Corporate" ` -StopRuleProcessing $true ` -Mode Enforce -Priority 0New-TransportRule -Name "Corporate to Hygiene B" ` -RecipientAddressMatchesPatterns "@corporate\.com$" ` -RecipientADAttributeMatchesPatterns "UserLogonName:@legacydomain-b\.com$" ` -FromScope NotInOrganization ` -ExceptIfHeaderContainsMessageHeader "X-InterOrg-Routed" ` -ExceptIfHeaderContainsWords "Corporate" ` -RouteMessageOutboundConnector "Route to Hygiene B" ` -SetHeaderName "X-InterOrg-Routed" -SetHeaderValue "Corporate" ` -StopRuleProcessing $true ` -Mode Enforce -Priority 1Get-TransportRule | Sort-Object Priority | Select-Object Priority, Name, State, Mode, @{n='RoutesTo';e={$_.RouteMessageOutboundConnector}} | Format-Table -AutoSize
Application relay inventory
Application relay inventory comes from configuration and telemetry, not just documentation. I normally check what is allowed to relay, what has actually submitted mail, and what is submitting through the cloud.
# On-premises: what is permitted to relay.Get-ReceiveConnector | Where-Object { $_.PermissionGroups -match "AnonymousUsers" } | Select-Object Server, Name, Bindings, @{n='Sources';e={ ($_.RemoteIPRanges | Select-Object -First 20) -join ',' }} | Export-Csv .\onprem-relay-permitted.csv -NoTypeInformation# What actually submitted. Use 35 days so month-end jobs are caught.Get-ExchangeServer | Where-Object ServerRole -match "Mailbox" | ForEach-Object { Get-MessageTrackingLog -Server $_.Name -EventId RECEIVE ` -Start (Get-Date).AddDays(-35) -End (Get-Date) -ResultSize Unlimited} | Where-Object { $_.Source -eq "SMTP" -and $_.ConnectorId -notmatch "Hybrid" } | Group-Object ClientIp | Sort-Object Count -Descending | Select-Object Count, Name | Export-Csv .\onprem-relay-actual.csv -NoTypeInformation# Cloud-side submissions.Get-MessageTraceV2 -StartDate (Get-Date).AddDays(-10) -EndDate (Get-Date) -PageSize 5000 | Where-Object { $_.FromIP } | Group-Object FromIP | Sort-Object Count -Descending | Select-Object -First 40 Count, Name
For every source, record the submitting IP, sender identity, recipients, whether it delivers internally or externally, and the business owner. Finding the owner usually takes longer than finding the relay, and it is the part the migration depends on.
Tracing
Get-MessageTraceV2 -SenderAddress "sender@external.example" ` -RecipientAddress "user@corporate.example" ` -StartDate (Get-Date).AddDays(-2) -EndDate (Get-Date) | Format-Table Received, RecipientAddress, Status, MessageIdGet-MessageTraceDetailV2 -MessageTraceId <id> -RecipientAddress "user@corporate.example" | Format-List Date, Event, Action, Detail# Which rules are firing, and how often.Get-MailTrafficPolicyReport -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) ` -EventType "TransportRule" | Group-Object Action | Select-Object Name, Count | Sort-Object Count -Descending
Configuration backup
Run this before each change window so you have a configuration snapshot to compare against or rebuild from.
$stamp = Get-Date -f yyyyMMdd-HHmmGet-TransportRule | Export-Clixml ".\rules-$stamp.xml"Get-OutboundConnector | Export-Clixml ".\outbound-$stamp.xml"Get-InboundConnector | Export-Clixml ".\inbound-$stamp.xml"Get-AcceptedDomain | Export-Clixml ".\domains-$stamp.xml"

