Enabling hybrid mail flow for migrated distribution lists.
There may be circumstances where mail flow continues through the Exchange on-premises environment. Customers may choose to continue to have their MX records route through Exchange, mailboxes may not have been migrated, or the Exchange solution may be retained as an SMTP relay for internal applications. All of these circumstances may require that mail flow continue to the distribution list even though the group has been migrated to Office 365. Customers may also have chosen to enable centralized mail flow which routes email to the on-premises environment for routing decisions.
Creating a solution that allows for cross-premises mail flow was quite a challenge. First you have to have a method to allow the same SMTP address to exist in the on-premises directory and in the Office 365 directory but on different objects. There has to be a mail object that exists in both directories so that DL membership and other dependencies can be tracked (See Office 365 – Distribution List Migrations Version 2.0 – Part 6). In addition, a method is needed to maintain the nickname cache and allow the recipient to appear in the groups within address book views. Messages that are transferred between on-premises Exchange and Office 365 should be secure and viewed as internal (and not anonymous).
In the distribution list migration module, administrators have the ability to enable hybrid mail flow. Using the -enableHybridMailFlow:$TRUE switch requires the use of an on-premises Exchange server. This is due to the remote PowerShell dependencies with creating objects.
The first step in enabling hybrid mail flow is to mail enable the contact object created through ADSI. This is facilitated by calling the update-recipient cmdlet. In addition to calling update recipient, the external address of the mail contact is set to the unique onmicrosoft.com address assigned to the new distribution list when created in Office 365. This serves as the routing link between on-premises and Office 365. The mail contact cannot share the same email addresses as the migrated group. If it did, when Azure AD Connect replicates the object to Office 365, a proxy address collision would occur. This necessitates using another object to hold the proxy addresses of the migrated distribution list.
[PS] C:\>Get-MailContact TestNewParameter-MigratedByScript | fl name,alias,externalEmailAddress,emailaddresses,customAttribute1,CustomAttribute2
Name : TestNewParameter-MigratedByScript
Alias : TestNewParameter-MigratedByScript
ExternalEmailAddress : SMTP:TESTNEWPARAMETER@domain.MAIL.ONMICROSOFT.COM
EmailAddresses : {x500:/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=6a14b390befd42e59d155cfdc9a45651-TestNewPara, smtp:TestNewParameter-MigratedByScript@domain.mail.onmicrosoft.com, SMTP:TestNewParameter-MigratedByScript@domain.com}
CustomAttribute1 : MigratedByScript
CustomAttribute2 : TestNewParameter@domain.com
The second step is to create a dynamic distribution group. Why would a dynamic distribution group be created in order to assist with mail flow? First, the dynamic distribution group can never be replicated by Azure AD Connect. This ensures that the object that will hold the SMTP addresses of the migrated distribution list will never collide with the object already created in Office 365 and will never soft match to the existing group. Second, it’s a distribution group by definition. This means that customers who use address book views heavily and look for group filters will still see distribution groups in the view they expect to see them, versus looking for a mail enabled contact that would not be in the same view. The dynamic distribution group is created with the same attributes as the distribution list that was migrated. Name, display name, alias, proxy addresses, and mail attributes all match. Additionally, the legacyExchangeDN of the original group is added as an X500 address of the dynamic distribution list preserving nickname cache. A dynamic distribution list must have a set of filtered criteria for recipients to include. In this case, the criteria are custom attribute 1 “MigratedByScript” and custom attribute 2 “Proxy Address of Migrated Group.” This ensures that the dynamic distribution list has one member: the mail contact that was created in place of the migrated distribution group.
[PS] C:\>Get-DynamicDistributionGroup TestNewParameter | fl name,alias,emailaddresses,*filter*
Name : TestNewParameter
Alias : TestNewParameter
EmailAddresses : {x500:/o=Home/ou=Exchange Administrative Group
(FYDIBOHF23SPDLT)/cn=Recipients/cn=b13dd7a5e1df487f8b250f4c4138986f-TestNew,
smtp:TestNewParameter0@domain.com, smtp:TestNewParameter1@domain.com,
smtp:TestNewParameter2@domain.com, smtp:TestNewParameter3@domain.com,
smtp:TestNewParameter4@domain.com, smtp:TestNewParameter5@domain.com,
smtp:TestNewParameter6@domain.com, smtp:TestNewParameter7@domain.com,
smtp:TestNewParameter8@domain.com, smtp:TestNewParameter9@domain.com,
smtp:TestNewParameter10@domain.com, smtp:TestNewParameter11@domain.com,
smtp:TestNewParameter12@domain.com, smtp:TestNewParameter13@domain.com,
smtp:TestNewParameter14@domain.com…}
RecipientFilter : ((((CustomAttribute1 -eq ‘MigratedByScript’) -and (CustomAttribute2 -eq
‘TestNewParameter@domain.com’) -and (Alias -ne $null))) -and (-not(Name -like
‘SystemMailbox{*’)) -and (-not(Name -like ‘CAS_{*’)) -and (-not(RecipientTypeDetailsValue -eq
‘MailboxPlan’)) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)) -and
(-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)) -and (-not(RecipientTypeDetailsValue
-eq ‘ArbitrationMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)) -and
(-not(RecipientTypeDetailsValue -eq ‘AuxAuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue
-eq ‘SupervisoryReviewPolicyMailbox’)))
LdapRecipientFilter : (&(extensionAttribute1=MigratedByScript)(extensionAttribute2=TestNewParameter@domain.com)(ma
ilNickname=*)(!(name=SystemMailbox{*))(!(name=CAS_{*))(!(msExchRecipientTypeDetails=16777216))(!(
msExchRecipientTypeDetails=536870912))(!(msExchRecipientTypeDetails=68719476736))(!(msExchRecipie
ntTypeDetails=8388608))(!(msExchRecipientTypeDetails=4398046511104))(!(msExchRecipientTypeDetails
=70368744177664))(!(msExchRecipientTypeDetails=140737488355328)))
RecipientFilterType : Precanned
How does this setup facilitate mail flow? Assuming we have an application on-premises that relays through Exchange and sends email to MigratedDL@contoso.com. Originally this was an on-premises distribution list and the membership would have been directly expanded and the message delivered to the recipients based on this expansion. For a migrated distribution list, the message is routed to the dynamic distribution group. When the dynamic group is expanded, there is a single recipient found: the mail contact created. Transport then re-routes the email to the mail contact, which has an external email using the onmicrosoft.com address of the migrated DL. In a hybrid environment, secure connectors are created for the mail.onmicrosoft.com namespace to ensure authentication occurs on cross-premises mail flow. Transport re-routes the message to migratedDL@contoso.mail.onmicrosoft.com. This namespace matches the hybrid connector and is routed to Office 365. Upon arrival in Office 365, the message is evaluated and migratedDL@contoso.mail.onmicrosoft.com is found as a secondary proxy on the group MigratedDL@contoso.com. The address is changed to MigratedDL@contoso.com at which point the group is expanded. The message is then delivered to the expanded group.
Here are sample message tracking events to follow the mail flow.
- Drop message for on-premises distribution list expansion.
RunspaceId : da80b36e-c62c-41d9-8244-991a146b7075
Timestamp : 4/1/2021 4:19:35 PM
ClientIp :
ClientHostname : server-Mail-0
ServerIp :
ServerHostname :
SourceContext :
ConnectorId :
Source : ROUTING
EventId : DROP
InternalMessageId : 87617332838410
MessageId : 5b55a8f65beb4062b9c7b4376972ba86@domain.com
NetworkMessageId : 8f58f417-29d7-43d4-1a4e-08d8f529f062
Recipients : {MemberTest@domain.com}
RecipientStatus : {[{LED=250 2.1.5 RESOLVER.GRP.Expanded; distribution list
expanded};{MSG=};{FQDN=};{IP=};{LRT=}]}
TotalBytes : 8759
RecipientCount : 1
RelatedRecipientAddress :
Reference :
MessageSubject : Test Routing 2
Sender : TIM@domain.com
ReturnPath : TIM@domain.com
Directionality : Originating
TenantId :
OriginalClientIp :
MessageInfo :
MessageLatency :
MessageLatencyType : None
EventData : {[DeliveryPriority, Normal], [AccountForest, home.domain.com]}
TransportTrafficType : Email
SchemaVersion : 15.02.0792.010
- Expansion event resolving to the mail enabled migration contact.
RunspaceId : da80b36e-c62c-41d9-8244-991a146b7075
Timestamp : 4/1/2021 4:19:35 PM
ClientIp :
ClientHostname :
ServerIp :
ServerHostname : server-Mail-0
SourceContext : server-DC-0.home.domain.com
ConnectorId :
Source : ROUTING
EventId : EXPAND
InternalMessageId : 87617332838410
MessageId : 5b55a8f65beb4062b9c7b4376972ba86@domain.com
NetworkMessageId : 8f58f417-29d7-43d4-1a4e-08d8f529f062
Recipients : {MemberTest-MigratedByScript@domain.com}
RecipientStatus : {250 2.1.5 RESOLVER.GRP.Expanded; distribution list expanded}
TotalBytes : 7896
RecipientCount : 1
RelatedRecipientAddress : MemberTest@domain.com
Reference :
MessageSubject : Test Routing 2
Sender : TIM@domain.com
ReturnPath : TIM@domain.com
Directionality : Originating
TenantId :
OriginalClientIp :
MessageInfo :
MessageLatency :
MessageLatencyType : None
EventData : {[DeliveryPriority, Normal], [AccountForest, home.domain.com]}
TransportTrafficType : Email
SchemaVersion : 15.02.0792.010
- Mail enabled contact resolved to target address (which is a secondary address of the migrated distribution list)
RunspaceId : da80b36e-c62c-41d9-8244-991a146b7075
Timestamp : 4/1/2021 4:19:35 PM
ClientIp :
ClientHostname :
ServerIp :
ServerHostname : server-Mail-0
SourceContext :
ConnectorId :
Source : ROUTING
EventId : RESOLVE
InternalMessageId : 87617332838410
MessageId : 5b55a8f65beb4062b9c7b4376972ba86@domain.com
NetworkMessageId : 8f58f417-29d7-43d4-1a4e-08d8f529f062
Recipients : {MEMBERTEST@domain.MAIL.ONMICROSOFT.COM}
RecipientStatus : {}
TotalBytes : 7896
RecipientCount : 1
RelatedRecipientAddress : MemberTest-MigratedByScript@domain.com
Reference :
MessageSubject : Test Routing 2
Sender : TIM@domain.com
ReturnPath : TIM@domain.com
Directionality : Originating
TenantId :
OriginalClientIp :
MessageInfo :
MessageLatency :
MessageLatencyType : None
EventData : {[DeliveryPriority, Normal], [AccountForest, home.domain.com]}
TransportTrafficType : Email
SchemaVersion : 15.02.0792.010
- Message transferred via the hybrid connector using certificate-based security.
RunspaceId : da80b36e-c62c-41d9-8244-991a146b7075
Timestamp : 4/1/2021 4:19:37 PM
ClientIp : 10.0.0.20
ClientHostname : server-Mail-0
ServerIp :
ServerHostname : domain-mail-onmicrosoft-com.mail.protection.outlook.com
SourceContext : ;250 2.6.0 5b55a8f65beb4062b9c7b4376972ba86@domain.com [InternalId=21801253998737,
Hostname=DM5PR04MB0619.namprd04.prod.outlook.com] 10314 bytes in 0.141, 71.363 KB/sec Queued
mail for delivery;ClientSubmitTime:
ConnectorId : Outbound to Office 365
Source : SMTP
EventId : SENDEXTERNAL
InternalMessageId : 87617332838413
MessageId : 5b55a8f65beb4062b9c7b4376972ba86@domain.com
NetworkMessageId : 8f58f417-29d7-43d4-1a4e-08d8f529f062
Recipients : {MEMBERTEST@domain.MAIL.ONMICROSOFT.COM}
RecipientStatus : {250 2.1.5 Recipient OK}
TotalBytes : 6935
RecipientCount : 1
RelatedRecipientAddress :
Reference :
MessageSubject : Test Routing 2
Sender : TIM@domain.com
ReturnPath : TIM@domain.com
Directionality : Originating
TenantId :
OriginalClientIp :
MessageInfo : 2021-04-01T16:19:34.691Z;SRV=server-Mail-0.home.domain.com:TOTAL-SUB=0.163|SA=0.125|MTSS-
PEN=0.039(MTSSD-PEN=0.038(MTSSDA=0.002|MTSSDC=0.005|SDSSO-PEN=0.019 (SMSC=0.014|MTSSDM-PEN=0.
004)));SRV=server-Mail-0.home.domain.com:TOTAL-HUB=2.232|SMR=0.133(SMRDI=0.005|SMRC=0.127
(SMRCL=0.102|X-SMRCR=0.127))|CAT=0.196(CATOS=0.036(CATSM=0.036(CATSM-Malware
Agent=0.035))|CATRESL=0.020(X-CATRESLX=0.008)|CATORES=0.008(CATRS=0.007(CATRS-Index Routing
Agent=0.006))|CATORT=0.111(CATRT=0.111(CATRT-RMS Encryption Agent=0.002|CATRT-Journal
Agent=0.109))|CATCC=0.008|CATBIF=0.001)|QDE=0.153|SMSC=0.647(X-SMSDR=0.152)|SMS=1.100
MessageLatency : 00:00:02.3930000
MessageLatencyType : EndToEnd
EventData : {[E2ELatency, 2.393], [ExternalSendLatency, 0.492], [ToEntity, Internet], [FromEntity,
Hosted], [MsgRecipCount, 1], [IncludeInSla, True],
[Microsoft.Exchange.Transport.MailRecipient.RequiredTlsAuthLevel, DomainValidation],
[Microsoft.Exchange.Transport.MailRecipient.EffectiveTlsAuthLevel, DomainValidation],
[IsSmtpResponseFromExternalServer, True], [DeliveryPriority, Normal], [AccountForest,
home.domain.com]}
TransportTrafficType : Email
SchemaVersion : 15.02.0792.010
- The message is received in Office 365 and the distribution group is expanded.
Message Trace ID : 2b83eb1b-af9d-4806-78aa-08d8f529f12b
Message ID : <5b55a8f65beb4062b9c7b4376972ba86@domain.com>
Date : 4/1/2021 4:19:37 PM
Event : Receive
Action :
Detail : Message received by: DM5PR04MB0619.namprd04.prod.outlook.com using TLS1.2 with AES256
Data : <root><MEP Name=”ConnectorId” String=”DM5PR04MB0619\Default DM5PR04MB0619″/><MEP Name=”ClientIP”
String=”2603:10b6:300:116::19″/><MEP Name=”ServerHostName”
String=”DM5PR04MB0619.namprd04.prod.outlook.com”/><MEP name=”FirstForestHop”
String=”DM5PR04MB0619.namprd04.prod.outlook.com”/><MEP Name=”DeliveryPriority”
String=”Normal”/><MEP Name=”ReturnPath” String=”TIM@domain.com”/><MEP Name=”CustomData” Blob=”S
:ProxyHop1=CO1NAM04FT009.mail.protection.outlook.com(10.152.90.137);S:ProxyHop2=MWHPR07CA0009.outloo
k.office365.com(2603:10b6:300:116::19);’S:InboundConnectorData=Name=Inbound from 19df6a88-b887-4e90-
8b47-31d6cfb90aca;ConnectorType=OnPremises;TenantId=f7d9d2a4-dded-4f6f-90a9-5011281137b9′;S:tlsversi
on=SP_PROT_TLS1_2_SERVER;S:tlscipher=CALG_AES_256;S:Oorg=domain.com”/><MEP
Name=”SequenceNumber” Long=”0″/><MEP Name=”RecipientReference” String=””/></root>
Message Trace ID : 2b83eb1b-af9d-4806-78aa-08d8f529f12b
Message ID : <5b55a8f65beb4062b9c7b4376972ba86@domain.com>
Date : 4/1/2021 4:19:37 PM
Event : Resolve
Action :
Detail : The message was resolved to membertest@domain.com.
Data : <root><MEP Name=”ServerHostName” String=”DM5PR04MB0619″/><MEP Name=”SourceContext” String=”Rewrite
to Primary”/><MEP Name=”ReturnPath” String=”TIM@domain.com”/><MEP Name=”SequenceNumber”
Long=”0″/><MEP Name=”RecipientReference” String=””/><MEP Name=”RelatedRecipient”
String=”membertest@domain.com”/></root>
Message Trace ID : 2b83eb1b-af9d-4806-78aa-08d8f529f12b
Message ID : <5b55a8f65beb4062b9c7b4376972ba86@domain.com>
Date : 4/1/2021 4:19:37 PM
Event : Expand DL
Action :
Detail : The message was sent to a distribution list (DL) that was expanded to the recipients of the DL.
Data : <root><MEP Name=”RcptCount” Integer=”1″/><MEP Name=”ServerHostName” String=”DM5PR04MB0619″/><MEP
Name=”SourceContext” String=”BY5PR04A04DC006.NAMPR04A004.prod.outlook.com”/><MEP Name=”ReturnPath”
String=”TIM@domain.com”/><MEP Name=”ClientName” String=””/><MEP Name=”SequenceNumber”
Long=”0″/><MEP Name=”RecipientStatus” String=”250 2.1.5 RESOLVER.GRP.Expanded; distribution list
expanded”/><MEP Name=”RecipientReference” String=””/></root>
Message Trace ID : 2b83eb1b-af9d-4806-78aa-08d8f529f12b
Message ID : <5b55a8f65beb4062b9c7b4376972ba86@domain.com>
Date : 4/1/2021 4:19:39 PM
Event : Drop
Action :
Detail : Reason: [{LED=250 2.1.5 RESOLVER.GRP.Expanded; distribution list
expanded};{MSG=};{FQDN=};{IP=};{LRT=}]
Data : <root><MEP Name=”SourceContext” String=””/><MEP Name=”ReturnPath”
String=”TIM@domain.com”/><MEP Name=”ClientName”
String=”DM5PR04MB0619.namprd04.prod.outlook.com”/><MEP Name=”SequenceNumber” Long=”0″/><MEP
Name=”RecipientStatus” String=”[{LED=250 2.1.5 RESOLVER.GRP.Expanded; distribution list
expanded};{MSG=};{FQDN=};{IP=};{LRT=}]”/><MEP Name=”RecipientReference” String=””/></root>
Here is an example of the original group retained, the hybrid mail contact created, and the dynamic distribution group.
Sample Flow: