Jump to content

Recommended Posts

Posted

Hi all,

 

Not sure if this is the right place to post about this, but we have a custom built email program that send emails using SMTP, with an Outlook account. This all works great, but with sending lots of emails, the sent items of the Outlook account can fill up the storage quota (a lot of the emails we send have large attachments). So what I'd like to do is have some sort of policy set on the account that any large emails (say >200KB) in the sent items get deleted after 6 months. We have an A1 license for Office (free for education) so I think our options may be limited. But I've looked into having retention policies on the sent items of the Outlook account, and auto applying retention labels using specific keyword searches looks like the way to go to do this. Does anyone know if this is possible with an A1 license? Our network manager isn't sure if this is possible with the A1 license, and I'm just looking for some guidance.

 

Thanks!

 

Chris

Posted

Overall, don't do this through O365. Using O365 as a SMTP relay is fine if you are sending the odd scan-to-email but if it is the volume you say its going to be painful. Sendgrid costs peanuts and is designed for ht ejob.

 

Health warning over..

 

 

Fairly sure enhanced stuff like that needs a A/E 3

 

I've got a PS script that is designed to call graph api to delete email, you could adapt that, or even a simple powershell job to search-mailbox and delete content

  • Thanks 1
Posted
Thanks for the reply. I'd certainly echo that O365 is not suited for high volume emails. But being an educational environment every penny counts, and it's free. But we're not really sending high volume emails, our custom based email system downloads pupil/parental information directly from SIMS, and then we can pick and choose who to email based the email requirements. It means we can send highly targeted emails so that parents only receive essential information that's relevant to them. So whilst it's certainly not a speedy system to send email, it's definitely effective.As for the license, it's pretty much what I was fearing. But the idea of doing it via code or powershell is interesting, and could definitely work. Do you have a good resource to point me in the direction of for doing it via powershell? Really appreciate you help!
Posted (edited)

Here's my code - note it's set to delete ALL email (not calendar, tasks etc) so would need a bit of work. Its a fair bit more involved than I recall and if you want to scope it to sent items only it would need modifying

 

You would need to create an app registration with mail.readwrite.all (then I would scope it down to the mailbox in question)

Limiting application permissions to specific Exchange Online mailboxes - Microsoft Graph | Microsoft Docs

if you are going to try this please do it cautiously in a test tenant...

 

$ClientID = "blah"

$AppSecret = "sshhh"

$loginURL = 'https://login.microsoftonline.com'

$TenantName = "yourtenant.onmicrosoft.com"

$resource = 'https://graph.microsoft.com'

$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"

$Scope = 'https://graph.microsoft.com/.default'

 

 

 

 

$user='[email protected]'

 

 

$start=(get-date).AddDays(-7).ToString('yyyy-MM-ddT00:00:01.00Z')

$finish=(get-date).AddDays(-1).ToString('yyyy-MM-ddT23:59:59.00Z')

 

 

 

 

$num=0

$datestamp=(get-date).AddMinutes(-10).ToString('yyyyMMddHHmmss')

 

 

 

 

$LogPath="."

 

 

$logname= $($LogPath + "" + $datestamp + "-ECC.txt")

 

 

# Get an Oauth 2 access token based on client id, secret and tenant domain

$body = @{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$AppSecret}

#write-host "$loginURL/$tenantname/oauth2/token"

 

 

 

 

 

 

 

 

$oauth = Invoke-RestMethod -Method Post -Uri "$loginURL/$tenantname/oauth2/token" -Body $body

 

 

$2daysago = "{0:s}" -f (get-date).AddDays(-2) + "Z"

# or, AddMinutes(-5)

 

 

#Write-Output $2daysago

 

 

function LogIt

{

param ($Message)

$tim=get-date -Format HH:mm:ss

 

 

Add-Content $logname "$tim`t$Message"

}

 

 

 

 

 

 

# Add System.Web for urlencode

Add-Type -AssemblyName System.Web

Add-Type -AssemblyName System.Drawing

 

 

# Create body

$Body = @{

client_id = $clientID

client_secret = $AppSecret

scope = $Scope

grant_type = 'client_credentials'

}

$body

 

 

$PostSplat = @{

ContentType = 'application/x-www-form-urlencoded'

Method = 'POST'

Body = $Body

Uri = $Url

}

 

 

function deleteFolders

{

param ($uri)

logit "INFO`tCalling delete $uri with $uri"

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Delete -ContentType "application/json" -SkipHttpErrorCheck -StatusCodeVariable scv

$scv

}

 

 

function deleteEmail

{

param ($uri)

logit "INFO`tCalling delete $uri"

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Delete -ContentType "application/json"

$scv

}

 

 

 

 

 

 

function get_All_Values_From_GraphAPI

{

#Where a response will run the risk of paging, follow all pages and return an array

param ($uri,$method)

$header

logit "INFO`tCalling $uri with method $method "

$Allinfo=@()

 

 

# Get the first X amount of detail

try

{

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $method -ContentType "application/json"

$someinfo

}

catch

{

logit("WARNING`tCall Failed with $($error[0]). Retrying in 5 seconds...")

start-sleep -seconds 5

 

 

if ($error[0] -like "*Access token has expired*")

{

logit("INFO`tRequesting New Acces Token")

# Request the token

$global:Request = Invoke-RestMethod @PostSplat

 

 

$global:Header = @{

Authorization = "$($Request.token_type) $($Request.access_token)" }

 

 

 

}

 

 

 

 

 

try

{

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $method -ContentType "application/json"

}

catch

{

logit("WARNING `tCall Failed with $($error[0]). Retrying in 30 seconds...")

if ($error[0] -like "*Access token has expired*")

{

logit("INFO`tRequesting New Acces Token")

# Request the token

$global:Request = Invoke-RestMethod @PostSplat

 

 

$global:Header = @{

Authorization = "$($Request.token_type) $($Request.access_token)" }

 

 

 

}

 

 

 

 

start-sleep -seconds 30

try

{

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $method -ContentType "application/json"

}

catch

{

logit("ERROR `tCall Failed with $($error[0]). Giving Up..")

$WeHaveAnError=$True

}

}

 

 

}

 

 

$AllInfo+=$SomeInfo.value

 

 

# Keep following paging links until all content is returned

while($someInfo.'@odata.nextLink' -ne $null)

{

try

{

$SomeInfo=Invoke-RestMethod -Uri $SomeInfo.'@odata.nextLink' -Headers $Header -Method $method -ContentType "application/json"

 

}

catch

{

logit("WARNING`tCall Failed with $($error[0]). Retrying in 5 seconds...")

start-sleep -seconds 5

 

 

if ($error[0] -like "*Access token has expired*")

{

logit("INFO`tRequesting New Acces Token")

# Request the token

$global:Request = Invoke-RestMethod @PostSplat

 

 

$global:Header = @{

Authorization = "$($Request.token_type) $($Request.access_token)"}

}

 

 

try

{

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $method -ContentType "application/json"

}

catch

{

logit("WARNING `tCall Failed with $($error[0]). Retrying in 30 seconds...")

 

if ($error[0] -like "*Access token has expired*")

{

logit("INFO`tRequesting New Acces Token")

# Request the token

$global:Request = Invoke-RestMethod @PostSplat

 

 

$global:Header = @{

Authorization = "$($Request.token_type) $($Request.access_token)" }

}

 

 

 

start-sleep -seconds 30

try

{

$SomeInfo = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $method -ContentType "application/json"

}

catch

{

logit("ERROR `tCall Failed with $($error[0]). Giving Up..")

$WeHaveAnError=$True

}

}

}

$AllInfo+=$SomeInfo.value

}

 

return ($AllInfo)

}

 

 

 

 

# Request the token

$global:Request = Invoke-RestMethod @PostSplat

 

 

$global:Header = @{

Authorization = "$($Request.token_type) $($Request.access_token)"

}

 

 

 

 

 

 

 

$queryurl=$('https://graph.microsoft.com/beta/users/'+ $user + '/mailFolders')

 

 

$myReport=get_All_Values_From_GraphAPI $queryurl Get

 

 

logit "Deleting other folders other than well known"

 

 

for ($num=2; $num -lt $myreport.length; $num++)

{

if ($myreport[$num].WellKnownName -eq $null -and $myreport[$num].displayName -ne 'RSS Feeds' )

 

{

 

 

$id=$myreport[$num].id

$displayName=$myreport[$num].displayName

 

write-host "Deleting $Displayname"

$queryurl=$('https://graph.microsoft.com/beta/users/' + $user + '/mailFolders/' + $id)

write-host "query is $queryurl"

 

 

$myDelete=deleteFolders $queryurl

if ($myDelete -eq '204')

{

write-host -ForegroundColor Green "`tOK (http $mydelete)"

}

elseif ($mydelete -eq '404')

{

write-host -ForegroundColor Magenta "`tNot found probably deleted (http $mydelete) "

 

}

else

{

write-host -ForegroundColor red "`tSomething gone pete tong (http $mydelete)"

}

 

 

 

 

 

}

 

 

}

 

 

 

 

# Now get all remaining messages

$queryurl=$('https://graph.microsoft.com/beta/users/'+ $user + '/messages?$top=999&$select=subject')

 

 

$remainingemails=get_All_Values_From_GraphAPI $queryurl Get

logit "Deleting $($remainingemails.length) Emails"

for ($num=2; $num -lt $remainingemails.length; $num++)

{

write-host "Deleting email $($remainingemails[$num].subject) $($remainingemails[$num].id)"

$queryurl=$('https://graph.microsoft.com/beta/users/'+ $user + '/messages/' + $remainingemails[$num].id)

DeleteEmail $queryurl

 

 

}

 

 

logit "Deletion Complete"

Edited by chaplic
  • Thanks 1
Posted
Thanks so much for that, I shall digest and see if I can cobble something together. I have a test account I can play on so no harm can be done. Thanks for your help! :thumb:

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...