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, j...@apache.org 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();
+    }
}




Reply via email to