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
|