← All scripts

Email security & monitoring

Internal Email Volume Report

Reports the number of messages sent per internal user per day from Exchange Online message trace, exported to CSV. Note: Get-MessageTrace covers only the last 10 days and is being replaced by Get-MessageTraceV2.

Download .ps158 lines · PowerShell

Replace generic placeholder values (tenant, domain, secrets) for your own environment before running. Read it first and test safely.

<#
.SYNOPSIS
    Reports internal email volume per user per day from Exchange Online.

.DESCRIPTION
    Connects to Exchange Online and, over a configurable window (default 7 days),
    counts messages sent by internal users (matched by your own email domain),
    groups them by sender and day, and exports the result to CSV.

    Requires:
      - The ExchangeOnlineManagement PowerShell module (Install-Module ExchangeOnlineManagement)
      - An account permitted to run message-trace / mail-traffic reports.

.NOTES
    Set the values in the "Configure for your environment" block before running.
    Generic placeholder values are used in place of real tenant/domain values.
#>

# ---------------------------------------------------------------------------
# Configure for your environment
# ---------------------------------------------------------------------------
$AdminUpn       = '[email protected]'  # your Exchange Online admin account
$InternalDomain = '@yourdomain.co.nz'                 # your organisation's primary email domain
$OutputPath     = 'C:\temp\InternalEmailMetrics.csv'  # where to write the report
$DaysBack       = 7                                   # how many days back to report on

# Connect to Exchange Online (prompts for sign-in / MFA)
Connect-ExchangeOnline -UserPrincipalName $AdminUpn

# Define the reporting window
$StartDate = (Get-Date).AddDays(-$DaysBack)
$EndDate   = Get-Date

# Pull message-trace data; fall back to the traffic summary report if empty
$MessageTraceData = Get-MessageTrace -StartDate $StartDate -EndDate $EndDate
if ($MessageTraceData.Count -eq 0) {
    Write-Host "No data from Get-MessageTrace. Trying alternative method..." -ForegroundColor Yellow
    $MessageTraceData = Get-MailTrafficSummaryReport -StartDate $StartDate -EndDate $EndDate
}

# Count messages sent by internal users, grouped by sender and day
if ($MessageTraceData.Count -gt 0) {
    $EmailVolumePerDay = $MessageTraceData |
        # Internal senders only (match your own domain), and only delivered items
        Where-Object { $_.SenderAddress -like "*$InternalDomain" -and $_.Received -ne $null } |
        # Group by "sender - yyyy-MM-dd"
        Group-Object { "$($_.SenderAddress) - $($_.Received.ToString('yyyy-MM-dd'))" } |
        Select-Object @{Name='Sender'; Expression={($_.Name -split ' - ')[0]}},
                      @{Name='Date';   Expression={($_.Name -split ' - ')[1]}},
                      @{Name='Count';  Expression={$_.Count}} |
        Sort-Object Date, Sender

    $EmailVolumePerDay | Export-Csv -Path $OutputPath -NoTypeInformation
    Write-Host "Report exported to $OutputPath" -ForegroundColor Green
} else {
    Write-Host "No email data found for the specified date range." -ForegroundColor Red
}