First, connect to exchange server via EWS Java API as
1 2 3 4 5 6 7 8 9 10 11 | ExchangeService service; private void init() throws Exception { service = new ExchangeService(ExchangeVersion.Exchange2010_SP2); // Provide Crendentials ExchangeCredentials credentials = new WebCredentials("my_login_id", "nypassword", "my_login_domain"); service.setCredentials(credentials); service.setUrl(new URI("https://somepoint.company.com/EWS/exchange.asmx")); } |
then, talk to exchange server to subscribe to push notification as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private void subscribeToPush() throws Exception { WellKnownFolderName wkFolder = WellKnownFolderName.Inbox; FolderId folderId = new FolderId(wkFolder); List<FolderId> folder = new ArrayList<FolderId>(); folder.add(folderId); URI callback = new URI("http://my_notification_listener_host:7777/podm/rs/emailnotification"); PushSubscription pushSubscription = service.subscribeToPushNotifications( folder, callback /* The endpoint of the listener. */, 5 /* Get a status event every 5 minutes if no new events are available. */, null /* watermark: null to start a new subscription. */, EventType.NewMail); System.out.println("PushSubscription = " + pushSubscription); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Enter String"); String s = br.readLine(); } |
The push notification listener is implemented as Restful Web Service in Java as
1 2 3 4 5 6 7 8 9 | @POST() @Path("/emailnotification") @Produces(MediaType.TEXT_XML) public Response onNotificationReceived() throws Exception { logger.debug("received EWS notification"); File file = new File("C:\\Users\\XYZ\\workspace\\POC\\ews_notification_response.xml"); String responseXMLStr = IOUtils.toString(new FileInputStream(file)); return Response.ok(responseXMLStr).build(); } |
Once deployed to JBoss AS 7.1, below are the traffic back end force between notification listener and exchange server as
on new email arrived in INBOX, exchange server notify our registered notification listener via SOAP message as
notification SOAP message header:
POST /podm/rs/emailnotification HTTP/1.1 Content-Type: text/xml; charset=utf-8 Accept: text/xml SOAPAction: http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification Host: my_notification_listener_host:8080 Content-Length: 1492 Connection: Close
notification SOAP message body:
<?xml version="1.0" encoding="UTF-8"?> <soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"> <soap11:Header> <t:RequestServerVersion xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" Version="Exchange2010_SP2" /> </soap11:Header> <soap11:Body> <m:SendNotification xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <m:ResponseMessages> <m:SendNotificationResponseMessage ResponseClass="Success"> <m:ResponseCode>NoError</m:ResponseCode> <m:Notification> <t:SubscriptionId>EABnaXphLWZlLm93ZmcuY29tEAAAAA4cC3zQY3VAn3vY0tY6uAZ8uvK7TlLSCA==</t:SubscriptionId> <t:PreviousWatermark>AQAAAB0YmFETCChLogUFZRl0jsftgtkCAAAAAAA=</t:PreviousWatermark> <t:MoreEvents>false</t:MoreEvents> <t:NewMailEvent> <t:Watermark>AQAAAB0YmFETCChLogUFZRl0jscHg9kCAAAAAAE=</t:Watermark> <t:TimeStamp>2015-05-01T17:52:40Z</t:TimeStamp> <t:ItemId Id="AAMkADAzNTU1N2I2LWY1MTgtNDFmMC1iMzY0LWQ0YzE0NzJiNTBlYwBGAAAAAACwfA0zVZM5SIQ183rvBHkaBwAgnojIUDF8R5DPCbpjOk1jAAAATOY4AAAgnojIUDF8R5DPCbpjOk1jAAAATidsAAA=" ChangeKey="CQAAAA==" /> <t:ParentFolderId Id="AQMkADAzNTUBN2I2LWY1MTgtNDFmMC1iMzY0LWQ0YzE0NzJiNTBlYwAuAAADsHwNM1WTOUiENfN67wR5GgEAIJ6IyFAxfEeQzwm6YzpNYwAAAUzmOAAAAA==" ChangeKey="AQAAAA==" /> </t:NewMailEvent> </m:Notification> </m:SendNotificationResponseMessage> </m:ResponseMessages> </m:SendNotification> </soap11:Body> </soap11:Envelope>
Once our notification listener receives a notification from exchange server, it sends back a ACK response to exchange server and also let exchange server know it's still alive:
notification response message header:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/xml Content-Length: 474 Date: Fri, 01 May 2015 17:52:41 GMT Connection: close
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <m:SendNotificationResult> <m:SubscriptionStatus>OK</m:SubscriptionStatus> </m:SendNotificationResult> </soap:Body> </soap:Envelope>
More traffic output:
14:38:29,151 DEBUG [jwang.poc.ejbs.EmailProcessorSB] (ServerService Thread Pool -- 64) subscription id=EABnaXphLWZlLm93ZmcuY29tEAAAAGcHwXOH1UFIuzwCceWIzEw2k58eE1vSCA==
14:38:29,152 INFO [jwang.poc.ejbs.EmailProcessorSB] (ServerService Thread Pool -- 64) resumed subscription to push notification on exchange server with previous watermark = AQAAAB0YmFETCChLogUFZRl0jscNWfACAAAAAAA=
*** notification with events
<?xml version="1.0" encoding="UTF-8"?>
<soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header>
<t:RequestServerVersion xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" Version="Exchange2010_SP2" />
</soap11:Header>
<soap11:Body>
<m:SendNotification xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:SendNotificationResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Notification>
<t:SubscriptionId>EABnaXphLWZlLm93ZmcuY29tEAAAAGcHwXOH1UFIuzwCceWIzEw2k58eE1vSCA==</t:SubscriptionId>
<t:PreviousWatermark>AQAAAB0YmFETCChLogUFZRl0jscE+vACAAAAAAE=</t:PreviousWatermark>
<t:MoreEvents>false</t:MoreEvents>
<t:NewMailEvent>
<t:Watermark>AQAAAB0YmFETCChLogUFZRl0jsd/BPECAAAAAAE=</t:Watermark>
<t:TimeStamp>2015-05-12T21:39:07Z</t:TimeStamp>
<t:ItemId Id="AAMkADAzNTU1N2I2LWY1MTgtNDFmMC1iMzY0LWQ0YzE0NzJiNTBlYwBGAAAAAACwfA0zVZM5SIQ183rvBHkaBwAgnojIUDF8R5DPCbpjOk1jAAAATOY4AAAgnojIUDF8R5DPCbpjOk1jAAAATigPAAA=" ChangeKey="CQAAAA==" />
<t:ParentFolderId Id="AQMkADAzNTUBN2I2LWY1MTgtNDFmMC1iMzY0LWQ0YzE0NzJiNTBlYwAuAAADsHwNM1WTOUiENfN67wR5GgEAIJ6IyFAxfEeQzwm6YzpNYwAAAUzmOAAAAA==" ChangeKey="AQAAAA==" />
</t:NewMailEvent>
</m:Notification>
</m:SendNotificationResponseMessage>
</m:ResponseMessages>
</m:SendNotification>
</soap11:Body>
</soap11:Envelope>
** notification status ping from server without events
<?xml version="1.0" encoding="UTF-8"?>
<soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header>
<t:RequestServerVersion xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" Version="Exchange2010_SP2" />
</soap11:Header>
<soap11:Body>
<m:SendNotification xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:SendNotificationResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Notification>
<t:SubscriptionId>EABnaXphLWZlLm93ZmcuY29tEAAAAGcHwXOH1UFIuzwCceWIzEw2k58eE1vSCA==</t:SubscriptionId>
<t:PreviousWatermark>AQAAAB0YmFETCChLogUFZRl0jsd/BPECAAAAAAE=</t:PreviousWatermark>
<t:MoreEvents>false</t:MoreEvents>
<t:StatusEvent>
<t:Watermark>AQAAAB0YmFETCChLogUFZRl0jscbCPECAAAAAAE=</t:Watermark>
</t:StatusEvent>
</m:Notification>
</m:SendNotificationResponseMessage>
</m:ResponseMessages>
</m:SendNotification>
</soap11:Body>
</soap11:Envelope>
By observation, exchange server seems generate new subscription id for every new subscription to push notification request (even with valid previous watermark parameter). After JBoss AS restars and new email arrives in inbox, exchange server will send notification event to all subscriptions (old and new). When we received a notification, we can check if its notification id matches our current active notification id, if not, we can response with "unscribe" to the exchange server to unscribe the stale subscription.
Unsubscribe response as:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <m:SendNotificationResult> <m:SubscriptionStatus>Unsubscribe</m:SubscriptionStatus> </m:SendNotificationResult> </soap:Body> </soap:Envelope>
as for the notification of current active notification id, we can response with OK to tell the exchange server we got the message and we're still alive:
OK response as:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <m:SendNotificationResult> <m:SubscriptionStatus>OK</m:SubscriptionStatus> </m:SendNotificationResult> </soap:Body> </soap:Envelope>