Anyone who has administered Exchange knows there are times when you need to go through all the mailboxes and delete a message with a certain subject.

Common examples include:

  • Virus Outbreak
  • Disgruntled employee sending one last email
  • Sensitive email accidently sent to incorrect recipients

Another scenario which is somewhat new with hosted environments is someone accidently sends a large email to a large number of people, resulting in a spike in Internet traffic as everyone downloads the message to their OST. Administrators need some way to quickly get into the mailboxes and remove the message to stop the downloads.

Since there doesn’t appear to currently be a way to handle the above scenarios with Exchange Online, we decided to do something about it! The script below searches through all your enabled mailboxes for a message with the subject specified, which was received within the last 4 hours. If a message with the specified subject is found the script deletes the message.

Of course you need to be very careful with this script as it has the potential to cause big problems if run incorrectly. By default the script runs in Test Mode, where only a single mailbox is processed. If you take the script out of test mode, all enabled mailboxes will be searched.

This script requires that you have the EWS Managed API, which can be downloaded here.

If you have any questions, need customizations, have suggestions, or need assistance, please email us at [email protected] We are constantly looking for new script ideas, so if you have a need for a script or Microsoft Online application, please let us know.

We can’t stress enough that since the script does delete messages, you need to be careful with it. MessageOps will not be responsible for any problems resulting from its execution in your environment.

You can download a properly formatted version of the script here.

#Microsoft Exchange Online Delete Message by Subject Script
#By: MessageOps,
#Searches all Microsoft Online Mailboxes for Messages with
#a given subject and deletes them
#By default the script operates in Test Mode where only a single mailbox is processed.
#To change the mode to have the script run against all mailboxes change the
#value of TestMode to 0.


#When Test Mode is set to 1, only this mailbox will be checked.
$TestMailbox=”[email protected]

#The Subject of the Message to Search for and delete
$subjecttoSearch  = “Subject of the Message to Delete”
#The BPOS Admin account.  This account must have a mailbox
$bposUserName = “[email protected]
$bposPassword = “Password”

#Defines how many hours back the search should go
$MailDate = [system.DateTime]::Now.Addhours(-4)

#If you are in the APAC or EMEA Datacenters, comment out this value and uncomment out the correct value below

$bposcasuri = [system.URI] “

#$bposcasuri=[system.URI] “
#$bposcasuri=[system.URI] “

$adminpassword = ConvertTo-SecureString $bposPassword -AsPlainText -Force
$adminCredential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $bposUserName,$adminpassword

$dllpath = “C:\Program Files\Microsoft\Exchange\Web Services\1.0\Microsoft.Exchange.WebServices.dll”

$deleteMode = [Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete
$aptcancelMode = [Microsoft.Exchange.WebServices.Data.SendCancellationsMode]::SendToNone
$taskmode =  [Microsoft.Exchange.WebServices.Data.AffectedTaskOccurrence]::AllOccurrences

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)

$service.Url = $bposcasuri
$service.Credentials = New-Object System.Net.NetworkCredential($bposUserName,$bposPassword,””)

If ($TestMode -eq 1){
$colUsers = get-msonlineUser -Identity $TestMailbox -Credential $admincredential
$colUsers = get-msonlineUser -Credential $admincredential -enabled -resultsize 10000

$colusers | ForEach-Object {
If (($_.ProxyAddresses -ne “”) -and ($_.SubscriptionIDs -ne “”) -and ($_.MailboxSize -gt 0)){
$Itembatch = [activator]::createinstance(([type]’System.Collections.Generic.List`1′).makegenerictype([Microsoft.Exchange.WebServices.Data.ItemId]))
$emailaddresses = $_.ProxyAddresses
ForEach ($address in $emailaddresses){
If ($addresstype.compareto(‘SMTP:’) -eq 0){
$mailboxname = $address.ProxyAddress.Replace(“SMTP:”,””)
$rfRootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::inbox,$MailboxName)
$rfRootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$rfRootFolderID)
“Checking ” + $MailboxName + ” ” + $ffFolder.DisplayName
$Sfir = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Subject, $subjecttoSearch)
$Sflt = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsGreaterThan([Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, $MailDate)
$sfCollection = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
$ivview = new-object Microsoft.Exchange.WebServices.Data.ItemView(20000)
$frFolderResult = $rfRootFolder.FindItems($sfCollection,$ivview)
foreach ($miMailItems in $frFolderResult.Items){
if ($miMailItems.Subject -eq $subjecttoSearch){
“****** Found : ” + $miMailItems.Subject
“Number of Items found in folder : ” + $Itembatch.Count

if($Itembatch.Count -ne 0){
“Deleting ” + $Itembatch.Count + ” Items”
$DelResponse = $service.DeleteItems($Itembatch,$deleteMode,$aptcancelMode,$taskmode)
foreach ($dr in $DelResponse) {


Was this article helpful?