You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/04/03 11:10:01 UTC

[02/15] james-project git commit: JAMES-1980 Improves for UseHeaderRecipients

JAMES-1980 Improves for UseHeaderRecipients


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

Branch: refs/heads/master
Commit: 604a9dae7c12bb9eb55ea7b7093deaa55b95558e
Parents: 398663e
Author: Benoit Tellier <bt...@linagora.com>
Authored: Wed Dec 28 09:31:54 2016 +0700
Committer: benwa <bt...@linagora.com>
Committed: Mon Apr 3 18:09:28 2017 +0700

----------------------------------------------------------------------
 .../mailet/base/test/FakeMailContext.java       |   5 +
 mailet/standard/pom.xml                         |   5 +
 .../transport/mailets/UseHeaderRecipients.java  | 131 +++++++++----
 .../mailets/UseHeaderRecipientsTest.java        | 184 +++++++++++++++++++
 4 files changed, 292 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/604a9dae/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
----------------------------------------------------------------------
diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
index 4617a94..1b22e44 100644
--- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
+++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMailContext.java
@@ -122,6 +122,11 @@ public class FakeMailContext implements MailetContext {
                 return this;
             }
 
+            public Builder recipients(MailAddress... recipients) {
+                this.recipients = Optional.<Collection<MailAddress>>of(ImmutableList.copyOf(recipients));
+                return this;
+            }
+
             public Builder recipient(MailAddress recipient) {
                 Preconditions.checkNotNull(recipient);
                 return recipients(ImmutableList.of(recipient));

http://git-wip-us.apache.org/repos/asf/james-project/blob/604a9dae/mailet/standard/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/standard/pom.xml b/mailet/standard/pom.xml
index 04ba9e5..45048ac 100644
--- a/mailet/standard/pom.xml
+++ b/mailet/standard/pom.xml
@@ -50,6 +50,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.james</groupId>
+            <artifactId>apache-mime4j-dom</artifactId>
+            <version>${mime4j.version}</version>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/604a9dae/mailet/standard/src/main/java/org/apache/james/transport/mailets/UseHeaderRecipients.java
----------------------------------------------------------------------
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/UseHeaderRecipients.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/UseHeaderRecipients.java
index 603a617..b802d5d 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/UseHeaderRecipients.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/UseHeaderRecipients.java
@@ -20,16 +20,29 @@
 
 package org.apache.james.transport.mailets;
 
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.field.address.LenientAddressParser;
+import org.apache.james.mime4j.util.MimeUtil;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
 import org.apache.mailet.base.GenericMailet;
 
-import javax.mail.MessagingException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import java.util.Collection;
-import java.util.StringTokenizer;
-import java.util.Vector;
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
 
 /**
  * <p>Mailet designed to process the recipients from the mail headers rather
@@ -55,6 +68,17 @@ import java.util.Vector;
  */
 public class UseHeaderRecipients extends GenericMailet {
 
+    public static final Function<Mailbox, MailAddress> TO_MAIL_ADDRESS = new Function<Mailbox, MailAddress>() {
+        @Override
+        public MailAddress apply(Mailbox input) {
+            try {
+                return new MailAddress(input.getAddress());
+            } catch (AddressException e) {
+                throw Throwables.propagate(e);
+            }
+        }
+    };
+
     /**
      * Controls certain log messages
      */
@@ -79,20 +103,10 @@ public class UseHeaderRecipients extends GenericMailet {
     public void service(Mail mail) throws MessagingException {
         MimeMessage message = mail.getMessage();
 
-        // Utilise features of Set Collections such that they automatically
-        // ensure that no two entries are equal using the equality method
-        // of the element objects.  MailAddress objects test equality based
-        // on equivalent but not necessarily visually identical addresses.
-        Collection<MailAddress> recipients = mail.getRecipients();
-        // Wipe all the exist recipients
-        recipients.clear();
-        recipients.addAll(getHeaderMailAddresses(message, "Mail-For"));
-        if (recipients.isEmpty()) {
-            recipients.addAll(getHeaderMailAddresses(message, "To"));
-            recipients.addAll(getHeaderMailAddresses(message, "Cc"));
-        }
+        mail.setRecipients(headersAddresses(message));
+
         if (isDebug) {
-            log("All recipients = " + recipients.toString());
+            log("All recipients = " + mail.getRecipients());
             log("Reprocessing mail using recipients in message headers");
         }
 
@@ -101,6 +115,18 @@ public class UseHeaderRecipients extends GenericMailet {
         mail.setState(Mail.GHOST);
     }
 
+    public Collection<MailAddress> headersAddresses(MimeMessage mimeMessage) throws MessagingException {
+        Collection<MailAddress> mailForHeaderAddresses = getHeaderMailAddresses(mimeMessage, "Mail-For");
+        if (!mailForHeaderAddresses.isEmpty()) {
+            return mailForHeaderAddresses;
+        }
+        return ImmutableList.<MailAddress>builder()
+            .addAll(getHeaderMailAddresses(mimeMessage, "To"))
+            .addAll(getHeaderMailAddresses(mimeMessage, "Cc"))
+            .addAll(getHeaderMailAddresses(mimeMessage, "Bcc"))
+            .build();
+    }
+
 
     /**
      * Return a string describing this mailet.
@@ -120,28 +146,67 @@ public class UseHeaderRecipients extends GenericMailet {
      * @return the collection of MailAddress objects.
      */
     private Collection<MailAddress> getHeaderMailAddresses(MimeMessage message, String name) throws MessagingException {
-
         if (isDebug) {
             log("Checking " + name + " headers");
         }
-        Collection<MailAddress> addresses = new Vector<MailAddress>();
         String[] headers = message.getHeader(name);
-        String addressString;
-        InternetAddress iAddress;
+        ImmutableList.Builder<MailAddress> addresses = ImmutableList.builder();
+
         if (headers != null) {
             for (String header : headers) {
-                StringTokenizer st = new StringTokenizer(header, ",", false);
-                while (st.hasMoreTokens()) {
-                    addressString = st.nextToken();
-                    iAddress = new InternetAddress(addressString);
-                    if (isDebug) {
-                        log("Address = " + iAddress.toString());
-                    }
-                    addresses.add(new MailAddress(iAddress));
-                }
+               addresses.addAll(getMailAddressesFromHeaderLine(header));
             }
         }
-        return addresses;
+        return addresses.build();
+    }
+
+    private ImmutableList<MailAddress> getMailAddressesFromHeaderLine(String header) throws MessagingException {
+        String unfoldedDecodedString = sanitizeHeaderString(header);
+        Iterable<String> headerParts = Splitter.on(",").split(unfoldedDecodedString);
+        return getMailAddressesFromHeadersParts(headerParts);
+    }
+
+    private ImmutableList<MailAddress> getMailAddressesFromHeadersParts(Iterable<String> headerParts) throws AddressException {
+        ImmutableList.Builder<MailAddress> result = ImmutableList.builder();
+        for (String headerPart : headerParts) {
+            if (isDebug) {
+                log("Address = " + headerPart);
+            }
+            result.addAll(readMailAddresses(headerPart));
+        }
+        return result.build();
+    }
+
+    private Collection<MailAddress> readMailAddresses(String headerPart) throws AddressException {
+        AddressList addressList = LenientAddressParser.DEFAULT
+            .parseAddressList(MimeUtil.unfold(headerPart));
+
+        ImmutableList.Builder<Mailbox> mailboxList = ImmutableList.builder();
+
+        for (Address address: addressList) {
+            mailboxList.addAll(convertAddressToMailboxCollection(address));
+        }
+
+        return FluentIterable.from(mailboxList.build())
+            .transform(TO_MAIL_ADDRESS)
+            .toList();
+    }
+
+    private Collection<Mailbox> convertAddressToMailboxCollection(Address address) {
+        if (address instanceof Mailbox) {
+            return ImmutableList.of((Mailbox) address);
+        } else if (address instanceof Group) {
+            return ImmutableList.copyOf(((Group) address).getMailboxes());
+        }
+        return ImmutableList.of();
+    }
+
+    private String sanitizeHeaderString(String header) throws MessagingException {
+        try {
+            return MimeUtility.unfold(MimeUtility.decodeText(header));
+        } catch (UnsupportedEncodingException e) {
+            throw new MessagingException("Can not decode header", e);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/604a9dae/mailet/standard/src/test/java/org/apache/james/transport/mailets/UseHeaderRecipientsTest.java
----------------------------------------------------------------------
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/UseHeaderRecipientsTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/UseHeaderRecipientsTest.java
new file mode 100644
index 0000000..95d220a
--- /dev/null
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/UseHeaderRecipientsTest.java
@@ -0,0 +1,184 @@
+/****************************************************************
+ * 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.james.transport.mailets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailContext;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.apache.mailet.base.test.MimeMessageBuilder;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class UseHeaderRecipientsTest {
+
+    public static final String RECIPIENT1 = "abc1@apache1.org";
+    public static final String RECIPIENT2 = "abc2@apache2.org";
+    public static final String RECIPIENT3 = "abc3@apache3.org";
+    private UseHeaderRecipients testee;
+    private FakeMailContext mailetContext;
+    private MailAddress mailAddress1;
+    private MailAddress mailAddress2;
+    private MailAddress mailAddress3;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() throws Exception {
+        testee = new UseHeaderRecipients();
+        mailetContext = FakeMailContext.defaultContext();
+        testee.init(FakeMailetConfig.builder().mailetContext(mailetContext).build());
+
+        mailAddress1 = new MailAddress(RECIPIENT1);
+        mailAddress2 = new MailAddress(RECIPIENT2);
+        mailAddress3 = new MailAddress(RECIPIENT3);
+    }
+
+    @Test
+    public void serviceShouldSetMimeMessageRecipients() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient(RECIPIENT1, RECIPIENT2)
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getRecipients())
+            .containsOnly(mailAddress1, mailAddress2);
+    }
+
+    @Test
+    public void serviceShouldSetToCcAndBccSpecifiedInTheMimeMessage() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient(RECIPIENT1)
+                .addCcRecipient(RECIPIENT2)
+                .addBccRecipient(RECIPIENT3)
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getRecipients())
+            .containsOnly(mailAddress1, mailAddress2, mailAddress3);
+    }
+
+    @Test
+    public void serviceShouldSetEmptyRecipientWhenNoRecipientsInTheMimeMessage() throws Exception {
+
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getRecipients())
+            .isEmpty();
+    }
+
+    @Test
+    public void serviceShouldGhostEmail() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getState())
+            .isEqualTo(Mail.GHOST);
+    }
+
+    @Test
+    public void serviceShouldResendTheEmail() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(MailAddressFixture.ANY_AT_JAMES)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient(RECIPIENT1)
+                .addCcRecipient(RECIPIENT2)
+                .addBccRecipient(RECIPIENT3)
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(mailetContext.getSentMails())
+            .containsOnly(FakeMailContext.sentMailBuilder()
+                .recipients(mailAddress1, mailAddress2, mailAddress3)
+                .build());
+    }
+
+    @Test
+    public void serviceShouldThrowOnInvalidMailAddress() throws Exception {
+        expectedException.expect(RuntimeException.class);
+
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients(mailAddress1)
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient("invalid")
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+    }
+
+    @Test
+    public void serviceShouldSupportAddressList() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients()
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient(RECIPIENT1, RECIPIENT2)
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getRecipients())
+            .containsOnly(mailAddress1, mailAddress2);
+    }
+
+    @Test
+    public void serviceShouldSupportMailboxes() throws Exception {
+        FakeMail fakeMail = FakeMail.builder()
+            .recipients()
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addToRecipient("APACHE" + "<" + UseHeaderRecipientsTest.RECIPIENT1 + ">")
+                .build())
+            .build();
+
+        testee.service(fakeMail);
+
+        assertThat(fakeMail.getRecipients())
+            .containsOnly(mailAddress1);
+    }
+}


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