Exchange Online IMAP and SMTP OAuth 2.0 with Delegated Permissions

Exchange Online IMAP and SMTP OAuth 2.0 with Delegated Permissions

Hi All,

This Week i had to Troubleshoot an Application with IMAP and SMTP Access to a Shared Mailbox that uses Microsoft Graph Delegated Permissions.

I’ve already blogged about how to Use Application Permissions

Register Azure AD (EntraID) Application

Register a new Application

Note down the following:

  • Display name
  • Application ID
  • Tenant ID

Click on “Add a Redirect URI”

Click on “Mobile and desktop applications”

Enable the (MSAL only) and copy the Redirect URI

On the “API Permissions” remove the default Permission

Approve with “Yes, remove”

Click on “Add a permission”

Select “Microsoft Graph” and “Delegated permission”

Add “IMAP.AccessAsUser.All”

Add “Mail.Send.Shared”

Click on “Grant admin consent for Icewolf” even if Admin consent required says “no”

Add Exchange Service Principal

First we need to get the Application

###############################################################################
# Get AzureAD Application with Microsoft.Graph PowerShell
###############################################################################
Connect-MgGraph -Scopes 'Application.Read.All'
$AppName = "EXO_IMAP_Delegated"
$Filter = "DisplayName eq '" + $AppName + "'"
$ServicePrincipalDetails = Get-MgServicePrincipal -Filter "$Filter"
$ServicePrincipalDetails

Note: all the code from this Article is also published at my GitHub Repo

Now we can create the Exchange Service Principal

###############################################################################
# Create Exchange Service Principal
###############################################################################
Connect-ExchangeOnline -ShowBanner:$false
New-ServicePrincipal -AppId $ServicePrincipalDetails.AppId -ServiceId $ServicePrincipalDetails.Id -DisplayName "EXO Serviceprincipal $($ServicePrincipalDetails.Displayname)"

Note: The Exchange Service Principal needs to be removed manually when you delete the Azure AD (EntraID) Application Registration.

Now we need to check if IMAP is enabled on the Shared Mailbox

###############################################################################
# CAS Mailbox
###############################################################################
$Mailbox = "SharedMBX@icewolf.ch"
Get-CASMailbox -Identity $Mailbox 
Set-CASMailbox -Identity $Mailbox -PopEnabled $false -ImapEnabled $true -SmtpClientAuthenticationDisabled $false
Get-CASMailbox -Identity $Mailbox

Now we need to grant the User the Full Access Permission to the SharedMailbox for the User

###############################################################################
#Full Access
###############################################################################
$Mailbox = "SharedMBX@icewolf.ch"
$User = "a.bohren@icewolf.ch"

#Add FullAccess Permission
Add-MailboxPermission -Identity $Mailbox -User $User -AccessRights FullAccess -AutoMapping $false

#Get FullAccess Permissions
Get-MailboxPermission  -Identity $Mailbox | where { ($_.AccessRights -eq "FullAccess") -and ($_.IsInherited -eq $false) -and -not ($_.User -like "NT AUTHORITY\SELF") } | ft -AutoSize

Now we need to grant the SendAs Permission to the to the SharedMailbox for the User

###############################################################################
# Send As
###############################################################################
$Mailbox = "SharedMBX@icewolf.ch"
$Trustee = "a.bohren@icewolf.ch"

#Add SendAs Permissions
Add-RecipientPermission -Identity $Mailbox -Trustee $Trustee -AccessRights SendAs

#Get SendAs Permissions
Get-RecipientPermission  -Identity $Mailbox | where { ($_.AccessRights -eq "SendAs") -and ($_.IsInherited -eq $false) -and -not ($_.Trustee -like "NT AUTHORITY\SELF") } | ft -AutoSize

Testing

Let’s test if we can get an Access Token

###############################################################################
# Test Token with MSAL and JWTDetails
# Install-Module MSAL.PS
# Install-Module JWTDetails
###############################################################################
$AppID = "e9d3d08b-d477-4688-b972-8cb06eefe439"
$TenantID = "icewolfch.onmicrosoft.com"
$RedirectURI = "msale9d3d08b-d477-4688-b972-8cb06eefe439://auth"
Clear-MsalTokenCache
$Scopes = "https://outlook.office.com/.default"
$Token = Get-MsalToken -Interactive -Scopes $Scopes -TenantID $TenantID -ClientId $AppID -RedirectURI $RedirectURI
$AccessToken = $Token.AccessToken
Get-JWTDetails -token $AccessToken

Now let’s test with the Get-IMAPAccessToken.ps1

###############################################################################
# Test Access
# OAuth2 IMAP Test Tool
# https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1
###############################################################################
Clear-MsalTokenCache
$AppID = "e9d3d08b-d477-4688-b972-8cb06eefe439" #EXO_IMAP_Delegated
$TenantID = "46bbad84-29f0-4e03-8d34-f6841a5071ad"
$RedirectURI = "msale9d3d08b-d477-4688-b972-8cb06eefe439://auth"
.\Get-IMAPAccessToken.ps1  -tenantID $TenantID -clientId $AppID  -redirectUri $RedirectURI -LoginHint "a.bohren@icewolf.ch" -SharedMailbox "sharedmbx@icewolf.ch"

Test the Send Mail Functionality

###############################################################################
# Sends Mail via Microsoft Graph API
# https://docs.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http
###############################################################################
#Delegated (work or school account)	Mail.Send
#Delegated (personal Microsoft account)	Mail.Send

#Create HTML Body
[string]$body = @"
<html>
	<head>
		<style>
		p {
			text-align: Left; 
			color: green;
			font-size: 12px;
			font-family: Arial
		}

		table, th, td {
			border: 1px solid;
			font-size: 12px;
			font-family: Arial			
		}
		</style>
	</head>
<body>
	<h3>HTML Header</h3>
	<p>the quick brown fox jumps over the lazy dog</p>
</body>
</html>
"@


$Mailbox = "sharedmbx@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/sendMail"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Body = @"
{
    "message": {
        "subject": "Microsoft Graph API Mail DEMO",
        "body": {
            "contentType": "HTML",
            "content": "$Body"
        },
        "toRecipients": [
            {
                "emailAddress": {
                    "address": "a.bohren@icewolf.ch"
                }
            }
        ]
    }
}
"@

#Send Actual Mail
$result = Invoke-RestMethod -Method "POST" -Uri $uri -Body $Body -Headers $Headers -ContentType $ContentType
If ($null -ne $result)
{
    Write-Host "Mail has been sucessufully sent"
}

The Testmail was sucessfully sent with the Shared Mailbox

Test with Remote Connectivity Analizer

You can use also Remote Connectivity Analizer to test the Access.

Select “Office 365” > “Imap Email”

Sign in with OAuth

Sign in with the User

Add the Emailaddress of the Shared Mailbox into the “Alternate Mailbox” field

That worked fine too

Hope this helps you to configure and Test your IMAP,POP3 and SendMail Functionality with delegated Microsoft Graph Permissions.

Regards
Andres Bohren

Exchange Logo

M365 Logo