Delivery Reports were introduced in Exchange 2010 and provide a method for users to verify that the messages they’ve sent have been successfully delivered. Users are able to generate these reports from the Delivery Reports screen in the Exchange Control Panel (ECP), which is also where Outlook 2010 will send them when they track a message. Since the ECP is driven by Exchange Management Shell cmdlets, we can create and view these reports using PowerShell. This gives you another tool to verify message delivery—in addition to the existing message tracking search functionality—but it can also provide the “read status” of a message. Let’s start off with a basic example.

To create a delivery report from the shell, you first need to use the Search-MessageTrackingReport cmdlet. This will give you a list of one or more reports, and you’ll need to pass the report id returned by this command to another cmdlet to get more details. Because of that, the bast way to handle this is to save the output in a variable:

$msg = Search-MessageTrackingReport -Identity allen -Recipients rob@uss.local -BypassDelegateChecking

If you want to search delivery reports for a mailbox other than your own, you need to use the -BypassDelegateChecking switch parameter as well. The search criteria can be based on the recipients of the message, as shown in the previous example, or on the subject of the message using the -Subject parameter.

After the search has completely successfully, use the Get-MessageTrackingReport cmdlet to review the results. To do this, we can simply iterate over each report id stored in the variable created in the previous step:

$msg | %{ Get-MessageTrackingReport -Identity $_.MessageTrackingReportId -BypassDelegateChecking }

For each message returned, the results should look similar to the following:

You can see that several details about the message are returned, including the delivery status, which was successful.

When tracking the status of a message sent to an external recipient, the we can only track the message as it leaves the last transport server on its way out of the organization. As long as this is successful, the TransferredCount will be incremented and the RecipientTrackingEvents will indicate that the message was transferred to a foreign organization.

Determining “Read Status” without Read Receipts

In addition to tracking the successful delivery of messages within the organization, you can also enable read tracking to determine the read status of a message. To do this, you first need to enable read tracking:

Set-OrganizationConfig -ReadTrackingEnabled $true

After this command has been run, read tracking will be enabled on all hub transport servers organization wide. By default, read status tracking for mailboxes is enabled. If read tracking needs to be disabled for specific users, you can disable on a per user basis using the Set-Mailbox cmdlet. For example:

Set-Mailbox -Identity steve -MessageTrackingReadStatusEnabled $false

At this point, read tracking has been enabled at the organization level, and we can determine the read status of a message by checking the delivery report. To do this, we’ll create another search. This time we’ll specify the subject of the e-mail for the search criteria:

$msg = Search-MessageTrackingReport -Identity allen -Subject 'Testing 1,2,3' -BypassDelegateChecking

According to the cmdlet help for the Get-MessageTrackingReport cmdlet, we should be able to determine the read status of a message by setting the -Status parameter to Read. So far, I haven’t been able to get that to work (I’m looking into this). However, we can still track the read status for messages using the RecipientPath report template when running the Get-MessageTrackingReport cmdlet:

$msg | %{ Get-MessageTrackingReport -Identity $_.MessageTrackingReportId -BypassDelegateChecking -RecipientPathFilter rob@uss.local -ReportTemplate RecipientPath }

When using the RecipientPath report template, you also need to set the -RecipientPathFilter parameter to the recipient address for the message. The above command produces the following output:

Notice that the RecipentTrackingEvents property shows that the message was submitted, delivered, and is also set to Read.

If you don’t have organization read tracking enabled, you can still check the read status of a message from PowerShell with the EWS Managed API. There is a great code sample for this posted here by a user in the Exchange 2010 forums on TechNet.