Entra / Microsoft 365 · Exchange Online
Remove utility messages from mailboxes
Example of how to use the Microsoft Graph PowerShell SDK cmdlets to remove "utility" messages from user mailboxes.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -NoWelcome -ClientId $AppId -TenantId $TenantId -CertificateThumbprint $AppThumbprint
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $TenantId = "",[string] $AppId = "",[int] $LookbackDays = 1825,[string] $StartDate = (Get-Date).AddDays(-$LookbackDays),[string] $EndDate = (Get-Date))$AppThumbprint = "F79286DB88C21491110109A0222348FACF694CBD"# The app needs the following application permissions:# User.Read.All: Read user account details# Mail.ReadWrite: Read and write mail in all mailboxes# Mail.Send: Send mail as a userConnect-MgGraph -NoWelcome -ClientId $AppId -TenantId $TenantId -CertificateThumbprint $AppThumbprint# List the email addresses of the notification messages to search for and remove$UM0 = "notifications@communityhub.microsoft.com"$UM1 = "messages-noreply@linkedin.com"$UM2 = "noreply@microsoft.com"$UM3 = "notifications-noreply@linkedin.com"$UM4 = "noreply@yammer.com"$UM5 = "microsoft@powerapps.com"$UM6 = "o365mc@microsoft.com"$UM7 = "jobs-listings@linkedin.com"$UM8 = "notifications@yammer.com"$UM9 = "noreply@amazon.com"$UM10 = "notify@mstechcommunity.microsoft.com"$UM11 = "notifications@owler.com"# Set the start and end dates for the search - starting five years ago and ending 30 days ago[datetime]$StartDate = (Get-Date).AddDays(-$LookbackDays)[string]$StartDate = Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:ssZ"[datetime]$EndDate = (Get-Date).AddDays(-$LookbackDays)[string]$EndDate = Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:ssZ"# Define the service plan IDs for Exchange Online (Plan 1) and Exchange Online (Plan 2)$ExoServicePlan1 = "9aaf7827-d63c-4b61-89c3-182f06f82e5c"$ExoServicePlan2 = "efb87545-963c-4e0d-99df-69c6916d9eb0"# Find users assigned a license that includes the Exchange Online (Plan 1) or Exchange Online (Plan 2) service plans.# The check also looks for users with the Exchange Online service plan enabled.Write-Host "Finding mailboxes..." -ForegroundColor Cyan[array]$Users = Get-MgUser -Filter "assignedPlans/any(c:c/servicePlanId eq $ExoServicePlan1 and capabilityStatus eq 'Enabled') `or assignedPlans/any(c:c/servicePlanId eq $ExoServicePlan2 and capabilityStatus eq 'Enabled')" `-ConsistencyLevel eventual -CountVariable Test -All -PageSize 999 -Sort ('displayname') `-Property Id, displayName, userprincipalName, assignedLicenses, assignedPlans, department, country, CreatedDateTimeIf ($Users) {Write-Output ("{0} users licensed for Exchange Online found" -f $Users.Count)} Else {Write-Output "No mailboxes found"Break}$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($User in $Users) {Write-Host ("Processing mailbox {0}" -f $User.DisplayName) -ForegroundColor Yellow[int]$i = 0[array]$Messages = Get-MgUserMailFolderMessage -UserId $User.Id -MailFolderId 'Inbox' `-Filter "(ReceivedDateTime ge $StartDate and ReceivedDateTime le $EndDate) `and (sender/emailAddress/address eq '$UM0' or sender/emailAddress/address eq '$UM1' or sender/emailAddress/address eq '$UM2' `or sender/emailAddress/address eq '$UM3' or sender/emailAddress/address eq '$UM4' or sender/emailAddress/address eq '$UM5' `or sender/emailAddress/address eq '$UM6' or sender/emailAddress/address eq '$UM7' or sender/emailAddress/address eq '$UM8' `or sender/emailAddress/address eq '$UM9' or sender/emailAddress/address eq '$UM10' or sender/emailAddress/address eq '$UM11')" `-Property Id, Subject, Sender, SentDateTime -All -PageSize 999If ($Messages) {# If messages are found, delete them!ForEach ($Message in $Messages) {Try {Remove-MgUserMessage -UserId $User.Id -MessageId $Message.Id -ErrorAction Continue$i++$ReportLine = [PSCustomObject][Ordered]@{Timestamp = (Get-Date -format s)Action = 'Message Deleted'Mailbox = $User.DisplayNameSMTPAddress = $User.UserPrincipalNameSubject = $Message.SubjectSenderEmail = $Message.Sender.EmailAddress.AddressSenderName = $Message.Sender.EmailAddress.NameSent = $Message.SentDateTime}} Catch {Write-Host ("Failed to remove message {0} from mailbox {1} with error {2}" -f $Message.Id, $User.DisplayName, $_.Exception.Message) -ForegroundColor Red$ReportLine = [PSCustomObject][Ordered]@{Timestamp = (Get-Date -format s)Action = 'Message Deletion Failed'Mailbox = $User.DisplayNameSMTPAddress = $User.UserPrincipalNameSubject = $Message.SubjectSenderEmail = $Message.Sender.EmailAddress.AddressSenderName = $Message.Sender.EmailAddress.NameSent = $Message.SentDateTime}}$Report.Add($ReportLine)}} Else {Write-Host ("No notification messages found in mailbox {0}" -f $User.DisplayName) -ForegroundColor Green}If ($i -gt 0) {Write-Host ("{0} notification messages removed from mailbox {1}" -f $i, $User.DisplayName) -ForegroundColor Green}}$Report | Out-GridView -Title "Utility Messages Removed from Mailboxes"# Send email to the mailbox owners[array]$IndividualMailboxes = $Report | Sort-Object SMTPAddress -Unique | Select-Object -ExpandProperty SMTPAddress$MsgSubject = "Notification Messages Removed from Your Mailbox"$MsgFrom = 'Azure.Management.Account@office365itpros.com'$HTMLHeader = "<body><h1>Messages removed by the ever-loyal Utility Message Removal Service</h1><p><strong>Generated:</strong> $(Get-Date -Format g)</p><h2><u>Messages removed from your Inbox</u></h2></p><p>The background agent removes messages from selected senders from your mailbox to avoid a build-up of messages with little value.</p><p>If necessary, you can recover these messages by going to the Deleted Items folder and using the <i>Recover items recently removed from this folder</i> option.</p>"$HTMLFooter ="<p>------------------------------------------------------------------------------</p>" +"<p>This email was sent by the Utility Message Removal service" +"<p>------------------------------------------------------------------------------</p></body>"ForEach ($Address in $IndividualMailboxes) {# Create a HTML fragment containing details of the messages removed from the mailbox$HTMLReport = $Report | Where-Object {$_.SMTPAddress -eq $Address -and $_.Action -eq 'Message Deleted'} | `Select-Object Action, Subject, SenderEmail, SenderName, Sent | Sort-Object {$_.Sent -as [datetime]} -DescendingWrite-Host ("Sending notification about {0} removed messages to {1}" -f $HTMLReport.count, $Address)$HTMLReport = $HTMLReport | ConvertTo-Html -Fragment# Assemble the pieces into a complete HTML message$HTMLBody = $HTMLHeader + $HTMLReport + $HTMLFooter# Add the recipient using the mailbox's primary SMTP address$EmailAddress = @{address = $Address}$EmailRecipient = @{EmailAddress = $EmailAddress}# Construct the message body$MessageBody = @{content = "$($HtmlBody)"ContentType = 'html'}# Create a draft message in the sending mailbox$NewMessage = New-MgUserMessage -UserId $MsgFrom -Body $MessageBody -ToRecipients $EmailRecipient -Subject $MsgSubject# Send the messageSend-MgUserMessage -UserId $MsgFrom -MessageId $NewMessage.Id}Write-Host ("Utility message cleanup complete. Details of {0} notification messages sent to {1} users" -f $Report.Count, $IndividualMailboxes.Count) -ForegroundColor Cyan# Generate the report in either Excel worksheet or CSV format, depending on if the ImportExcel module is availableIf (Get-Module ImportExcel -ListAvailable) {Import-Module ImportExcel -ErrorAction SilentlyContinue$ExcelOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\Removed Notification Messages Report.xlsx"$Report | Export-Excel -Path $ExcelOutputFile -WorksheetName "Deleted Notification Messages" -Title ("Removed Notification Messages {0}" -f (Get-Date -format 'dd-MMM-yyyy')) -TitleBold -TableName "Microsoft365LicensingReport"Write-Host ("Report saved to {0}" -f $ExcelOutputFile) -ForegroundColor Green} Else {$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\Removed Notification Messages Report.CSV"$Report | Export-Csv -Path $CSVOutputFile -NoTypeInformation -Encoding Utf8Write-Host ("Report saved to {0}" -f $CSVOutputFile) -ForegroundColor Green}
Parameters
ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.-AppId""Application (client) ID for the app registration used to connect.-LookbackDays1825Maximum age in days of utility messages to remove from mailboxes (default is about five years).-StartDate(Get-Date).AddDays(-10)Start of the reporting window.-EndDate(Get-Date)End of the reporting window.Attribution
Author
Office365itpros