Very cool new feature! -David On May 7, 2009, at 3:29 PM, [hidden email] wrote: > Author: jaz > Date: Thu May 7 21:29:06 2009 > New Revision: 772780 > > URL: http://svn.apache.org/viewvc?rev=772780&view=rev > Log: > implemented service to process bounced emails and update the > communication event status > > > Added: > ofbiz/trunk/applications/party/servicedef/mcas.xml > Modified: > ofbiz/trunk/applications/party/ofbiz-component.xml > ofbiz/trunk/applications/party/servicedef/services.xml > ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/ > CommunicationEventServices.java > > Modified: ofbiz/trunk/applications/party/ofbiz-component.xml > URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/ofbiz-component.xml?rev=772780&r1=772779&r2=772780&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/applications/party/ofbiz-component.xml (original) > +++ ofbiz/trunk/applications/party/ofbiz-component.xml Thu May 7 > 21:29:06 2009 > @@ -34,7 +34,8 @@ > <service-resource type="model" loader="main" > location="servicedef/services.xml"/> > <service-resource type="model" loader="main" > location="servicedef/services_view.xml"/> > <service-resource type="eca" loader="main" location="servicedef/ > secas.xml"/> > - > + <service-resource type="mca" loader="main" location="servicedef/ > mcas.xml"/> > + > <test-suite loader="main" location="testdef/PartyTests.xml"/> > > <webapp name="party" > > Added: ofbiz/trunk/applications/party/servicedef/mcas.xml > URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/mcas.xml?rev=772780&view=auto > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/applications/party/servicedef/mcas.xml (added) > +++ ofbiz/trunk/applications/party/servicedef/mcas.xml Thu May 7 > 21:29:06 2009 > @@ -0,0 +1,28 @@ > +<?xml version="1.0" encoding="UTF-8"?> > +<!-- > +Licensed to the Apache Software Foundation (ASF) under one > +or more contributor license agreements. See the NOTICE file > +distributed with this work for additional information > +regarding copyright ownership. The ASF licenses this file > +to you under the Apache License, Version 2.0 (the > +"License"); you may not use this file except in compliance > +with the License. You may obtain a copy of the License at > + > +http://www.apache.org/licenses/LICENSE-2.0 > + > +Unless required by applicable law or agreed to in writing, > +software distributed under the License is distributed on an > +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > +KIND, either express or implied. See the License for the > +specific language governing permissions and limitations > +under the License. > +--> > + > +<service-mca xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > + xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/service-mca.xsd > "> > + > + <mca mail-rule-name="processBouncedMessage"> > + <action service="processBouncedMessage" mode="sync"/> > + </mca> > + > +</service-mca> > > Modified: ofbiz/trunk/applications/party/servicedef/services.xml > URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/services.xml?rev=772780&r1=772779&r2=772780&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/applications/party/servicedef/services.xml (original) > +++ ofbiz/trunk/applications/party/servicedef/services.xml Thu May > 7 21:29:06 2009 > @@ -93,7 +93,10 @@ > <service name="updatePerson" engine="java" default-entity- > name="Person" > location="org.ofbiz.party.party.PartyServices" > invoke="updatePerson" auth="true"> > <description>Update a Person</description> > - <permission-service service- > name="partyGroupPermissionCheck" main-action="UPDATE"/> > + <required-permissions join-type="AND"> > + <check-permission permission="update:party:${partyId}"/> > + </required-permissions> > + <!-- <permission-service service- > name="partyGroupPermissionCheck" main-action="UPDATE"/> --> > <auto-attributes mode="IN" include="pk" optional="true"><!-- > if no partyId specified will use userLogin.partyId --></auto- > attributes> > <auto-attributes mode="IN" include="nonpk" optional="true"/> > <attribute name="preferredCurrencyUomId" type="String" > mode="IN" optional="true"/> > @@ -1167,4 +1170,10 @@ > <attribute name="contactMechId" type="String" mode="IN" > optional="true"/> > <attribute name="contactMechId" type="String" mode="OUT" > optional="false"/> > </service> > + > + <!-- bounced message processing --> > + <service name="processBouncedMessage" engine="java" > + > location="org.ofbiz.party.communication.CommunicationEventServices" > invoke="processBouncedMessage"> > + <implements service="mailProcessInterface"/> > + </service> > </services> > > Modified: ofbiz/trunk/applications/party/src/org/ofbiz/party/ > communication/CommunicationEventServices.java > URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java?rev=772780&r1=772779&r2=772780&view=diff > = > = > = > = > = > = > = > = > ====================================================================== > --- ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/ > CommunicationEventServices.java (original) > +++ ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/ > CommunicationEventServices.java Thu May 7 21:29:06 2009 > @@ -31,8 +31,12 @@ > import java.util.Map; > import java.util.Set; > import java.util.TreeSet; > +import java.util.regex.Matcher; > +import java.util.regex.Pattern; > > import javax.mail.Address; > +import javax.mail.BodyPart; > +import javax.mail.Header; > import javax.mail.MessagingException; > import javax.mail.Multipart; > import javax.mail.Part; > @@ -946,4 +950,115 @@ > } > return attachmentCount; > } > + > + /* > + * Service to process incoming email and look for a bounce > message. If the email is indeed a bounce message > + * the CommunicationEvent will be updated with the proper > COM_BOUNCED status. > + */ > + public static Map<String,Object> > processBouncedMessage(DispatchContext dctx, Map<String, ? extends > Object> context) { > + Debug.logInfo("Running process bounced message check...", > module); > + MimeMessageWrapper wrapper = (MimeMessageWrapper) > context.get("messageWrapper"); > + MimeMessage message = wrapper.getMessage(); > + > + LocalDispatcher dispatcher = dctx.getDispatcher(); > + GenericDelegator delegator = dctx.getDelegator(); > + > + try { > + Object content = message.getContent(); > + if (content instanceof Multipart) { > + Multipart mp = (Multipart) content; > + int parts = mp.getCount(); > + > + if (parts >= 3) { // it must have all three parts > in order to process correctly > + > + // get the second part (delivery report) > + BodyPart part2 = mp.getBodyPart(1); // index 1 > should be the second part > + String contentType = part2.getContentType(); > + if (contentType != null && "message/delivery- > status".equalsIgnoreCase(contentType)) { > + Debug.logInfo("Delivery status report part > found; processing...", module); > + > + // message is only available as an input > stream; read the stream > + InputStream insPart2 = (InputStream) > part2.getInputStream(); > + int part2Size = part2.getSize(); > + byte[] part2Bytes = new byte[part2Size]; > + insPart2.read(part2Bytes, 0, part2Size); > + String part2Text = new String(part2Bytes); > + > + // find the "Action" element and obtain its > value (looking for "failed") > + Pattern p2 = Pattern.compile("^Action: (.*) > $", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); > + Matcher m2 = p2.matcher(part2Text); > + String action = null; > + if (m2.find()) { > + action = m2.group(1); > + } > + > + if (action != null && > "failed".equalsIgnoreCase(action)) { > + // message bounced -- get the original > message > + BodyPart part3 = mp.getBodyPart(2); // > index 2 should be the third part > + > + // read part 3 message > + InputStream insPart3 = (InputStream) > part3.getInputStream(); > + int part3Size = part3.getSize(); > + byte[] part3Bytes = new byte[part3Size]; > + insPart3.read(part3Bytes, 0, part3Size); > + String part3Text = new > String(part3Bytes); > + > + // find the "Message-Id" element and > obtain its value (looking for "failed") > + Pattern p3 = Pattern.compile("^Message- > Id: (.*)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); > + Matcher m3 = p3.matcher(part3Text); > + String messageId = null; > + if (m3.find()) { > + messageId = m3.group(1); > + } > + > + // find the matching communication event > + if (messageId != null) { > + List<GenericValue> values; > + try { > + values = > delegator.findByAnd("CommunicationEvent", > UtilMisc.toMap("messageId", messageId)); > + } catch (GenericEntityException e) { > + Debug.logError(e, module); > + return > ServiceUtil.returnError(e.getMessage()); > + } > + if (values != null && values.size() > > 0) { > + // there should be only one; > unique key > + GenericValue value = > values.get(0); > + > + // update the communication > event status > + Map<String,Object> updateCtx = > FastMap.newInstance(); > + > updateCtx.put("communicationEventId", > value.getString("communicationEventId")); > + updateCtx.put("statusId", > "COM_BOUNCED"); > + updateCtx.put("userLogin", > context.get("userLogin")); > + Map<String,Object> result; > + try { > + result = > dispatcher.runSync("updateCommunicationEvent", updateCtx); > + } catch > (GenericServiceException e) { > + Debug.logError(e, module); > + return > ServiceUtil.returnError(e.getMessage()); > + } > + if > (ServiceUtil.isError(result)) { > + return > ServiceUtil.returnError(ServiceUtil.getErrorMessage(result)); > + } > + } else { > + if (Debug.infoOn()) { > + Debug.logInfo("Unable to > find communication event with the matching messageId : " + > messageId, module); > + } > + } > + } else { > + Debug.logWarning("No message ID > attached to part", module); > + } > + } > + } > + } > + } > + } catch (MessagingException e) { > + Debug.logError(e, module); > + return ServiceUtil.returnError(e.getMessage()); > + } catch (IOException e) { > + Debug.logError(e, module); > + return ServiceUtil.returnError(e.getMessage()); > + } > + > + return ServiceUtil.returnSuccess(); > + } > } > > |
Indeed it is :) Rev 772850 and 772851 improve it even more by adding
support to catch bounce messages on newsletter marketing emails (the ones which don't create unique communication events per email) and invalidating an email address from the contact list when it bounces. Andrew On May 7, 2009, at 7:21 PM, David E Jones wrote: > > Very cool new feature! > > -David > > > On May 7, 2009, at 3:29 PM, [hidden email] wrote: > >> Author: jaz >> Date: Thu May 7 21:29:06 2009 >> New Revision: 772780 >> >> URL: http://svn.apache.org/viewvc?rev=772780&view=rev >> Log: >> implemented service to process bounced emails and update the >> communication event status >> >> >> Added: >> ofbiz/trunk/applications/party/servicedef/mcas.xml >> Modified: >> ofbiz/trunk/applications/party/ofbiz-component.xml >> ofbiz/trunk/applications/party/servicedef/services.xml >> ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/ >> CommunicationEventServices.java >> >> Modified: ofbiz/trunk/applications/party/ofbiz-component.xml >> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/ofbiz-component.xml?rev=772780&r1=772779&r2=772780&view=diff >> = >> = >> = >> = >> = >> = >> = >> = >> = >> ===================================================================== >> --- ofbiz/trunk/applications/party/ofbiz-component.xml (original) >> +++ ofbiz/trunk/applications/party/ofbiz-component.xml Thu May 7 >> 21:29:06 2009 >> @@ -34,7 +34,8 @@ >> <service-resource type="model" loader="main" >> location="servicedef/services.xml"/> >> <service-resource type="model" loader="main" >> location="servicedef/services_view.xml"/> >> <service-resource type="eca" loader="main" location="servicedef/ >> secas.xml"/> >> - >> + <service-resource type="mca" loader="main" >> location="servicedef/mcas.xml"/> >> + >> <test-suite loader="main" location="testdef/PartyTests.xml"/> >> >> <webapp name="party" >> >> Added: ofbiz/trunk/applications/party/servicedef/mcas.xml >> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/mcas.xml?rev=772780&view=auto >> = >> = >> = >> = >> = >> = >> = >> = >> = >> ===================================================================== >> --- ofbiz/trunk/applications/party/servicedef/mcas.xml (added) >> +++ ofbiz/trunk/applications/party/servicedef/mcas.xml Thu May 7 >> 21:29:06 2009 >> @@ -0,0 +1,28 @@ >> +<?xml version="1.0" encoding="UTF-8"?> >> +<!-- >> +Licensed to the Apache Software Foundation (ASF) under one >> +or more contributor license agreements. See the NOTICE file >> +distributed with this work for additional information >> +regarding copyright ownership. The ASF licenses this file >> +to you under the Apache License, Version 2.0 (the >> +"License"); you may not use this file except in compliance >> +with the License. You may obtain a copy of the License at >> + >> +http://www.apache.org/licenses/LICENSE-2.0 >> + >> +Unless required by applicable law or agreed to in writing, >> +software distributed under the License is distributed on an >> +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >> +KIND, either express or implied. See the License for the >> +specific language governing permissions and limitations >> +under the License. >> +--> >> + >> +<service-mca xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >> + xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/service-mca.xsd >> "> >> + >> + <mca mail-rule-name="processBouncedMessage"> >> + <action service="processBouncedMessage" mode="sync"/> >> + </mca> >> + >> +</service-mca> >> >> Modified: ofbiz/trunk/applications/party/servicedef/services.xml >> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/servicedef/services.xml?rev=772780&r1=772779&r2=772780&view=diff >> = >> = >> = >> = >> = >> = >> = >> = >> = >> ===================================================================== >> --- ofbiz/trunk/applications/party/servicedef/services.xml (original) >> +++ ofbiz/trunk/applications/party/servicedef/services.xml Thu May >> 7 21:29:06 2009 >> @@ -93,7 +93,10 @@ >> <service name="updatePerson" engine="java" default-entity- >> name="Person" >> location="org.ofbiz.party.party.PartyServices" >> invoke="updatePerson" auth="true"> >> <description>Update a Person</description> >> - <permission-service service- >> name="partyGroupPermissionCheck" main-action="UPDATE"/> >> + <required-permissions join-type="AND"> >> + <check-permission permission="update:party:${partyId}"/> >> + </required-permissions> >> + <!-- <permission-service service- >> name="partyGroupPermissionCheck" main-action="UPDATE"/> --> >> <auto-attributes mode="IN" include="pk" optional="true"><!-- >> if no partyId specified will use userLogin.partyId --></auto- >> attributes> >> <auto-attributes mode="IN" include="nonpk" optional="true"/> >> <attribute name="preferredCurrencyUomId" type="String" >> mode="IN" optional="true"/> >> @@ -1167,4 +1170,10 @@ >> <attribute name="contactMechId" type="String" mode="IN" >> optional="true"/> >> <attribute name="contactMechId" type="String" mode="OUT" >> optional="false"/> >> </service> >> + >> + <!-- bounced message processing --> >> + <service name="processBouncedMessage" engine="java" >> + >> location="org.ofbiz.party.communication.CommunicationEventServices" >> invoke="processBouncedMessage"> >> + <implements service="mailProcessInterface"/> >> + </service> >> </services> >> >> Modified: ofbiz/trunk/applications/party/src/org/ofbiz/party/ >> communication/CommunicationEventServices.java >> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/src/org/ofbiz/party/communication/CommunicationEventServices.java?rev=772780&r1=772779&r2=772780&view=diff >> = >> = >> = >> = >> = >> = >> = >> = >> = >> ===================================================================== >> --- ofbiz/trunk/applications/party/src/org/ofbiz/party/ >> communication/CommunicationEventServices.java (original) >> +++ ofbiz/trunk/applications/party/src/org/ofbiz/party/ >> communication/CommunicationEventServices.java Thu May 7 21:29:06 >> 2009 >> @@ -31,8 +31,12 @@ >> import java.util.Map; >> import java.util.Set; >> import java.util.TreeSet; >> +import java.util.regex.Matcher; >> +import java.util.regex.Pattern; >> >> import javax.mail.Address; >> +import javax.mail.BodyPart; >> +import javax.mail.Header; >> import javax.mail.MessagingException; >> import javax.mail.Multipart; >> import javax.mail.Part; >> @@ -946,4 +950,115 @@ >> } >> return attachmentCount; >> } >> + >> + /* >> + * Service to process incoming email and look for a bounce >> message. If the email is indeed a bounce message >> + * the CommunicationEvent will be updated with the proper >> COM_BOUNCED status. >> + */ >> + public static Map<String,Object> >> processBouncedMessage(DispatchContext dctx, Map<String, ? extends >> Object> context) { >> + Debug.logInfo("Running process bounced message check...", >> module); >> + MimeMessageWrapper wrapper = (MimeMessageWrapper) >> context.get("messageWrapper"); >> + MimeMessage message = wrapper.getMessage(); >> + >> + LocalDispatcher dispatcher = dctx.getDispatcher(); >> + GenericDelegator delegator = dctx.getDelegator(); >> + >> + try { >> + Object content = message.getContent(); >> + if (content instanceof Multipart) { >> + Multipart mp = (Multipart) content; >> + int parts = mp.getCount(); >> + >> + if (parts >= 3) { // it must have all three parts >> in order to process correctly >> + >> + // get the second part (delivery report) >> + BodyPart part2 = mp.getBodyPart(1); // index 1 >> should be the second part >> + String contentType = part2.getContentType(); >> + if (contentType != null && "message/delivery- >> status".equalsIgnoreCase(contentType)) { >> + Debug.logInfo("Delivery status report part >> found; processing...", module); >> + >> + // message is only available as an input >> stream; read the stream >> + InputStream insPart2 = (InputStream) >> part2.getInputStream(); >> + int part2Size = part2.getSize(); >> + byte[] part2Bytes = new byte[part2Size]; >> + insPart2.read(part2Bytes, 0, part2Size); >> + String part2Text = new String(part2Bytes); >> + >> + // find the "Action" element and obtain >> its value (looking for "failed") >> + Pattern p2 = Pattern.compile("^Action: (.*) >> $", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); >> + Matcher m2 = p2.matcher(part2Text); >> + String action = null; >> + if (m2.find()) { >> + action = m2.group(1); >> + } >> + >> + if (action != null && >> "failed".equalsIgnoreCase(action)) { >> + // message bounced -- get the original >> message >> + BodyPart part3 = mp.getBodyPart(2); // >> index 2 should be the third part >> + >> + // read part 3 message >> + InputStream insPart3 = (InputStream) >> part3.getInputStream(); >> + int part3Size = part3.getSize(); >> + byte[] part3Bytes = new byte[part3Size]; >> + insPart3.read(part3Bytes, 0, part3Size); >> + String part3Text = new >> String(part3Bytes); >> + >> + // find the "Message-Id" element and >> obtain its value (looking for "failed") >> + Pattern p3 = Pattern.compile("^Message- >> Id: (.*)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); >> + Matcher m3 = p3.matcher(part3Text); >> + String messageId = null; >> + if (m3.find()) { >> + messageId = m3.group(1); >> + } >> + >> + // find the matching communication event >> + if (messageId != null) { >> + List<GenericValue> values; >> + try { >> + values = >> delegator.findByAnd("CommunicationEvent", >> UtilMisc.toMap("messageId", messageId)); >> + } catch (GenericEntityException e) { >> + Debug.logError(e, module); >> + return >> ServiceUtil.returnError(e.getMessage()); >> + } >> + if (values != null && >> values.size() > 0) { >> + // there should be only one; >> unique key >> + GenericValue value = >> values.get(0); >> + >> + // update the communication >> event status >> + Map<String,Object> updateCtx = >> FastMap.newInstance(); >> + >> updateCtx.put("communicationEventId", >> value.getString("communicationEventId")); >> + updateCtx.put("statusId", >> "COM_BOUNCED"); >> + updateCtx.put("userLogin", >> context.get("userLogin")); >> + Map<String,Object> result; >> + try { >> + result = >> dispatcher.runSync("updateCommunicationEvent", updateCtx); >> + } catch >> (GenericServiceException e) { >> + Debug.logError(e, module); >> + return >> ServiceUtil.returnError(e.getMessage()); >> + } >> + if >> (ServiceUtil.isError(result)) { >> + return >> ServiceUtil.returnError(ServiceUtil.getErrorMessage(result)); >> + } >> + } else { >> + if (Debug.infoOn()) { >> + Debug.logInfo("Unable to >> find communication event with the matching messageId : " + >> messageId, module); >> + } >> + } >> + } else { >> + Debug.logWarning("No message ID >> attached to part", module); >> + } >> + } >> + } >> + } >> + } >> + } catch (MessagingException e) { >> + Debug.logError(e, module); >> + return ServiceUtil.returnError(e.getMessage()); >> + } catch (IOException e) { >> + Debug.logError(e, module); >> + return ServiceUtil.returnError(e.getMessage()); >> + } >> + >> + return ServiceUtil.returnSuccess(); >> + } >> } >> >> > |
Free forum by Nabble | Edit this page |