I tried posting this on the Exchange Development Forum and did not get any answers, so I will try here. Forum Link
I have windows services that start every 15 minutes to find out if there are any subscriptions that need to be created or updated. I am using the Managed API v1.1 for Exchange 2007 Service Pack 1 (SP1). I have a table that stores all the users who want to track the mailbox. Therefore, when a notification appears in the "Listening Service", I can find the user and access the message to put it in the application that we create. The table has the following columns in which subscription data is stored:
- SubscriptionId - VARCHAR (MAX)
- Watermark - VARCHAR (MAX)
- LastStatusUpdate - DATETIME
My services call a function that requests data (depending on what function it performs). If the user does not have a subscription, the service will go and create it. I use impersonation to access mailboxes. Here is my ActiveSubscription method, which runs when a user needs a subscription that has been created or updated.
private void ActivateSubscription(User user) { if (user.ADGUID.HasValue) { PrincipalContext ctx = new PrincipalContext(ContextType.Domain, Settings.ActiveDirectoryServerName, Settings.ActiveDirectoryRootContainer); using (UserPrincipal up = UserPrincipal.FindByIdentity(ctx, IdentityType.Guid, user.ADGUID.Value.ToString())) { ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SID, up.Sid.Value); } } else { ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress); } PushSubscription pushSubscription = ewService.SubscribeToPushNotifications( new FolderId[] { WellKnownFolderName.Inbox, WellKnownFolderName.SentItems }, Settings.ListenerService, 30, user.Watermark, EventType.NewMail, EventType.Created); user.Watermark = pushSubscription.Watermark; user.SubscriptionID = pushSubscription.Id; user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime(); _users.Update(user); }
We also ran the following cmdlet to give the user access to EWS with the ability to impersonate use on an Exchange server.
Get-ExchangeServer | where {$_.IsClientAccessServer -eq $TRUE} | ForEach-Object {Add-ADPermission -Identity $_.distinguishedname -User (Get-User -Identity mailmonitor | select-object).identity -extendedRight ms-Exch-EPI-Impersonation}
The "ActivateSubscription" code above works as expected. Or so I thought. When I tested it, I watched my inbox and it worked great. The only problem I encountered was that the subscription worked twice, when the item was a new message in the inbox, I received a notification about the NewMail event and the generated event. I checked these checks to make sure the message has not yet been registered with my listening service. Everything worked great.
Today, we started testing two mailboxes at the same time. Two mailboxes were mine and another developer mailbox. We found strange behavior. My subscription worked properly. But he is not, the incoming part of his subscription is working properly, but a notification has never been sent to any e-mail address that he sent to listen. Looking at the properties of a mailbox on Exchange, I do not see the difference between its mailbox and mine. We even compared options / settings in Outlook. I see no reason why it works on my mailbox, and not on it.
Is there something that I am missing when creating a subscription. I didnโt think it was, since my subscription works as expected.
My listening code works fine. I put the code below if someone wants to see it, to make sure that this is not a problem.
Thanks Terry
Listening Service Code:
/// <summary> /// Summary description for PushNotificationClient /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. // [System.Web.Script.Services.ScriptService] public class PushNotificationClient : System.Web.Services.WebService, INotificationServiceBinding { ExchangeService ewService = new ExchangeService(ExchangeVersion.Exchange2007_SP1); public PushNotificationClient() { //todo: init the service. SetupExchangeWebService(); } private void SetupExchangeWebService() { ewService.Credentials = Settings.ServiceCreds; try { ewService.AutodiscoverUrl(Settings.AutoDiscoverThisEmailAddress); } catch (AutodiscoverRemoteException e) { //log auto discovery failed ewService.Url = Settings.ExchangeService; } } public SendNotificationResultType SendNotification(SendNotificationResponseType SendNotification1) { using (var _users = new ExchangeUser(Settings.SqlConnectionString)) { var result = new SendNotificationResultType(); var responseMessages = SendNotification1.ResponseMessages.Items; foreach (var responseMessage in responseMessages) { if (responseMessage.ResponseCode != ResponseCodeType.NoError) { //log error and unsubscribe. result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe; return result; } var sendNoficationResponse = responseMessage as SendNotificationResponseMessageType; if (sendNoficationResponse == null) { result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe; return result; } var notificationType = sendNoficationResponse.Notification; var subscriptionId = notificationType.SubscriptionId; var previousWatermark = notificationType.PreviousWatermark; User user = _users.GetById(subscriptionId); if (user != null) { if (user.MonitorEmailYN == true) { BaseNotificationEventType[] baseNotifications = notificationType.Items; for (int i = 0; i < notificationType.Items.Length; i++) { if (baseNotifications[i] is BaseObjectChangedEventType) { var bocet = baseNotifications[i] as BaseObjectChangedEventType; AccessCreateDeleteNewMailEvent(bocet, ref user); } } _PreviousItemId = null; } else { user.SubscriptionID = String.Empty; user.SubscriptionStatusDateTime = null; user.Watermark = String.Empty; _users.Update(user); result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe; return result; } user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime(); _users.Update(user); } else { result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe; return result; } } result.SubscriptionStatus = SubscriptionStatusType.OK; return result; } } private string _PreviousItemId; private void AccessCreateDeleteNewMailEvent(BaseObjectChangedEventType bocet, ref User user) { var watermark = bocet.Watermark; var timestamp = bocet.TimeStamp.ToLocalTime(); var parentFolderId = bocet.ParentFolderId; if (bocet.Item is ItemIdType) { var itemId = bocet.Item as ItemIdType; if (itemId != null) { if (string.IsNullOrEmpty(_PreviousItemId) || (!string.IsNullOrEmpty(_PreviousItemId) && _PreviousItemId != itemId.Id)) { ProcessItem(itemId, ref user); _PreviousItemId = itemId.Id; } } } user.SubscriptionStatusDateTime = timestamp; user.Watermark = watermark; using (var _users = new ExchangeUser(Settings.SqlConnectionString)) { _users.Update(user); } } private void ProcessItem(ItemIdType itemId, ref User user) { try { ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress); EmailMessage email = EmailMessage.Bind(ewService, itemId.Id); using (var _entity = new SalesAssistantEntityDataContext(Settings.SqlConnectionString)) { var direction = EmailDirection.Incoming; if (email.From.Address == user.EmailAddress) { direction = EmailDirection.Outgoing; } int? bodyType = (int)email.Body.BodyType; var _HtmlToRtf = new HtmlToRtf(); var message = _HtmlToRtf.ConvertHtmlToText(email.Body.Text); bool? IsIncoming = Convert.ToBoolean((int)direction); if (IsIncoming.HasValue && IsIncoming.Value == false) { foreach (var emailTo in email.ToRecipients) { _entity.InsertMailMessage(email.From.Address, emailTo.Address, email.Subject, message, bodyType, IsIncoming); } } else { if (email.ReceivedBy != null) { _entity.InsertMailMessage(email.From.Address, email.ReceivedBy.Address, email.Subject, message, bodyType, IsIncoming); } else { var emailToFind = user.EmailAddress; if (email.ToRecipients.Any(x => x.Address == emailToFind)) { _entity.InsertMailMessage(email.From.Address, emailToFind, email.Subject, message, bodyType, IsIncoming); } } } } } catch(Exception e) { //Log exception using (var errorHandler = new ErrorHandler(Settings.SqlConnectionString)) { errorHandler.LogException(e, user.UserID, user.SubscriptionID, user.Watermark, user.SubscriptionStatusDateTime); } throw e; } } }