james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [4/7] james-project git commit: JAMES-1717 Mailet sub-project should allow automatically generated mail detection
Date Fri, 20 May 2016 11:53:26 GMT
JAMES-1717 Mailet sub-project should allow automatically generated mail detection


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/661c15ee
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/661c15ee
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/661c15ee

Branch: refs/heads/master
Commit: 661c15ee017dd42a0fbb9339b53ceb50fc25a780
Parents: be08b5a
Author: Benoit Tellier <btellier@linagora.com>
Authored: Thu May 19 18:05:34 2016 +0700
Committer: Benoit Tellier <btellier@linagora.com>
Committed: Fri May 20 18:52:07 2016 +0700

----------------------------------------------------------------------
 mailet/base/pom.xml                             |  10 +
 .../base/AutomaticallySentMailDetector.java     |  35 +++
 .../base/AutomaticallySentMailDetectorImpl.java | 124 +++++++++
 .../AutomaticallySentMailDetectorImplTest.java  | 250 +++++++++++++++++++
 mailet/pom.xml                                  |  12 +
 5 files changed, 431 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/661c15ee/mailet/base/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/base/pom.xml b/mailet/base/pom.xml
index ca3dd2e..e85a706 100644
--- a/mailet/base/pom.xml
+++ b/mailet/base/pom.xml
@@ -53,6 +53,16 @@
             <artifactId>apache-mailet-api</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>apache-mime4j-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>${assertj-1.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/661c15ee/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetector.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetector.java
b/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetector.java
new file mode 100644
index 0000000..e47c863
--- /dev/null
+++ b/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetector.java
@@ -0,0 +1,35 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.mailet.base;
+
+import javax.mail.MessagingException;
+
+import org.apache.mailet.Mail;
+
+public interface AutomaticallySentMailDetector {
+
+    boolean isAutomaticallySent(Mail mail) throws MessagingException;
+
+    boolean isMailingList(Mail mail) throws MessagingException;
+
+    boolean isAutoSubmitted(Mail mail) throws MessagingException;
+
+    boolean isMdnSentAutomatically(Mail mail) throws MessagingException;
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/661c15ee/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetectorImpl.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetectorImpl.java
b/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetectorImpl.java
new file mode 100644
index 0000000..032556a
--- /dev/null
+++ b/mailet/base/src/main/java/org/apache/mailet/base/AutomaticallySentMailDetectorImpl.java
@@ -0,0 +1,124 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.mailet.base;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import javax.mail.MessagingException;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.parser.AbstractContentHandler;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.MimeConfig;
+import org.apache.mailet.Mail;
+
+public class AutomaticallySentMailDetectorImpl implements AutomaticallySentMailDetector {
+
+    public boolean isAutomaticallySent(Mail mail) throws MessagingException {
+        return isMailingList(mail) ||
+            isAutoSubmitted(mail) ||
+            isMdnSentAutomatically(mail);
+    }
+
+    public boolean isMailingList(Mail mail) throws MessagingException {
+        String localPart = mail.getSender().getLocalPart();
+        return localPart.startsWith("owner-")
+            || localPart.endsWith("-request")
+            || localPart.equalsIgnoreCase("MAILER-DAEMON")
+            || localPart.equalsIgnoreCase("LISTSERV")
+            || localPart.equalsIgnoreCase("majordomo")
+            || mail.getMessage()
+            .getMatchingHeaders(new String[]{"List-Help",
+                "List-Subscribe",
+                "List-Unsubscribe",
+                "List-Owner",
+                "List-Post",
+                "List-Id",
+                "List-Archive"})
+            .hasMoreElements();
+    }
+
+    public boolean isAutoSubmitted(Mail mail) throws MessagingException {
+        String[] headers = mail.getMessage().getHeader("Auto-Submitted");
+        if (headers != null) {
+            for (String header : headers) {
+                if (header.equalsIgnoreCase("auto-replied")) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean isMdnSentAutomatically(Mail mail) throws MessagingException {
+        ResultCollector resultCollector = new ResultCollector(false);
+        MimeConfig config = MimeConfig.custom().setMaxLineLen(-1).setMaxHeaderLen(-1).build();
+        MimeStreamParser parser = new MimeStreamParser(config);
+        parser.setContentHandler(createMdnContentHandler(resultCollector));
+        try {
+            parser.parse(mail.getMessage().getInputStream());
+        } catch (MimeException e) {
+            throw new MessagingException("Can not parse Mime", e);
+        } catch (IOException e) {
+            throw new MessagingException("Can not read content", e);
+        }
+        return resultCollector.getResult();
+    }
+
+    private AbstractContentHandler createMdnContentHandler(final ResultCollector resultCollector)
{
+        return new AbstractContentHandler() {
+            @Override
+            public void body(BodyDescriptor bodyDescriptor, InputStream inputStream) throws
MimeException, IOException {
+                if (bodyDescriptor.getMimeType().equalsIgnoreCase("message/disposition-notification"))
{
+                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+                    String line;
+                    while ((line = reader.readLine()) != null ) {
+                        if (line.startsWith("Disposition:")) {
+                            if (line.contains("MDN-sent-automatically") || line.contains("automatic-action"))
{
+                                resultCollector.setResult(true);
+                            }
+                        }
+                    }
+                }
+            }
+        };
+    }
+
+    private static class ResultCollector {
+        private boolean result;
+
+        public ResultCollector(boolean result) {
+            this.result = result;
+        }
+
+        public boolean getResult() {
+            return result;
+        }
+
+        public void setResult(boolean result) {
+            this.result = result;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/661c15ee/mailet/base/src/test/java/org/apache/mailet/base/AutomaticallySentMailDetectorImplTest.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/AutomaticallySentMailDetectorImplTest.java
b/mailet/base/src/test/java/org/apache/mailet/base/AutomaticallySentMailDetectorImplTest.java
new file mode 100644
index 0000000..9581ac9
--- /dev/null
+++ b/mailet/base/src/test/java/org/apache/mailet/base/AutomaticallySentMailDetectorImplTest.java
@@ -0,0 +1,250 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.mailet.base;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Properties;
+
+import javax.activation.DataHandler;
+import javax.mail.Session;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.test.FakeMail;
+import org.junit.Test;
+
+public class AutomaticallySentMailDetectorImplTest {
+
+    @Test
+    public void ownerIsAMailingListPrefix() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("owner-list@any.com"));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void requestIsAMailingListPrefix() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("list-request@any.com"));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void mailerDaemonIsReserved() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("MAILER-DAEMON@any.com"));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listservIsReserved() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("LISTSERV@any.com"));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void majordomoIsReserved() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("majordomo@any.com"));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listIdShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Id", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listHelpShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Help", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listSubscribeShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Subscribe", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listUnsubscribeShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Unsubscribe", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listPostShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Post", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listOwnerShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Owner", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void listArchiveShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("List-Archive", "any");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void normalMailShouldNotBeIdentifiedAsMailingList() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        fakeMail.setMessage(new MimeMessage(Session.getDefaultInstance(new Properties())));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMailingList(fakeMail)).isFalse();
+    }
+
+    @Test
+    public void isAutoSubmittedShouldNotMatchNonAutoSubmittedMails() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setMessage(new MimeMessage(Session.getDefaultInstance(new Properties())));
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isAutoSubmitted(fakeMail)).isFalse();
+    }
+
+    @Test
+    public void isAutoSubmittedShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.setHeader("Auto-Submitted", "auto-replied");
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isAutoSubmitted(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void isMdnSentAutomaticallyShouldBeDetected() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        MimeMultipart multipart = new MimeMultipart();
+        MimeBodyPart scriptPart = new MimeBodyPart();
+        scriptPart.setDataHandler(
+            new DataHandler(
+                new ByteArrayDataSource(
+                    "Disposition: MDN-sent-automatically",
+                    "message/disposition-notification;")
+            ));
+        scriptPart.setHeader("Content-Type", "message/disposition-notification");
+        multipart.addBodyPart(scriptPart);
+        message.setContent(multipart);
+
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMdnSentAutomatically(fakeMail)).isTrue();
+    }
+
+    @Test
+    public void isMdnSentAutomaticallyShouldNotFilterManuallySentMdn() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        MimeMultipart multipart = new MimeMultipart();
+        MimeBodyPart scriptPart = new MimeBodyPart();
+        scriptPart.setDataHandler(
+            new DataHandler(
+                new ByteArrayDataSource(
+                    "Disposition: MDN-sent-manually",
+                    "message/disposition-notification; charset=UTF-8")
+            ));
+        scriptPart.setHeader("Content-Type", "message/disposition-notification");
+        multipart.addBodyPart(scriptPart);
+        message.setContent(multipart);
+
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMdnSentAutomatically(fakeMail)).isFalse();
+    }
+
+    @Test
+    public void isMdnSentAutomaticallyShouldManageItsMimeType() throws Exception {
+        FakeMail fakeMail = new FakeMail();
+        fakeMail.setSender(new MailAddress("any@any.com"));
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        MimeMultipart multipart = new MimeMultipart();
+        MimeBodyPart scriptPart = new MimeBodyPart();
+        scriptPart.setDataHandler(
+            new DataHandler(
+                new ByteArrayDataSource(
+                    "Disposition: MDN-sent-automatically",
+                    "text/plain")
+            ));
+        scriptPart.setHeader("Content-Type", "text/plain");
+        multipart.addBodyPart(scriptPart);
+        message.setContent(multipart);
+
+        fakeMail.setMessage(message);
+
+        assertThat(new AutomaticallySentMailDetectorImpl().isMdnSentAutomatically(fakeMail)).isFalse();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/661c15ee/mailet/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/pom.xml b/mailet/pom.xml
index 8cec493..f4ac702 100644
--- a/mailet/pom.xml
+++ b/mailet/pom.xml
@@ -54,6 +54,7 @@
         <maven-reporting-impl.version>2.2</maven-reporting-impl.version>
         <maven-reporting-api.version>3.0</maven-reporting-api.version>
         <qdox.version>1.12.1</qdox.version>
+        <assertj-1.version>1.7.1</assertj-1.version>
     </properties>
 
 
@@ -79,6 +80,11 @@
                 <version>${project.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.james</groupId>
+                <artifactId>apache-mime4j-core</artifactId>
+                <version>0.8.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
                 <groupId>javax.mail</groupId>
                 <artifactId>mail</artifactId>
                 <version>${javax.version}</version>
@@ -129,6 +135,12 @@
                 <version>${httpclient-osgi.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.assertj</groupId>
+                <artifactId>assertj-core</artifactId>
+                <version>${assertj-1.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
                 <groupId>com.thoughtworks.qdox</groupId>
                 <artifactId>qdox</artifactId>
                 <version>${qdox.version}</version>


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Mime
View raw message