Answered by:
Retrieving ALL Delivery statuses in MessageTracking - EWS

Question
-
Hi!
Using Exchange 2010 SP1 Web Service for tracking sent emails. VS 2010 C#.
I am trying to retrieve ALL the delivery statuses for a sent email per each recipient. For now, I can only retrieve one status per recipient. (The last status message whether it is delivered or has failed). The picture below shows the two statuses I want to retrieve: Submitted and Failed.
I even have messages with three statuses, but i am only able to retrieve the LAST status from EWS MessageTrackingCenter.
Here is my code:
In the mail folder "sentitems" i will fetch one mail based on a unique subject "Test 1" and show ALL statuses for this one mail.
private string FindAllStatusesEWS() { string sURL = "https://myExchangeServer.com/EWS/Exchange.asmx"; string sUserName= "myUser"; string sPassword = "myPassword"; string sDomain = "myDomain"; string sEmailFrom = "myUser@myDomain.com"; string sScope = "Site"; string sSubject = "Test 1"; string sResultat = MessageTrackingDeliveryStatusType.Unknown.ToString(); List<MessageTrackingEntity> METCollection = new List<MessageTrackingEntity>(); try { this._esb = new ExchangeServiceBinding(); this._esb.Url = sURL; this._esb.Credentials = new NetworkCredential(sUserName, sPassword, sDomain); this._esb.RequestServerVersionValue = new RequestServerVersion(); this._esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2010_SP1; Type enumType = typeof(DistinguishedFolderIdNameType); string selection = (string)cbFolder.Text; DistinguishedFolderIdNameType value = DistinguishedFolderIdNameType.sentitems ; this._fc = new FolderCache("", this._esb, value); // FindItem Request Properties FindItemType fit = new FindItemType(); fit.ParentFolderIds = this._fc.EWSSourceFolderId; fit.Traversal = ItemQueryTraversalType.Shallow; // Set Request Shape ItemResponseShapeType oShape = new ItemResponseShapeType(); oShape.BaseShape = DefaultShapeNamesType.AllProperties; fit.ItemShape = oShape; // Create a restriction RestrictionType rt = new RestrictionType(); ContainsExpressionType cet = new ContainsExpressionType(); // Specify how the search expressoin is compared cet.ContainmentComparison = ContainmentComparisonType.IgnoreCase; cet.ContainmentComparisonSpecified = true; cet.ContainmentMode = ContainmentModeType.Substring; cet.ContainmentModeSpecified = true; // Identify the field to identify the item field to examine PathToUnindexedFieldType ptuft = new PathToUnindexedFieldType(); ptuft.FieldURI = UnindexedFieldURIType.itemSubject; // Add the field to compare to the search expression cet.Item = ptuft; // Identify the value to compare to the examined field (ItemClass) ConstantValueType cvt = new ConstantValueType(); cvt.Value = sSubject; // Add the value to the search expression cet.Constant = cvt; // Add the search expression to the restriction rt.Item = cet; // Add the restriction to the request fit.Restriction = rt; // Find Items FindItemResponseType firt = this._esb.FindItem(fit); FindItemResponseMessageType firmt = (FindItemResponseMessageType)firt.ResponseMessages.Items[0]; ArrayOfRealItemsType aItem = new ArrayOfRealItemsType(); aItem = (ArrayOfRealItemsType)firmt.RootFolder.Item; if (aItem.Items != null) { if (aItem.Items.Length < 2) { if (aItem.Items.Length > 0) { foreach (ItemType aorit in aItem.Items) { MessageType mt = (MessageType)aorit; // Build Message ID Search FindMessageTrackingReportRequestType fmtRequest = new FindMessageTrackingReportRequestType(); fmtRequest.Domain = sDomain; fmtRequest.Scope = sScope; fmtRequest.MessageId = mt.InternetMessageId; fmtRequest.Sender = new EmailAddressType(); fmtRequest.Sender.EmailAddress = sEmailFrom; // Search FindMessageTrackingReportResponseMessageType fmtResponse = this._esb.FindMessageTrackingReport(fmtRequest); if (fmtResponse.MessageTrackingSearchResults != null) { GetMessageTrackingReportRequestType gmt = new GetMessageTrackingReportRequestType(); gmt.Scope = sScope; foreach (FindMessageTrackingSearchResultType mtsResult in fmtResponse.MessageTrackingSearchResults) { gmt.MessageTrackingReportId = mtsResult.MessageTrackingReportId; GetMessageTrackingReportResponseMessageType gmtResponse = this._esb.GetMessageTrackingReport(gmt); foreach (RecipientTrackingEventType rte in gmtResponse.MessageTrackingReport.RecipientTrackingEvents) { MessageBox.Show("Mail to: " + rte.Recipient.EmailAddress + ", Status: " + rte.DeliveryStatus); } } } } } } else { lb.Items.Add(String.Format("Subject: {0}: Error: More than one mail found.", sSubject)); } } else { lb.Items.Add(String.Format("Subject: {0}: Error: No mail found.", sSubject)); } } catch (Exception ex) { throw new Exception("Error. ", ex); } return sResultat; }
Could anyone please point me in the right direction?
Best Regards
Gunnarvoy
Friday, May 20, 2011 2:22 PM
Answers
-
Thanks for trying to help, JoSwa, but I was perhaps a bit unclear.
By "retrieving all delivery statuses" I meant all the events that was related to a sent mail (statuses like Pending and Transferred) per recipient - just like the report in "Open Delivery Report" menu item when right clicking on a mail in the sentitems folder in the outlook web client.
I found a solution, and for the sake of completeness I post it here:
From the code below, replace
foreach (FindMessageTrackingSearchResultType mtsResult in fmtResponse.MessageTrackingSearchResults) { gmt.MessageTrackingReportId = mtsResult.MessageTrackingReportId; GetMessageTrackingReportResponseMessageType gmtResponse = this._esb.GetMessageTrackingReport(gmt); foreach (RecipientTrackingEventType rte in gmtResponse.MessageTrackingReport.RecipientTrackingEvents) { MessageBox.Show("Mail to: " + rte.Recipient.EmailAddress + ", Status: " + rte.DeliveryStatus); }
with
foreach (FindMessageTrackingSearchResultType mtsResult in fmtResponse.MessageTrackingSearchResults) { gmt.MessageTrackingReportId = mtsResult.MessageTrackingReportId; gmt.ReportTemplate = MessageTrackingReportTemplateType.RecipientPath; foreach (EmailAddressType mtsrRecipients in mtsResult.Recipients) { gmt.RecipientFilter = mtsrRecipients; GetMessageTrackingReportResponseMessageType gmtResponse = this._esb.GetMessageTrackingReport(gmt); METCollection.AddRange(MessageTrackingEntityPopulate(gmtResponse)); } }
where MessageTrackingEntityPopulate is as follows:/// <summary> /// Populate a list of MessageTrackingEntity. Contains delivery status and EventDescription per recipient. /// </summary> /// <param name="gmtResponse">GetMessageTrackingReportResponseMessageType</param> /// <returns>List<MessageTrackingEntity></returns> private List<MessageTrackingEntity> MessageTrackingEntityPopulate(GetMessageTrackingReportResponseMessageType gmtResponse) { List<MessageTrackingEntity> MTEList = new List<MessageTrackingEntity>(); MessageTrackingReportType mtr = gmtResponse.MessageTrackingReport; //DeliveryStatus foreach (RecipientTrackingEventType rte in mtr.RecipientTrackingEvents) { MessageTrackingEntity MTE = new MessageTrackingEntity(); //Dont care to track the NOTREAD or READ statuses if (rte.EventDescription.ToUpper() == "NOTREAD" || rte.EventDescription.ToUpper() == "READ") continue; //EventDescription MTE.EventDescription = rte.EventDescription; //Submit time MTE.SubmitTime = mtr.SubmitTime; //Tracking date MTE.TrackingDate = rte.Date; //Subject MTE.Subject = mtr.Subject; //DeliveryStatus MTE.DeliveryStatus = rte.DeliveryStatus; //RecipientEmailAddress MTE.RecipientsEmailAddress = rte.Recipient.EmailAddress; //Name MTE.Name = rte.Recipient.Name; //EventData if (rte.EventData != null) { StringBuilder sbEventData = new StringBuilder(); //Append EventData foreach (string ed in rte.EventData) sbEventData.Append(ed + ", "); //Remove trailing ', ' if (sbEventData.Length > 0) sbEventData.Remove(sbEventData.Length - 2, 2); } MTEList.Add(MTE); } return MTEList; }
The clue was to assign MessageTrackingReportTemplateType.RecipientPath to gmt.ReportTemplate, and for each recipients in mtsResult.Recipients apply the recipient email address as a filter to gmt.RecipientFilter.Best Regards
Gunnarvoy
- Marked as answer by Gunnarvoy Friday, July 1, 2011 9:47 AM
Friday, July 1, 2011 9:36 AM
All replies
-
Helo Gunnarvoy..
In Exchange server 2010 have 25 field and there one field "EventID" only have the Delivery status value.
EventID This search filter uses the event-id field. The value must exactly match one of the possible EventID values. EventID is the event classification that is assigned to each message tracking log entry. The available values are BADMAIL, DEFER, DELIVER, DSN, EXPAND, FAIL, POISONMESSAGE, RECEIVE, REDIRECT, RESOLVE, SEND, SUBMIT, and TRANSFER.By
A PathFinder
JoSwa..Monday, May 23, 2011 5:48 PM -
Thanks for trying to help, JoSwa, but I was perhaps a bit unclear.
By "retrieving all delivery statuses" I meant all the events that was related to a sent mail (statuses like Pending and Transferred) per recipient - just like the report in "Open Delivery Report" menu item when right clicking on a mail in the sentitems folder in the outlook web client.
I found a solution, and for the sake of completeness I post it here:
From the code below, replace
foreach (FindMessageTrackingSearchResultType mtsResult in fmtResponse.MessageTrackingSearchResults) { gmt.MessageTrackingReportId = mtsResult.MessageTrackingReportId; GetMessageTrackingReportResponseMessageType gmtResponse = this._esb.GetMessageTrackingReport(gmt); foreach (RecipientTrackingEventType rte in gmtResponse.MessageTrackingReport.RecipientTrackingEvents) { MessageBox.Show("Mail to: " + rte.Recipient.EmailAddress + ", Status: " + rte.DeliveryStatus); }
with
foreach (FindMessageTrackingSearchResultType mtsResult in fmtResponse.MessageTrackingSearchResults) { gmt.MessageTrackingReportId = mtsResult.MessageTrackingReportId; gmt.ReportTemplate = MessageTrackingReportTemplateType.RecipientPath; foreach (EmailAddressType mtsrRecipients in mtsResult.Recipients) { gmt.RecipientFilter = mtsrRecipients; GetMessageTrackingReportResponseMessageType gmtResponse = this._esb.GetMessageTrackingReport(gmt); METCollection.AddRange(MessageTrackingEntityPopulate(gmtResponse)); } }
where MessageTrackingEntityPopulate is as follows:/// <summary> /// Populate a list of MessageTrackingEntity. Contains delivery status and EventDescription per recipient. /// </summary> /// <param name="gmtResponse">GetMessageTrackingReportResponseMessageType</param> /// <returns>List<MessageTrackingEntity></returns> private List<MessageTrackingEntity> MessageTrackingEntityPopulate(GetMessageTrackingReportResponseMessageType gmtResponse) { List<MessageTrackingEntity> MTEList = new List<MessageTrackingEntity>(); MessageTrackingReportType mtr = gmtResponse.MessageTrackingReport; //DeliveryStatus foreach (RecipientTrackingEventType rte in mtr.RecipientTrackingEvents) { MessageTrackingEntity MTE = new MessageTrackingEntity(); //Dont care to track the NOTREAD or READ statuses if (rte.EventDescription.ToUpper() == "NOTREAD" || rte.EventDescription.ToUpper() == "READ") continue; //EventDescription MTE.EventDescription = rte.EventDescription; //Submit time MTE.SubmitTime = mtr.SubmitTime; //Tracking date MTE.TrackingDate = rte.Date; //Subject MTE.Subject = mtr.Subject; //DeliveryStatus MTE.DeliveryStatus = rte.DeliveryStatus; //RecipientEmailAddress MTE.RecipientsEmailAddress = rte.Recipient.EmailAddress; //Name MTE.Name = rte.Recipient.Name; //EventData if (rte.EventData != null) { StringBuilder sbEventData = new StringBuilder(); //Append EventData foreach (string ed in rte.EventData) sbEventData.Append(ed + ", "); //Remove trailing ', ' if (sbEventData.Length > 0) sbEventData.Remove(sbEventData.Length - 2, 2); } MTEList.Add(MTE); } return MTEList; }
The clue was to assign MessageTrackingReportTemplateType.RecipientPath to gmt.ReportTemplate, and for each recipients in mtsResult.Recipients apply the recipient email address as a filter to gmt.RecipientFilter.Best Regards
Gunnarvoy
- Marked as answer by Gunnarvoy Friday, July 1, 2011 9:47 AM
Friday, July 1, 2011 9:36 AM