While ago I suddenly got multiple prioritized reports of email not being delivery to users in one specific external organization. Actually, it wasn’t even the first time. It took me a while to fix the situation and after that some digging to understand what had happened.
A little more than a year ago I wrote about guest users and how those are actually implemented. Guest users have been popular due to their relation to Teams and Sharepoint (or OneDrive). They are also heavily used for other B2B scenarios as well.
Due to guest users being used so widely, also undesired things happen every now and then. This blog tries to explain what relation guest users have to email forwarding and what could go wrong. When things go wrong, emails your organization is sending will be unintentionally forwarded to a different address than they were sent!
The interesting attribute for a guest account in this relation is the “proxy addresses”, it is visible in AzureAD portal and of course from Get-AzureADUser as well. By default, this will contain one value that is the one where the invite was originally sent. There is a chance that you end up with multiple proxy addresses there!
In this example the scenario is such that the external partner decides to re-brand their business and as part of it also change the email addresses. Eventually they decide to remove the old addresses and then the strange things starts to happen.

The interesting part is that when you send the invite, your tenant seems to be aware of the target account, even with zero activity from the recipient. I didn’t find a way of checking it, but the next steps will reveal there is something happening in the background. When you send another invite to the same recipient, with another email address, your tenant will detect it is the same account you have already invited.
The following Powerscript shows this happening in my test environment
# First invitation to .se address
PS > New-AzureADMSInvitation -InvitedUserEmailAddress "***.***@***.se" -SendInvitationMessage $false -InviteRedirectUrl "https://localhost"
Id : ********-****-****-****-********832da
InvitedUserDisplayName :
InvitedUserEmailAddress : ***.***@***.se
SendInvitationMessage : False
InviteRedirectUrl : https://localhost/
InvitedUser : class User {
Id: ********-****-****-****-********8394
OdataType:
}
# Results UPN with .se and ProxyAddress with .se
PS > Get-AzureADUser -ObjectID "********-****-****-****-********8394" | select displayname,UserPrincipalName,proxyaddresses | fl
DisplayName : ***.***
UserPrincipalName : ***.***_***.se#EXT#@***.onmicrosoft.com
ProxyAddresses : {SMTP:***.***@***.se}
# Second invitation to .com address
PS > New-AzureADMSInvitation -InvitedUserEmailAddress "***.***@***.com" -SendInvitationMessage $false -InviteRedirectUrl "https://localhost"
Id : ********-****-****-****-********832da
InvitedUserDisplayName :
InvitedUserEmailAddress : ***.***@***.com
SendInvitationMessage : False
InviteRedirectUrl : https://localhost/
InvitedUser : class User {
Id: ********-****-****-****-********8394
OdataType:
}
## Results the same exact Guest object "...8394" with UPN having ".se" ##
## ProxyAddresses has now both .se AND .com. .se remains as primary! ##
PS > Get-AzureADUser -ObjectID "********-****-****-****-********8394" | select displayname,UserPrincipalName,proxyaddresses | fl
DisplayName : ***.***
UserPrincipalName : ***.***_***.se#EXT#@***.onmicrosoft.com
ProxyAddresses : {smtp:***.***@***.com, SMTP:***.***@***.se}
The problematic thing is that while AzureAD seems to be able to match multiple email addresses to one actual account, even when invitations haven’t been redeemed, it leaves the end users totally unaware of this. Two separate users (in the same tenant, of course) can invite the same person individually, as far as they are using different email addresses as targets. The problem is that when this happens, the guest account ends up having multiple proxy addresses and one of them is going to be the primary one. Emails sent to the non-primary ones will be forwarded to the primary one. If, like in my example case, the primary address is no longer valid, senders start getting non delivery reports. What a mess!
You can try to find guest accounts in your AzureAD with this kind of issue with the following Powershell script
Connect-AzureAD
# List all guest users to a variable
$allGuestUsers = Get-AzureADUser -All 1 -Filter "usertype eq 'guest'"
# Go through all guest users
foreach($user in $allGuestUsers) {
$found = @()
# Go through each proxyaddress of a guest user
foreach($address in $user.proxyaddresses) {
# Take note of the domain part of the address
$found += $address.split("@")[1]
}
# If there is found more than one domain in the proxyaddresses
# print the upn of the user.
if(($found | select -Unique).count -gt 1) {
write-host "User: $($user.userprincipalname):"
$user.proxyaddresses
}
}
If you get results, you might want to investigate those users in more detail and perhaps list some more details from the script. If you find something worth to fix you might want to try something like this (at your own risk , of course)
Connect-ExchangeOnline
# According to my example, find guest users with alias in 2.com domain
# and primary address in 1.com domain
$allGuestUsersTBCorrected = $allGuestUsers | Where-Object {$_.ProxyAddresses -ilike "SMTP:*@1.com" -and $_.ProxyAddresses -ilike "smtp:*@2.com"}
# Go through all selected users
foreach($user in $allGuestUsersTBCorrected) {
# Find email address in the expected domain and remove "smtp:" from
# the string (select everything after it)
$newAddress = ($user.proxyaddresses | Where-Object {$_ -like "*@2.com"}).split(":")[1]
# Update mailuser with wanted details
Set-MailUser -Identity $user.objectid -ExternalEmailAddress $newAddress -EmailAddresses $newAddress
}