In this tutorial, I will show you how to create mailbox rules in Exchange Online using Microsoft Graph PowerShell. I will cover what permissions are required to complete the tasks (both delegated and application permissions), how to construct your own rule conditions and actions and how to apply the mailbox rule across multiple users in your tenant.
To create the mailbox rules we will utilise the New-MgUserMailFolderMessageRule cmdlet which is included in the Microsoft.Graph.Mail module.
Pre-requisites and permissions
Firstly, to run our script and the necessary commands you must have the Microsoft Graph PowerShell SDK installed, check out my tutorial on how to install the Microsoft Graph PowerShell module.
You must also ensure that the user with which you are logging into your tenant, has the necessary permissions to perform these actions, in most cases, global administrator rights will do.
How to create a mailbox rule using Microsoft Graph PowerShell
Now let’s take a look at how to create a single mailbox rule in a single user account using Microsoft Graph PowerShell. I have commented on the script below to help you understand what is going on.
In the below script, we are creating a mailbox rule that applies to senders that include a specific string in their sender address and to action them emails by moving them all to a specific folder.
As you can also see, there is some information we need to supply for this to happen. Firstly the users UPN we want the rule to apply to, then the target folder name, the display name of the rule and also the sender contains field.
#Import the graph module
Import-Module Microsoft.Graph.Mail
#Connect to Microsoft Graph
Connect-MgGraph -Scope MailboxSettings.Read, MailboxSettings.ReadWrite, Mail.ReadWrite
#Complete the below with the requested information
$targetuser = "your UPN here"
$targetfolder = "Target folder name here"
$userid = $targetuser
#Store the target folder
$targetfolder = Get-MgUserMailFolder -UserId $userId -filter "DisplayName eq '$targetfolder'"
#Store the inbox folder (New rules can only be created on the inbox folder)
$MailboxFolder = Get-MgUserMailFolder -UserId $userId -filter "DisplayName eq 'inbox'"
#Define the Conditions and Actions
$params = @{
DisplayName = "Company-Wide Move To Training Folder"
Sequence = 2
IsEnabled = $true
Conditions = @{
SenderContains = @(
"[email protected]"
)
}
Actions = @{
moveToFolder = $targetfolder.id
StopProcessingRules = $true
}
}
#Create the rule
New-MgUserMailFolderMessageRule -UserId $userId -MailFolderId $mailboxfolder.id -BodyParameter $params
Once the script is run, you should see an output like the following:
You can also verify this is completed as expected by logging into outlook.office.com as your target user by clicking Settings > View all Outlook Settings > Rules.
Here is another example where I will just focus on the rule parameter section of the script, as this is what will most likely change. Here we specified if the email comes from “[email protected]” and contains “Training” in the subject field, then move it to the target folder and mark it as high importance.
$params = @{
DisplayName = "Company-Wide Move To Training Folder"
Sequence = 2
IsEnabled = $true
Conditions = @{
SenderContains = @(
"[email protected]"
)
SubjectContains = @(
"Training"
)
}
Actions = @{
moveToFolder = $targetfolder.id
markImportance = "high"
}
}
How to construct your own message rule in JSON format
If you do not wish to use the above examples, the best thing for you to do is construct your own rule conditions and actions, so let’s take a look at how to construct your own rule.
Firstly, let’s start with a baseline, below is the body of our defined parameters, as you can see the conditions and actions fields are empty. There are also some initial parameters we need to supply such as the DisplayName, Sequence number and IsEnabled (where it is enabled or not..).
$params = @{
DisplayName = "#DisplayName#"
Sequence = 2 #supply a number
IsEnabled = $true #true or false
Conditions = @{
#conditions
}
Actions = @{
#Actions
}
}
There are many different parameters you can supply into your condition and actions fields of the script, take a look at the lists below to see what is available,
Optional Conditions
- “bodyContains”: [“String”]
- “bodyOrSubjectContains”: [“String”]
- “categories”: [“String”], “fromAddresses”: [{“@odata.type”: “microsoft.graph.recipient”}]
- “hasAttachments”: “Boolean”, “headerContains”: [“String”]
- “importance”: “String”, “isApprovalRequest”: “Boolean”
- “isAutomaticForward”: “Boolean”
- “isAutomaticReply”: “Boolean”
- “isEncrypted”: “Boolean”
- “isMeetingRequest”: “Boolean”
- “isMeetingResponse”: “Boolean”
- “isNonDeliveryReport”: “Boolean”
- “isPermissionControlled”: “Boolean”
- “isReadReceipt”: “Boolean”
- “isSigned”: “Boolean”
- “isVoicemail”: “Boolean”
- “messageActionFlag”: “String”
- “notSentToMe”: “Boolean”
- “recipientContains”: [“String”]
- “senderContains”: [“String”]
- “sensitivity”: “String”
- “sentCcMe”: “Boolean”
- “sentOnlyToMe”: “Boolean”
- “sentToAddresses”: [{“@odata.type”: “microsoft.graph.recipient”}]
- “sentToMe”: “Boolean”
- “sentToOrCcMe”: “Boolean”
- “subjectContains”: [“String”]
- “withinSizeRange”: {“@odata.type”: “microsoft.graph.sizeRange”}
Optional Actions
- “assignCategories”: [“String”]
- “copyToFolder”: “String”
- “delete”: “Boolean”
- “forwardAsAttachmentTo”: [{“@odata.type”: “microsoft.graph.recipient”}]
- “forwardTo”: [{“@odata.type”: “microsoft.graph.recipient”}]
- “markAsRead”: “Boolean”
- “markImportance”: “String”
- “moveToFolder”: “String”
- “permanentDelete”: “Boolean”
- “redirectTo”: {“@odata.type”: “microsoft.graph.recipient”}
- “stopProcessingRules”: “Boolean”
To include the various types of conditions and actions in your script, you can do so by including them in the relevant format. Not every parameter is specified in the same format, so here are some examples below.
Example: “copyToFolder”: “String”
When targeting a folder, the folder id must be specified. Use my example in the script above to gather the folder id.
copyToFolder = $targetfolder.id
Example: “markAsRead”: “Boolean”
As this is a Boolean value, it can either be True or False.
markAsRead: $true or $false
Example: “bodyOrSubjectContains”: [“String”]
Although the value is in ‘string‘ format, it is enclosed in square brackets, this means when we are specifying this parameter, it must be presented in an array.
bodyContains = @(
"important information"
)
How to create a mailbox rule for all users
Unfortunately, unlike when we apply mailbox settings to our own user context, we cannot apply mailbox settings to any other user while using delegated permissions in the Microsoft Graph PowerShell (which is the only permission type we can use when using an interactive login prompt). This is because the mailbox settings are not properties of the user, but are saved in the mailbox configuration, which cannot be accessed through delegate permissions. This is not made that clear on the MS Docs, however, so take that in mind.
To achieve our goal, we first need to register an application in Azure AD and then provide the application with the necessary Graph permissions. You have the option to use a client secret or certificate to authenticate to 365, so in our case, we are going to use a secret to simplify the process. Follow these steps:
2. Select Azure Active Directory from the left-hand menu, then select App registrations.
3. Select New Registration. Enter a name for your application, select Accounts in this organizational directory only and enter a Redirect URI (I have just used office.com). Then click register.
4. Make a note of the Application (client) ID on the overview tab, as we will need this in our script.
5. From the Left-Hand menu, select API permissions.
6. Click Add a permission, then select Microsoft Graph and click Application Permissions.
7. In the search box, find and select the following permissions:
- MailboxSettings.ReadWrite
- Mail.Read
- User.Read.All
and click Add permissions.
8. While on the app registration page, select Grant admin consent for … and click yes to the pop-up.
9. Now on the left-hand menu, select Certificate & secrets.
10. Click Add new secret and a new window will appear on the right. Enter the description and expiry length, then click Add.
11. Once you have created the secret, you will see it on the App registrations page. Make a note of the Value and Secret ID as we will need that in our script.
12. Lastly, we just need to grab the tenant ID. We can do this by heading back to https://aad.portal.azure.com/ and selecting Azure Active Directory from the left-hand menu. The Tenant ID will be listed on the Overview tab.
Full Script
Here is the full script which will deploy your mailbox rule to all users in your Microsoft 365 tenant.
#Import Module
Import-Module Microsoft.Graph.Mail
#Store connection information
$appid = 'YOUR APPLICATION ID'
$tenantid = 'YOUR TENANT ID'
$secret = 'YOUR CLIENT SECRET >VALUE<'
#Store request body
$body = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $appid
Client_Secret = $secret
}
#Sent HTTPs request to Microsoft
$connection = Invoke-RestMethod `
-Uri https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token `
-Method POST `
-Body $body
#Store access token
$token = $connection.access_token
#Connect to Microsoft Graph
Connect-MgGraph -AccessToken $token
#Define target folder
$targetfolder = "Folder where you want to move mail to"
#Store all users
$allusers = get-mguser -Property UserType, Displayname, Id, Mail, UserPrincipalName | where-object {$_.UserType -eq "Member"}
#Apply rule to all users
ForEach ($user in $allusers) {
#Null variables
$vtargetfolder = $null
$MailboxFolder = $null
#Store targer and inbox folder
$vtargetfolder = Get-MgUserMailFolder -UserId $user.Id -filter "DisplayName eq '$targetfolder'"
$MailboxFolder = Get-MgUserMailFolder -UserId $user.id -filter "DisplayName eq 'inbox'"
#Check if Target folder exists
If ($vtargetfolder -eq $null) {
write-host "Folder:" $targetfolder " is missing for" $user.DisplayName
} else{
#Define rule conditions and actions
$params = @{
DisplayName = "Company-Wide Move To Training Folder"
Sequence = 2
IsEnabled = $true
Conditions = @{
SenderContains = @(
"[email protected]"
)
}
Actions = @{
moveToFolder = $targetfolder.id
StopProcessingRules = $true
}
}
#Create new rule
New-MgUserMailFolderMessageRule -UserId $user.id -MailFolderId $mailboxfolder.id -BodyParameter $params | out-null
Write-host "Mailbox rule created successfully for" + $user.DisplayName
}
}