Inumbo is a cloud-based mail hygiene solution. Whether using their free or paid subscription, you can search the message tracking log in the web portal to see a history of messages being processed for your subscription. The main thing I use it for is to know if I haven’t received a message because it was marked as spam. But rather than use the web portal, you can also use their REST API to programmatically get tracking records. So instead of logging into the portal and searching, you just run a script and perform filtered searches and also get more information that what is exposed in the portal.
You need to get a read-only or read/write API key since that is what is used to authenticate the request. You don’t have to use any search restrictions, and my script doesn’t require any either, but usually you’ll want to narrow it down to a time frame, sender, recipient, or action performed (delivered, rejected, etc.) I have included these common search parameters, plus subject and sender IP. Subject is a substring filter, and the start date and end date parameters are not mutually exclusive.
Speaking of dates, the API requires the format to be in epoch time (number of seconds since 1/1/1970, aka UNIX time). To convert a .NET DateTime object to UNIX time, I use a method that was introduced in .NET 4.6. If you aren’t using 4.6+, you can modify the Get-UnixTime function (at line 61) to calculate it using a time span, and there is link in the script for how to do that. Furthermore, the script will account for time zone in the request and the response, so you can use “3/23/16 7:00 AM,” “3/23/16 7:00 AM -0700,” or “3/23/16 2:00 PM UTC” and get the same results, and the time stamp for each result will be in local time.
There are a number of properties for a record, so I only keep the ones that are relevant for normal queries. These are time stamp, action, sender IP, sender, recipient, subject, RPD (anti-spam) score, SpamAssassin score, and description (why it was rejected or next hop information). That’s still nine properties, too many to display in a table and see enough of the values to be meaningful, and I want the default output to be as a table. So I specified the default properties to return five of the nine in a table.
How did I do that? I created a custom formatting file (included in the download). The file specifies that, for the custom type I assign to the record object, the default view is a table with five properties and specific widths for the columns, except for the subject which will fill the rest of the width. To use the file, you need to run Update-FormatData .\TrackingInfo.format.psx1. You will need to this once in each time you open a new shell. You can add the command to your profile or even add the line to the script. If you don’t use the formatting file, I still set a default property set in the script so the five properties are displayed, but the default will be in a list. You, of course, can use standard format and export cmdlets to choose the properties displayed and how they are displayed. So, if you want to see all properties, pipeline the results to, for example, Format-List -Property *.
The script’s code can be expanded and seen below, but you can download the script and the formatting file in the below attachment.
Get-InumboTracking.zip (2.9 KiB)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
<# .Synopsis Retrieve message tracking information from Inumbo .Description Get message tracking details for messages from Inumbo, optionally filtering on sender, recipient, date range, IP, subject, and action. .Parameter Action Restrict search results to valid action: quarantine, deliver, delete, bounce, reject, defer, or error. .Parameter Sender Sender email address to restrict search results. .Parameter Recipient Recipient email address to restrict search results. .Parameter Subject Substring of subject to restrict search results. .Parameter SenderIP IP address of sending server to restrict search results .Parameter StartDate Date and time to restrict the search results to messages with a timestamp after the date provided. Any DateTime object, or string that can be converted to DateTime, can be used and time zone will be accounted for. It can be used with or without EndDate. .Parameter EndDate Date and time to restrict the search results to messages with a timestamp before the date provided. Any DateTime object, or string that can be converted to DateTime, can be used and time zone will be accounted for. It can be used with or without StartDate. .Parameter ResultSize Maximum number of records to return. There is no default other than any limit that Inumbo may enforce. If a number larger than 50 is specified, the result size will be the number of available records if the total is within the next higher multiple of 50, or the next higher multiple of 50 if there are more records. For example, if the ResultSize parameter is 65 and there are 80 records, the result size will be 80; if there are 120 records, the result size will be 100. .Example Get-InumboTracking.ps1 -StartDate "3/21/16 7:00 AM" .Example Get-InumboTracking.ps1 -Sender johndoe@company.com -EndDate "3/18/16 9:00 AM -0700" .Notes Version: 1.0 Date: 3/21/16 #> Param ( [ValidateSet('QUARANTINE', 'DELIVER', 'DELETE', 'BOUNCE', 'REJECT', 'DEFER', 'ERROR')][string]$Action, [ValidateScript({$_ -as [System.Net.Mail.MailAddress]})][string]$Sender, [ValidateScript({$_ -as [System.Net.Mail.MailAddress]})][string]$Recipient, [string]$Subject, [ValidateScript({$_ -as [System.Net.IPAddress]})][string]$SenderIP, [DateTime]$StartDate, [DateTime]$EndDate, [int]$ResultSize ) #Put your Inumbo read-only or read/write key below $apiKey = '123456789abcdefghijklmnopqrst' #This function requires .NET 4.6 #If using a lower version, the function can be modified to use a timespan to make the calculation #http://stackoverflow.com/questions/4192971/in-powershell-how-do-i-convert-datetime-to-unix-time function Get-UnixTime ($date) { $dateOffset = New-Object -TypeName System.DateTimeOffset($date) $dateOffset.ToUnixTimeSeconds() } function Get-RPDScoreTranslation ($score) { #RPD is CYREN's Recurrent Pattern Detection anti-spam engine if (-not($score)) {return $null} switch ([int]$score) { 0 {$return = 'Unknown'} 10 {$return = 'Suspect'} 40 {$return = 'ValidBulk'} 50 {$return = 'Bulk'} 100 {$return = 'Spam'} } $return } #Convert API key to credential object to send as a password $credential = New-Object -TypeName Management.Automation.PSCredential('api',(ConvertTo-SecureString $apiKey -AsPlainText -Force)) $url = 'https://api.inumbo.com/v1/tracking' #Build query if ($Action -or $Sender -or $Recipient -or $SenderIP -or $Subject -or $StartDate -or $EndDate) { $queryString = '&query=' if ($Action) { $queryString += 'action=' + $Action.ToUpper() + ' ' } if ($Sender) { $queryString += "from=$Sender " } if ($Recipient) { $queryString += "to=$Recipient " } if ($SenderIP) { $queryString += "ip=$SenderIP " } if ($Subject) { $queryString += "subject~$Subject " } if ($StartDate) { #Convert date to Unix time format needed by API $start = Get-UnixTime $StartDate $queryString += "time>$start " } if ($EndDate) { #Convert date to Unix time format needed by API $end = Get-UnixTime $EndDate $queryString += "time<$end " } $queryString = $queryString.TrimEnd(' ') } if ($ResultSize -le 50 -and $ResultSize -gt 0) { #Use limit parameter if result size specified is 50 or less $limitParam = "?limit=$ResultSize" $fullUrl = $url + $limitParam + $queryString $response = Invoke-RestMethod -Method Get -Uri $fullUrl -Credential $credential $result = $response.items } else { $offset = 0 do { #If no result size or larger than 50, use paging to build result object $offsetParam = "?offset=$offset" $fullUrl = $url + $offsetParam + $queryString $response = Invoke-RestMethod -Method Get -Uri $fullUrl -Credential $credential $result += $response.items $offset = $offset + 50 } until ($response.total_count -eq 0 -or $result.Count -ge $ResultSize) } #Filter results to contain desired properties $output = $result | Sort-Object -Property msgts | Select-Object -Property @{n='Timestamp';e={([DateTime]$_.msgts0).ToLocalTime()}}, @{n='Action';e={$_.msgaction}}, @{n='SenderIP';e={$_.msgfromserver}}, @{n='Sender';e={$_.msgfrom}}, @{n='Recipient';e={$_.msgto}}, @{n='Subject';e={$_.msgsubject}}, #Convert spam rating to corresponding word meaning @{n='RPDScore';e={Get-RPDScoreTranslation $_.score_rpd}}, #SpamAssassin rating (>=5 means spam) @{n='SAScore';e={[math]::Round($_.score_sa,1)}}, @{n='Description';e={$_.msgdescription}} #Add custom type for use with formatting file foreach ($entry in $output) { $entry.pstypenames.Insert(0,'Tracking.Information') } #Create the default property display set (mostly for use without formatting file) $defaultDisplaySet = 'Timestamp','Action','Sender','Recipient','Subject' $defaultDisplayPropertySet = New-Object -TypeName System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet) $psStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) $output | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $psStandardMembers Write-Output $output |