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 2020/06/19 04:12:04 UTC

[james-project] branch master updated (97c391d -> 60d08c5)

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from 97c391d  Mailed Javadoc contribution from github @amichair
     new 16341d1  JAMES-3214 Add missing test scope
     new 92f6550  JAMES-3184 Limit concurrency while generating ReIndexingEntry
     new 1bee82c  JAMES-3184 Remove an unused constant
     new 97e4ed5  JAMES-3184 Remove an unused constant
     new 2bc6fb0  JAMES-3184 Limit concurrency while generating ReIndexingEntry for MessageFastView
     new c95991c  [Refactoring] factorize setup in BounceIntegrationTest
     new 7a1658f  [Refactoring] rename BOUNCE_RECEIVER to sender, and give unique passwords
     new 524e20a  JAMES-3210 add integration test demonstrating that the dsn bounce response is send to the sender
     new f38dac2  JAMES-3210 make the dsn text message nicer by separating the recipients
     new ae23e99  JAMES-3223 bump guava version to fix vulnerability
     new 9d132e8  JAMES-3223 bump common-beanutils version to fix vulnerability
     new 60d08c5  JAMES-3213 Source ReplyTo in ICALToJsonAttribute

The 12 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 mailbox/backup/pom.xml                             |   5 +
 .../task/SolveMessageInconsistenciesService.java   |   1 -
 .../deleted-messages-vault-cassandra/pom.xml       |   5 +
 mailbox/plugin/deleted-messages-vault/pom.xml      |   5 +
 .../mailbox/tools/indexer/ReIndexerPerformer.java  |   6 +-
 .../transport/mailets/ICALToJsonAttribute.java     |  88 +++++++--
 .../model/{ICAL.java => ICALAttributeDTO.java}     | 103 ++++++-----
 .../transport/mailets/ICALToJsonAttributeTest.java | 188 ++++++++++++++-----
 .../{ICALTest.java => ICALAttributeDTOTest.java}   |  83 +++------
 mpt/impl/imap-mailbox/cyrus/pom.xml                |   5 -
 pom.xml                                            |   2 +-
 .../james/mailets/BounceIntegrationTest.java       | 200 ++++++++++-----------
 .../apache/james/transport/mailets/DSNBounce.java  |   8 +-
 .../pom.xml                                        |   5 +
 .../jmap/MessageFastViewProjectionCorrector.java   |  10 +-
 .../webadmin-mailbox-deleted-message-vault/pom.xml |   5 +
 16 files changed, 424 insertions(+), 295 deletions(-)
 rename mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/{ICAL.java => ICALAttributeDTO.java} (63%)
 rename mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/{ICALTest.java => ICALAttributeDTOTest.java} (74%)


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


[james-project] 02/12: JAMES-3184 Limit concurrency while generating ReIndexingEntry

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 92f6550997af2ea634110eb0000f786f6bd2b46a
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jun 17 13:46:37 2020 +0700

    JAMES-3184 Limit concurrency while generating ReIndexingEntry
    
    Current code was starting listing 256 mailboxes concurently, then was rate limiting the resulting messages.
    
    This results in a too big number of Cassandra queries eventually overflowing the driver.
    
    The proposed short term solution is to enforce a single mailbox to be reindexed at once.
    
    A long term solution would be to add a `concurrentMailboxes` parameter with the runningOptions.
---
 .../java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java   | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java b/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
index 60b47b0..d50b2ee 100644
--- a/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
+++ b/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
@@ -55,6 +55,8 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class ReIndexerPerformer {
+    public static final int MAILBOX_CONCURRENCY = 1;
+
     private static class ReIndexingEntry {
         private final Mailbox mailbox;
         private final MailboxSession mailboxSession;
@@ -147,7 +149,7 @@ public class ReIndexerPerformer {
         LOGGER.info("Starting a full reindex");
 
         Flux<Either<Failure, ReIndexingEntry>> entriesToIndex = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession).list()
-            .flatMap(mailbox -> reIndexingEntriesForMailbox(mailbox, mailboxSession));
+            .flatMap(mailbox -> reIndexingEntriesForMailbox(mailbox, mailboxSession), MAILBOX_CONCURRENCY);
 
         return reIndexMessages(entriesToIndex, runningOptions, reprocessingContext)
             .doFinally(any -> LOGGER.info("Full reindex finished"));
@@ -172,7 +174,7 @@ public class ReIndexerPerformer {
 
         try {
             Flux<Either<Failure, ReIndexingEntry>> entriesToIndex = mailboxMapper.findMailboxWithPathLike(mailboxQuery.asUserBound())
-                .flatMap(mailbox -> reIndexingEntriesForMailbox(mailbox, mailboxSession));
+                .flatMap(mailbox -> reIndexingEntriesForMailbox(mailbox, mailboxSession), MAILBOX_CONCURRENCY);
 
             return reIndexMessages(entriesToIndex, runningOptions, reprocessingContext)
                 .doFinally(any -> LOGGER.info("User {} reindex finished", username.asString()));


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


[james-project] 10/12: JAMES-3223 bump guava version to fix vulnerability

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit ae23e9916951ec614e23180c07acb98c868d8ba9
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Tue Jun 16 12:02:25 2020 +0200

    JAMES-3223 bump guava version to fix vulnerability
---
 mpt/impl/imap-mailbox/cyrus/pom.xml | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/mpt/impl/imap-mailbox/cyrus/pom.xml b/mpt/impl/imap-mailbox/cyrus/pom.xml
index 82a80e2..2ceb816 100644
--- a/mpt/impl/imap-mailbox/cyrus/pom.xml
+++ b/mpt/impl/imap-mailbox/cyrus/pom.xml
@@ -59,10 +59,5 @@
                 </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>20.0</version><!--$NO-MVN-MAN-VER$-->
-        </dependency>
     </dependencies>
 </project>


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


[james-project] 05/12: JAMES-3184 Limit concurrency while generating ReIndexingEntry for MessageFastView

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 2bc6fb04b5df41916c39e889027b42c6b497c88b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jun 17 13:53:45 2020 +0700

    JAMES-3184 Limit concurrency while generating ReIndexingEntry for MessageFastView
    
    Current code was starting listing 256 mailboxes concurently * 256 users, then was rate limiting the resulting messages.
    
    This results in a too big number of Cassandra queries eventually overflowing the driver.
    
    The proposed short term solution is to enforce a single mailbox to be reindexed at once.
    
    A long term solution would be to add a `concurrentMailboxes` & `concurrentUsers` parameters with the runningOptions.
---
 .../webadmin/data/jmap/MessageFastViewProjectionCorrector.java    | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
index 3c883b3..5bfd792 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
@@ -58,6 +58,8 @@ import reactor.core.publisher.Mono;
 public class MessageFastViewProjectionCorrector {
     private static final Logger LOGGER = LoggerFactory.getLogger(MessageFastViewProjectionCorrector.class);
     private static final Duration PERIOD = Duration.ofSeconds(1);
+    public static final int USER_CONCURRENCY = 1;
+    public static final int MAILBOX_CONCURRENCY = 1;
 
     public static class RunningOptions {
         public static RunningOptions withMessageRatePerSecond(int messageRatePerSecond) {
@@ -178,7 +180,7 @@ public class MessageFastViewProjectionCorrector {
             return Iterators.toFlux(usersRepository.list())
                 .map(mailboxManager::createSystemSession)
                 .doOnNext(any -> progress.incrementProcessedUserCount())
-                .flatMap(session -> listUserMailboxMessages(progress, session));
+                .flatMap(session -> listUserMailboxMessages(progress, session), USER_CONCURRENCY);
         } catch (UsersRepositoryException e) {
             return Flux.error(e);
         }
@@ -187,9 +189,9 @@ public class MessageFastViewProjectionCorrector {
     private Flux<ProjectionEntry> listUserMailboxMessages(Progress progress, MailboxSession session) {
         try {
             return listUsersMailboxes(session)
-                .flatMap(mailboxMetadata -> retrieveMailbox(session, mailboxMetadata))
+                .flatMap(mailboxMetadata -> retrieveMailbox(session, mailboxMetadata), MAILBOX_CONCURRENCY)
                 .flatMap(Throwing.function(messageManager -> listAllMailboxMessages(messageManager, session)
-                    .map(message -> new ProjectionEntry(messageManager, message.getUid(), session))));
+                    .map(message -> new ProjectionEntry(messageManager, message.getUid(), session))), MAILBOX_CONCURRENCY);
         } catch (MailboxException e) {
             LOGGER.error("JMAP fastview re-computation aborted for {} as we failed listing user mailboxes", session.getUser(), e);
             progress.incrementFailedUserCount();


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


[james-project] 06/12: [Refactoring] factorize setup in BounceIntegrationTest

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c95991c734cd9aa874cd6ee6fc725de483a591a1
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Jun 11 14:30:25 2020 +0200

    [Refactoring] factorize setup in BounceIntegrationTest
---
 .../james/mailets/BounceIntegrationTest.java       | 129 ++++++---------------
 1 file changed, 34 insertions(+), 95 deletions(-)

diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
index f7abaac..6359364 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
@@ -25,13 +25,15 @@ import static org.apache.james.mailets.configuration.Constants.PASSWORD;
 import static org.apache.james.mailets.configuration.Constants.RECIPIENT;
 import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute;
 
+import java.util.Arrays;
+
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.MemoryJamesServerMain;
 import org.apache.james.mailets.configuration.MailetConfiguration;
 import org.apache.james.mailets.configuration.MailetContainer;
 import org.apache.james.mailets.configuration.ProcessorConfiguration;
 import org.apache.james.modules.protocols.ImapGuiceProbe;
 import org.apache.james.modules.protocols.SmtpGuiceProbe;
-import org.apache.james.probe.DataProbe;
 import org.apache.james.transport.mailets.Bounce;
 import org.apache.james.transport.mailets.DSNBounce;
 import org.apache.james.transport.mailets.Forward;
@@ -45,6 +47,7 @@ import org.apache.james.transport.matchers.RecipientIs;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.TestIMAPClient;
 import org.apache.james.utils.SMTPMessageSender;
+import org.apache.mailet.Mailet;
 import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
@@ -62,7 +65,6 @@ public class BounceIntegrationTest {
     public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN);
 
     private TemporaryJamesServer jamesServer;
-    private DataProbe dataProbe;
 
     @After
     public void tearDown() {
@@ -71,19 +73,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void dsnBounceMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
-                .matcher(All.class)
-                .mailet(DSNBounce.class)
-                .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+        setup(DSNBounce.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
@@ -94,21 +84,32 @@ public class BounceIntegrationTest {
             .awaitMessage(awaitAtMostOneMinute);
     }
 
-    @Test
-    public void bounceMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
+    private void setup(Class<? extends Mailet> mailet, Pair<String, String>... additionalProperties) throws Exception {
+        MailetConfiguration.Builder mailetConfiguration = MailetConfiguration.builder()
                 .matcher(All.class)
-                .mailet(Bounce.class)
-                .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
+                .mailet(mailet)
+                .addProperty("passThrough", "false");
+
+        Arrays.stream(additionalProperties)
+                    .forEach(property -> mailetConfiguration.addProperty(property.getKey(), property.getValue()));
+
+        jamesServer = TemporaryJamesServer.builder()
+                .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
+                .withMailetContainer(
+                        generateMailetContainerConfiguration(mailetConfiguration))
+                .build(temporaryFolder.newFolder());
+
+        jamesServer.getProbe(DataProbeImpl.class)
+                .fluent()
+                .addDomain(DEFAULT_DOMAIN)
+                .addUser(RECIPIENT, PASSWORD)
+                .addUser(BOUNCE_RECEIVER, PASSWORD)
+                .addUser(POSTMASTER, PASSWORD);
+    }
 
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+    @Test
+    public void bounceMailetShouldDeliverBounce() throws Exception {
+        setup(Bounce.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
@@ -121,19 +122,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void forwardMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(generateMailetContainerConfiguration(MailetConfiguration.builder()
-                .matcher(All.class)
-                .mailet(Forward.class)
-                .addProperty("forwardTo", BOUNCE_RECEIVER)
-                .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+        setup(Forward.class, Pair.of("forwardTo", BOUNCE_RECEIVER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
@@ -146,20 +135,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void redirectMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
-                    .matcher(All.class)
-                    .mailet(Redirect.class)
-                    .addProperty("recipients", BOUNCE_RECEIVER)
-                    .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+        setup(Redirect.class, Pair.of("recipients", BOUNCE_RECEIVER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
@@ -172,20 +148,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void resendMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
-                    .matcher(All.class)
-                    .mailet(Resend.class)
-                    .addProperty("recipients", BOUNCE_RECEIVER)
-                    .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+        setup(Resend.class, Pair.of("recipients", BOUNCE_RECEIVER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
@@ -198,19 +161,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void notifySenderMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
-                    .matcher(All.class)
-                    .mailet(NotifySender.class)
-                    .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(BOUNCE_RECEIVER, PASSWORD);
+        setup(NotifySender.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
@@ -223,19 +174,7 @@ public class BounceIntegrationTest {
 
     @Test
     public void notifyPostmasterMailetShouldDeliverBounce() throws Exception {
-        jamesServer = TemporaryJamesServer.builder()
-            .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
-            .withMailetContainer(
-                generateMailetContainerConfiguration(MailetConfiguration.builder()
-                    .matcher(All.class)
-                    .mailet(NotifyPostmaster.class)
-                    .addProperty("passThrough", "false")))
-            .build(temporaryFolder.newFolder());
-
-        dataProbe = jamesServer.getProbe(DataProbeImpl.class);
-        dataProbe.addDomain(DEFAULT_DOMAIN);
-        dataProbe.addUser(RECIPIENT, PASSWORD);
-        dataProbe.addUser(POSTMASTER, PASSWORD);
+        setup(NotifyPostmaster.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);


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


[james-project] 01/12: JAMES-3214 Add missing test scope

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 16341d1ce041bc37f63172c0e2059a1204ad281b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jun 15 13:34:19 2020 +0700

    JAMES-3214 Add missing test scope
---
 mailbox/backup/pom.xml                                               | 5 +++++
 mailbox/plugin/deleted-messages-vault-cassandra/pom.xml              | 5 +++++
 mailbox/plugin/deleted-messages-vault/pom.xml                        | 5 +++++
 .../distributed-jmap-rfc-8621-integration-tests/pom.xml              | 5 +++++
 .../webadmin/webadmin-mailbox-deleted-message-vault/pom.xml          | 5 +++++
 5 files changed, 25 insertions(+)

diff --git a/mailbox/backup/pom.xml b/mailbox/backup/pom.xml
index 6d6c3f4..c530b9f 100644
--- a/mailbox/backup/pom.xml
+++ b/mailbox/backup/pom.xml
@@ -57,6 +57,11 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
diff --git a/mailbox/plugin/deleted-messages-vault-cassandra/pom.xml b/mailbox/plugin/deleted-messages-vault-cassandra/pom.xml
index ab90748..801def9 100644
--- a/mailbox/plugin/deleted-messages-vault-cassandra/pom.xml
+++ b/mailbox/plugin/deleted-messages-vault-cassandra/pom.xml
@@ -62,6 +62,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/mailbox/plugin/deleted-messages-vault/pom.xml b/mailbox/plugin/deleted-messages-vault/pom.xml
index 4a438a0..26db1a7 100644
--- a/mailbox/plugin/deleted-messages-vault/pom.xml
+++ b/mailbox/plugin/deleted-messages-vault/pom.xml
@@ -95,6 +95,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>metrics-tests</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/pom.xml b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/pom.xml
index 702c1bb..5906025 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/pom.xml
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/pom.xml
@@ -107,6 +107,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>jmap-rfc-8621-integration-tests-common</artifactId>
             <scope>test</scope>
         </dependency>
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/pom.xml b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/pom.xml
index 3d3a9d4..c43b410 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/pom.xml
@@ -104,6 +104,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-webadmin-core</artifactId>
         </dependency>
         <dependency>


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


[james-project] 11/12: JAMES-3223 bump common-beanutils version to fix vulnerability

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 9d132e8280b36e1d5d7c3f6e01452a71727dd10d
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Tue Jun 16 12:02:51 2020 +0200

    JAMES-3223 bump common-beanutils version to fix vulnerability
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 4c64989..f2de229 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2093,7 +2093,7 @@
             <dependency>
                 <groupId>commons-beanutils</groupId>
                 <artifactId>commons-beanutils</artifactId>
-                <version>1.9.3</version>
+                <version>1.9.4</version>
             </dependency>
             <dependency>
                 <groupId>commons-cli</groupId>


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


[james-project] 09/12: JAMES-3210 make the dsn text message nicer by separating the recipients

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit f38dac2f7a64e7b66926980c1641c70d2d32cb25
Author: Rémi KOWALSKI <rk...@linagora.com>
AuthorDate: Tue Jun 16 16:20:32 2020 +0200

    JAMES-3210 make the dsn text message nicer by separating the recipients
---
 .../main/java/org/apache/james/transport/mailets/DSNBounce.java   | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
index 6354d32..11b4a06 100755
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -356,9 +357,10 @@ public class DSNBounce extends GenericMailet implements RedirectNotify {
 
         builder.append(bounceMessage()).append(LINE_BREAK);
         builder.append("Failed recipient(s):").append(LINE_BREAK);
-        for (MailAddress mailAddress : originalMail.getRecipients()) {
-            builder.append(mailAddress);
-        }
+        builder.append(originalMail.getRecipients()
+                .stream()
+                .map(MailAddress::asString)
+                .collect(Collectors.joining(", ")));
         builder.append(LINE_BREAK).append(LINE_BREAK);
         builder.append("Error message:").append(LINE_BREAK);
         builder.append(AttributeUtils.getValueAndCastFromMail(originalMail, DELIVERY_ERROR, String.class).orElse("")).append(LINE_BREAK);


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


[james-project] 08/12: JAMES-3210 add integration test demonstrating that the dsn bounce response is send to the sender

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 524e20a28c8904bd62fc82ceec46412897a43f7d
Author: Rémi KOWALSKI <rk...@linagora.com>
AuthorDate: Tue Jun 16 15:34:36 2020 +0200

    JAMES-3210 add integration test demonstrating that the dsn bounce response is send to the sender
---
 .../james/mailets/BounceIntegrationTest.java       | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
index a3aea2a..dce1fc6 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
@@ -24,6 +24,9 @@ import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
 import static org.apache.james.mailets.configuration.Constants.PASSWORD;
 import static org.apache.james.mailets.configuration.Constants.RECIPIENT;
 import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.internet.MimeMessage;
 
 import java.util.Arrays;
 
@@ -44,6 +47,7 @@ import org.apache.james.transport.mailets.Redirect;
 import org.apache.james.transport.mailets.Resend;
 import org.apache.james.transport.matchers.All;
 import org.apache.james.transport.matchers.RecipientIs;
+import org.apache.james.util.MimeMessageUtil;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.TestIMAPClient;
 import org.apache.james.utils.SMTPMessageSender;
@@ -58,6 +62,8 @@ public class BounceIntegrationTest {
     public static final String POSTMASTER_PASSWORD = "postmasterSecret";
     public static final String SENDER = "bounce.receiver@" + DEFAULT_DOMAIN;
     public static final String SENDER_PASSWORD = "senderSecret";
+    public static final String OTHER = "other@" + DEFAULT_DOMAIN;
+    public static final String OTHER_PASSWORD = "otherSecret";
 
     @Rule
     public TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -86,6 +92,46 @@ public class BounceIntegrationTest {
             .awaitMessage(awaitAtMostOneMinute);
     }
 
+    @Test
+    public void dsnBounceMailetShouldDeliverBounceToTheMailFromAddress() throws Exception {
+        setup(DSNBounce.class);
+
+        messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessageWithHeaders(SENDER, RECIPIENT,
+                "From: " + OTHER + "\r\n" +
+                    "To: " + RECIPIENT + "\r\n" +
+                    "Subject: " + "Hello\r\n" +
+                    "\r\n" +
+                    "Please bounce me to the return address\r\n"
+            );
+
+        testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(SENDER, SENDER_PASSWORD)
+            .select(TestIMAPClient.INBOX)
+            .awaitMessage(awaitAtMostOneMinute);
+    }
+
+    @Test
+    public void dsnBounceMailetBouncedMailShouldBeAdressedToTheSenderInEnvelopeAndHeader() throws Exception {
+        setup(DSNBounce.class);
+
+        messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .sendMessageWithHeaders(SENDER, RECIPIENT,
+                "From: " + OTHER + "\r\n" +
+                    "To: " + RECIPIENT + "\r\n" +
+                    "Subject: " + "Hello\r\n" +
+                    "\r\n" +
+                    "Please bounce me to the return address\r\n"
+            );
+
+        MimeMessage mimeMessage = MimeMessageUtil.mimeMessageFromString(testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(SENDER, SENDER_PASSWORD)
+            .select(TestIMAPClient.INBOX)
+            .awaitMessage(awaitAtMostOneMinute)
+            .readFirstMessage());
+        assertThat(mimeMessage.getHeader("To")[0]).isEqualTo(SENDER);
+    }
+
     private void setup(Class<? extends Mailet> mailet, Pair<String, String>... additionalProperties) throws Exception {
         MailetConfiguration.Builder mailetConfiguration = MailetConfiguration.builder()
                 .matcher(All.class)
@@ -106,6 +152,7 @@ public class BounceIntegrationTest {
                 .addDomain(DEFAULT_DOMAIN)
                 .addUser(RECIPIENT, PASSWORD)
                 .addUser(SENDER, SENDER_PASSWORD)
+                .addUser(OTHER, OTHER_PASSWORD)
                 .addUser(POSTMASTER, POSTMASTER_PASSWORD);
     }
 


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


[james-project] 03/12: JAMES-3184 Remove an unused constant

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 1bee82c602adac1f251ca421735275bdfd303ae7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jun 17 13:47:25 2020 +0700

    JAMES-3184 Remove an unused constant
---
 .../mailbox/cassandra/mail/task/SolveMessageInconsistenciesService.java  | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesService.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesService.java
index 89a90ea..7d492fa 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesService.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/SolveMessageInconsistenciesService.java
@@ -404,7 +404,6 @@ public class SolveMessageInconsistenciesService {
     }
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SolveMessageInconsistenciesService.class);
-    private static final Duration DELAY = Duration.ZERO;
     private static final Duration PERIOD = Duration.ofSeconds(1);
 
     private final CassandraMessageIdToImapUidDAO messageIdToImapUidDAO;


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


[james-project] 04/12: JAMES-3184 Remove an unused constant

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 97e4ed52291661ae3ed0065fcef009f0a5253401
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jun 17 13:52:45 2020 +0700

    JAMES-3184 Remove an unused constant
---
 .../james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java    | 2 --
 1 file changed, 2 deletions(-)

diff --git a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
index bd851f7..3c883b3 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
@@ -57,8 +57,6 @@ import reactor.core.publisher.Mono;
 
 public class MessageFastViewProjectionCorrector {
     private static final Logger LOGGER = LoggerFactory.getLogger(MessageFastViewProjectionCorrector.class);
-    
-    private static final Duration DELAY = Duration.ZERO;
     private static final Duration PERIOD = Duration.ofSeconds(1);
 
     public static class RunningOptions {


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


[james-project] 07/12: [Refactoring] rename BOUNCE_RECEIVER to sender, and give unique passwords

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 7a1658fbeccdf55c470da6a80abd940ea2649bb2
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Jun 11 14:36:40 2020 +0200

    [Refactoring] rename BOUNCE_RECEIVER to sender, and give unique passwords
---
 .../james/mailets/BounceIntegrationTest.java       | 38 ++++++++++++----------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
index 6359364..a3aea2a 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/BounceIntegrationTest.java
@@ -55,7 +55,9 @@ import org.junit.rules.TemporaryFolder;
 
 public class BounceIntegrationTest {
     public static final String POSTMASTER = "postmaster@" + DEFAULT_DOMAIN;
-    public static final String BOUNCE_RECEIVER = "bounce.receiver@" + DEFAULT_DOMAIN;
+    public static final String POSTMASTER_PASSWORD = "postmasterSecret";
+    public static final String SENDER = "bounce.receiver@" + DEFAULT_DOMAIN;
+    public static final String SENDER_PASSWORD = "senderSecret";
 
     @Rule
     public TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -76,10 +78,10 @@ public class BounceIntegrationTest {
         setup(DSNBounce.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
-            .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
+            .sendMessage(SENDER, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
@@ -103,8 +105,8 @@ public class BounceIntegrationTest {
                 .fluent()
                 .addDomain(DEFAULT_DOMAIN)
                 .addUser(RECIPIENT, PASSWORD)
-                .addUser(BOUNCE_RECEIVER, PASSWORD)
-                .addUser(POSTMASTER, PASSWORD);
+                .addUser(SENDER, SENDER_PASSWORD)
+                .addUser(POSTMASTER, POSTMASTER_PASSWORD);
     }
 
     @Test
@@ -112,49 +114,49 @@ public class BounceIntegrationTest {
         setup(Bounce.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
-            .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
+            .sendMessage(SENDER, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
 
     @Test
     public void forwardMailetShouldDeliverBounce() throws Exception {
-        setup(Forward.class, Pair.of("forwardTo", BOUNCE_RECEIVER));
+        setup(Forward.class, Pair.of("forwardTo", SENDER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
 
     @Test
     public void redirectMailetShouldDeliverBounce() throws Exception {
-        setup(Redirect.class, Pair.of("recipients", BOUNCE_RECEIVER));
+        setup(Redirect.class, Pair.of("recipients", SENDER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
 
     @Test
     public void resendMailetShouldDeliverBounce() throws Exception {
-        setup(Resend.class, Pair.of("recipients", BOUNCE_RECEIVER));
+        setup(Resend.class, Pair.of("recipients", SENDER));
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
@@ -164,10 +166,10 @@ public class BounceIntegrationTest {
         setup(NotifySender.class);
 
         messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
-            .sendMessage(BOUNCE_RECEIVER, RECIPIENT);
+            .sendMessage(SENDER, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(BOUNCE_RECEIVER, PASSWORD)
+            .login(SENDER, SENDER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
@@ -180,7 +182,7 @@ public class BounceIntegrationTest {
             .sendMessage("any@" + DEFAULT_DOMAIN, RECIPIENT);
 
         testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
-            .login(POSTMASTER, PASSWORD)
+            .login(POSTMASTER, POSTMASTER_PASSWORD)
             .select(TestIMAPClient.INBOX)
             .awaitMessage(awaitAtMostOneMinute);
     }
@@ -193,13 +195,13 @@ public class BounceIntegrationTest {
     }
 
     private ProcessorConfiguration.Builder transport() {
-        // This processor delivers emails to BOUNCE_RECEIVER and POSTMASTER
+        // This processor delivers emails to SENDER and POSTMASTER
         // Other recipients will be bouncing
         return ProcessorConfiguration.transport()
             .addMailet(MailetConfiguration.BCC_STRIPPER)
             .addMailet(MailetConfiguration.builder()
                 .matcher(RecipientIs.class)
-                .matcherCondition(BOUNCE_RECEIVER)
+                .matcherCondition(SENDER)
                 .mailet(LocalDelivery.class))
             .addMailet(MailetConfiguration.builder()
                 .matcher(RecipientIs.class)


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


[james-project] 12/12: JAMES-3213 Source ReplyTo in ICALToJsonAttribute

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 60d08c54a2347b16efe8348acd6ac7e285ee5b25
Author: Gautier DI FOLCO <gd...@linagora.com>
AuthorDate: Thu Jun 11 16:01:34 2020 +0200

    JAMES-3213 Source ReplyTo in ICALToJsonAttribute
---
 .../transport/mailets/ICALToJsonAttribute.java     |  88 ++++++++--
 .../model/{ICAL.java => ICALAttributeDTO.java}     | 103 +++++------
 .../transport/mailets/ICALToJsonAttributeTest.java | 188 ++++++++++++++++-----
 .../{ICALTest.java => ICALAttributeDTOTest.java}   |  83 +++------
 4 files changed, 290 insertions(+), 172 deletions(-)

diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
index d3eafad..ed0ea90 100644
--- a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
@@ -27,12 +27,17 @@ import java.util.stream.Stream;
 
 import javax.mail.Address;
 import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
-import org.apache.james.transport.mailets.model.ICAL;
+import org.apache.james.core.MaybeSender;
+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.transport.mailets.model.ICALAttributeDTO;
 import org.apache.james.util.StreamUtils;
 import org.apache.mailet.Attribute;
 import org.apache.mailet.AttributeName;
@@ -97,12 +102,10 @@ public class ICALToJsonAttribute extends GenericMailet {
     public static final String DEFAULT_SOURCE_ATTRIBUTE_NAME = "icalendar";
     public static final String DEFAULT_RAW_SOURCE_ATTRIBUTE_NAME = "attachments";
     public static final String DEFAULT_DESTINATION_ATTRIBUTE_NAME = "icalendarJson";
-    public static final AttributeName SOURCE = AttributeName.of(SOURCE_ATTRIBUTE_NAME);
-    public static final AttributeName RAW_SOURCE = AttributeName.of(RAW_SOURCE_ATTRIBUTE_NAME);
-    public static final AttributeName DESTINATION = AttributeName.of(DESTINATION_ATTRIBUTE_NAME);
     public static final AttributeName DEFAULT_SOURCE = AttributeName.of(DEFAULT_SOURCE_ATTRIBUTE_NAME);
     public static final AttributeName DEFAULT_RAW_SOURCE = AttributeName.of(DEFAULT_RAW_SOURCE_ATTRIBUTE_NAME);
     public static final AttributeName DEFAULT_DESTINATION = AttributeName.of(DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+    public static final String REPLY_TO_HEADER_NAME = "replyTo";
 
     static {
         ICal4JConfigurator.configure();
@@ -170,27 +173,72 @@ public class ICALToJsonAttribute extends GenericMailet {
     }
 
     private void setAttribute(Mail mail, Map<String, Calendar> calendars, Map<String, byte[]> rawCalendars) throws MessagingException {
-        Optional<String> sender = retrieveSender(mail);
+        Optional<MailAddress> sender = retrieveSender(mail);
         if (!sender.isPresent()) {
             LOGGER.info("Skipping {} because no sender and no from", mail.getName());
             return;
         }
+
+        MailAddress transportSender = sender.get();
+        MailAddress replyTo = fetchReplyTo(mail).orElse(transportSender);
+
         Map<String, byte[]> jsonsInByteForm = calendars.entrySet()
             .stream()
-            .flatMap(calendar -> toJson(calendar, rawCalendars, mail, sender.get()))
+            .flatMap(calendar -> toJson(calendar, rawCalendars, mail, transportSender, replyTo))
             .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue));
         mail.setAttribute(new Attribute(destinationAttributeName, AttributeValue.ofAny(jsonsInByteForm)));
     }
 
-    private Stream<Pair<String, byte[]>> toJson(Map.Entry<String, Calendar> entry, Map<String, byte[]> rawCalendars, Mail mail, String sender) {
+    private Optional<MailAddress> fetchReplyTo(Mail mail) throws MessagingException {
+        return Optional.ofNullable(mail.getMessage())
+            .flatMap(Throwing.<MimeMessage, Optional<String[]>>function(mimeMessage ->
+                    Optional.ofNullable(mimeMessage.getHeader(REPLY_TO_HEADER_NAME))
+                ).sneakyThrow())
+            .filter(headers -> headers.length > 0)
+            .map(headers -> headers[0])
+            .flatMap(this::retrieveReplyTo);
+    }
+
+    private Optional<MailAddress> retrieveReplyTo(String headerValue) {
+        return LenientAddressParser.DEFAULT
+            .parseAddressList(headerValue)
+            .stream()
+            .flatMap(this::convertAddressToMailboxStream)
+            .flatMap(this::convertMailboxToMailAddress)
+            .findFirst();
+
+    }
+
+    private Stream<MailAddress> convertMailboxToMailAddress(Mailbox mailbox) {
+        try {
+            return Stream.of(new MailAddress(mailbox.getAddress()));
+        } catch (AddressException e) {
+            return Stream.empty();
+        }
+    }
+
+    private Stream<Mailbox> convertAddressToMailboxStream(org.apache.james.mime4j.dom.address.Address address) {
+        if (address instanceof Mailbox) {
+            return Stream.of((Mailbox) address);
+        } else if (address instanceof Group) {
+            return ((Group) address).getMailboxes().stream();
+        }
+        return Stream.empty();
+    }
+
+    private Stream<Pair<String, byte[]>> toJson(Map.Entry<String, Calendar> entry,
+                                                Map<String, byte[]> rawCalendars,
+                                                Mail mail,
+                                                MailAddress sender,
+                                                MailAddress replyTo) {
         return mail.getRecipients()
             .stream()
-            .flatMap(recipient -> toICAL(entry, rawCalendars, recipient, sender))
+            .flatMap(recipient -> toICAL(entry, rawCalendars, recipient, sender, replyTo))
             .flatMap(ical -> toJson(ical, mail.getName()))
             .map(json -> Pair.of(UUID.randomUUID().toString(), json.getBytes(StandardCharsets.UTF_8)));
     }
 
-    private Stream<String> toJson(ICAL ical, String mailName) {
+    private Stream<String> toJson(ICALAttributeDTO ical, String mailName) {
         try {
             return Stream.of(objectMapper.writeValueAsString(ical));
         } catch (JsonProcessingException e) {
@@ -202,7 +250,11 @@ public class ICALToJsonAttribute extends GenericMailet {
         }
     }
 
-    private Stream<ICAL> toICAL(Map.Entry<String, Calendar> entry, Map<String, byte[]> rawCalendars, MailAddress recipient, String sender) {
+    private Stream<ICALAttributeDTO> toICAL(Map.Entry<String, Calendar> entry,
+                                            Map<String, byte[]> rawCalendars,
+                                            MailAddress recipient,
+                                            MailAddress sender,
+                                            MailAddress replyTo) {
         Calendar calendar = entry.getValue();
         byte[] rawICal = rawCalendars.get(entry.getKey());
         if (rawICal == null) {
@@ -210,27 +262,27 @@ public class ICALToJsonAttribute extends GenericMailet {
             return Stream.of();
         }
         try {
-            return Stream.of(ICAL.builder()
+            return Stream.of(ICALAttributeDTO.builder()
                 .from(calendar, rawICal)
-                .recipient(recipient)
                 .sender(sender)
-                .build());
+                .recipient(recipient)
+                .replyTo(replyTo));
         } catch (Exception e) {
             LOGGER.error("Exception while converting calendar to ICAL", e);
             return Stream.of();
         }
     }
 
-    private Optional<String> retrieveSender(Mail mail) throws MessagingException {
-        Optional<String> fromMime = StreamUtils.ofOptional(
+    private Optional<MailAddress> retrieveSender(Mail mail) throws MessagingException {
+        Optional<MailAddress> fromMime = StreamUtils.ofOptional(
             Optional.ofNullable(mail.getMessage())
                 .map(Throwing.function(MimeMessage::getFrom).orReturn(new Address[]{})))
             .map(address -> (InternetAddress) address)
             .map(InternetAddress::getAddress)
+            .map(MaybeSender::getMailSender)
+            .flatMap(MaybeSender::asStream)
             .findFirst();
-        Optional<String> fromEnvelope = mail.getMaybeSender().asOptional()
-            .map(MailAddress::asString);
 
-        return fromMime.or(() -> fromEnvelope);
+        return fromMime.or(() -> mail.getMaybeSender().asOptional());
     }
 }
diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICALAttributeDTO.java
similarity index 63%
rename from mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java
rename to mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICALAttributeDTO.java
index 7a09d65..e594e4e 100644
--- a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICALAttributeDTO.java
@@ -32,54 +32,52 @@ import net.fortuna.ical4j.model.Calendar;
 import net.fortuna.ical4j.model.Property;
 import net.fortuna.ical4j.model.component.VEvent;
 
-public class ICAL {
+public class ICALAttributeDTO {
 
     public static final String DEFAULT_SEQUENCE_VALUE = "0";
 
     public static class Builder {
-        private String ical;
-        private String sender;
-        private String recipient;
-        private Optional<String> uid = Optional.empty();
-        private Optional<String> sequence = Optional.empty();
-        private Optional<String> dtstamp = Optional.empty();
-        private Optional<String> method = Optional.empty();
-        private Optional<String> recurrenceId = Optional.empty();
-
-        public Builder from(Calendar calendar, byte[] originalEvent) {
-            this.ical = new String(originalEvent, StandardCharsets.UTF_8);
+        public RequiresSender from(Calendar calendar, byte[] originalEvent) {
+            String ical = new String(originalEvent, StandardCharsets.UTF_8);
             VEvent vevent = (VEvent) calendar.getComponent("VEVENT");
-            this.uid = optionalOf(vevent.getUid());
-            this.method = optionalOf(calendar.getMethod());
-            this.recurrenceId = optionalOf(vevent.getRecurrenceId());
-            this.sequence = optionalOf(vevent.getSequence());
-            this.dtstamp = optionalOf(vevent.getDateStamp());
-            return this;
+            Optional<String> uid = optionalOf(vevent.getUid());
+            Optional<String> method = optionalOf(calendar.getMethod());
+            Optional<String> recurrenceId = optionalOf(vevent.getRecurrenceId());
+            Optional<String> sequence = optionalOf(vevent.getSequence());
+            Optional<String> dtstamp = optionalOf(vevent.getDateStamp());
+
+            Preconditions.checkNotNull(ical);
+            Preconditions.checkState(uid.isPresent(), "uid is a compulsory property of an ICAL object");
+            Preconditions.checkState(method.isPresent(), "method is a compulsory property of an ICAL object");
+            Preconditions.checkState(dtstamp.isPresent(), "dtstamp is a compulsory property of an ICAL object");
+
+            return sender -> recipient -> replyTo ->
+                    new ICALAttributeDTO(
+                            ical,
+                            uid.get(), sender.asString(),
+                            recipient.asString(),
+                            replyTo.asString(),
+                            dtstamp.get(), method.get(), sequence,
+                            recurrenceId);
         }
 
         private Optional<String> optionalOf(Property property) {
             return Optional.ofNullable(property).map(Property::getValue);
         }
 
-        public Builder sender(String sender) {
-            this.sender = sender;
-            return this;
+        @FunctionalInterface
+        public interface RequiresSender {
+            RequiresRecipient sender(MailAddress sender);
         }
 
-
-        public Builder recipient(MailAddress recipient) {
-            this.recipient = recipient.asString();
-            return this;
+        @FunctionalInterface
+        public interface RequiresRecipient {
+            RequiresReplyTo recipient(MailAddress recipient);
         }
 
-        public ICAL build() {
-            Preconditions.checkNotNull(recipient);
-            Preconditions.checkNotNull(sender);
-            Preconditions.checkNotNull(ical);
-            Preconditions.checkState(uid.isPresent(), "uid is a compulsary property of an ICAL object");
-            Preconditions.checkState(method.isPresent(), "method is a compulsary property of an ICAL object");
-            Preconditions.checkState(dtstamp.isPresent(), "dtstamp is a compulsary property of an ICAL object");
-            return new ICAL(ical, sender, recipient, uid, sequence, dtstamp, method, recurrenceId);
+        @FunctionalInterface
+        public interface RequiresReplyTo {
+            ICALAttributeDTO replyTo(MailAddress replyTo);
         }
     }
 
@@ -90,21 +88,23 @@ public class ICAL {
     private final String ical;
     private final String sender;
     private final String recipient;
-    private final Optional<String> uid;
+    private final String replyTo;
+    private final String uid;
+    private final String dtstamp;
+    private final String method;
     private final Optional<String> sequence;
-    private final Optional<String> dtstamp;
-    private final Optional<String> method;
     private final Optional<String> recurrenceId;
 
-    private ICAL(String ical, String sender, String recipient, Optional<String> uid, Optional<String> sequence, Optional<String> dtstamp,
-                 Optional<String> method, Optional<String> recurrenceId) {
+    private ICALAttributeDTO(String ical, String uid, String sender, String recipient, String replyTo, String dtstamp,
+                             String method, Optional<String> sequence, Optional<String> recurrenceId) {
         this.ical = ical;
         this.sender = sender;
         this.recipient = recipient;
+        this.replyTo = replyTo;
         this.uid = uid;
-        this.sequence = sequence;
         this.dtstamp = dtstamp;
         this.method = method;
+        this.sequence = sequence;
         this.recurrenceId = recurrenceId;
     }
 
@@ -120,22 +120,26 @@ public class ICAL {
         return recipient;
     }
 
-    public Optional<String> getUid() {
-        return uid;
+    public String getReplyTo() {
+        return replyTo;
     }
 
-    public String getSequence() {
-        return sequence.orElse(DEFAULT_SEQUENCE_VALUE);
+    public String getUid() {
+        return uid;
     }
 
-    public Optional<String> getDtstamp() {
+    public String getDtstamp() {
         return dtstamp;
     }
 
-    public Optional<String> getMethod() {
+    public String getMethod() {
         return method;
     }
 
+    public String getSequence() {
+        return sequence.orElse(DEFAULT_SEQUENCE_VALUE);
+    }
+
     @JsonProperty("recurrence-id")
     public Optional<String> getRecurrenceId() {
         return recurrenceId;
@@ -143,8 +147,8 @@ public class ICAL {
 
     @Override
     public final boolean equals(Object o) {
-        if (o instanceof ICAL) {
-            ICAL that = (ICAL) o;
+        if (o instanceof ICALAttributeDTO) {
+            ICALAttributeDTO that = (ICALAttributeDTO) o;
             return Objects.equals(that.ical, this.ical)
                 && Objects.equals(that.sender, this.sender)
                 && Objects.equals(that.recipient, this.recipient)
@@ -152,13 +156,14 @@ public class ICAL {
                 && Objects.equals(that.sequence, this.sequence)
                 && Objects.equals(that.dtstamp, this.dtstamp)
                 && Objects.equals(that.method, this.method)
-                && Objects.equals(that.recurrenceId, this.recurrenceId);
+                && Objects.equals(that.recurrenceId, this.recurrenceId)
+                && Objects.equals(that.replyTo, this.replyTo);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(ical, sender, recipient, uid, sequence, dtstamp, method, recurrenceId);
+        return Objects.hash(ical, sender, recipient, uid, sequence, dtstamp, method, recurrenceId, replyTo);
     }
 }
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
index 40111b7..35666d2 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -21,12 +21,14 @@ package org.apache.james.transport.mailets;
 
 import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.mail.MessagingException;
 
@@ -41,10 +43,11 @@ import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import com.fasterxml.jackson.core.util.BufferRecyclers;
 import com.google.common.collect.ImmutableMap;
@@ -56,23 +59,20 @@ public class ICALToJsonAttributeTest {
     @SuppressWarnings("unchecked")
     private static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
     private ICALToJsonAttribute testee;
 
-    @Before
-    public void setUp() {
+    @BeforeEach
+    void setUp() {
         testee = new ICALToJsonAttribute();
     }
 
     @Test
-    public void getMailetInfoShouldReturnExpectedValue() {
+    void getMailetInfoShouldReturnExpectedValue() {
         assertThat(testee.getMailetInfo()).isEqualTo("ICALToJson Mailet");
     }
 
     @Test
-    public void initShouldSetAttributesWhenAbsent() throws Exception {
+    void initShouldSetAttributesWhenAbsent() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         assertThat(testee.getSourceAttributeName()).isEqualTo(ICALToJsonAttribute.DEFAULT_SOURCE);
@@ -80,34 +80,31 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void initShouldThrowOnEmptySourceAttribute() throws Exception {
-        expectedException.expect(MessagingException.class);
-
-        testee.init(FakeMailetConfig.builder()
-            .setProperty(ICALToJsonAttribute.SOURCE_ATTRIBUTE_NAME, "")
-            .build());
+    void initShouldThrowOnEmptySourceAttribute() {
+        assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder()
+                .setProperty(ICALToJsonAttribute.SOURCE_ATTRIBUTE_NAME, "")
+                .build()))
+            .isInstanceOf(MessagingException.class);
     }
 
     @Test
-    public void initShouldThrowOnEmptyRawSourceAttribute() throws Exception {
-        expectedException.expect(MessagingException.class);
-
-        testee.init(FakeMailetConfig.builder()
-            .setProperty(ICALToJsonAttribute.RAW_SOURCE_ATTRIBUTE_NAME, "")
-            .build());
+    void initShouldThrowOnEmptyRawSourceAttribute() {
+        assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder()
+                .setProperty(ICALToJsonAttribute.RAW_SOURCE_ATTRIBUTE_NAME, "")
+                .build()))
+            .isInstanceOf(MessagingException.class);
     }
 
     @Test
-    public void initShouldThrowOnEmptyDestinationAttribute() throws Exception {
-        expectedException.expect(MessagingException.class);
-
-        testee.init(FakeMailetConfig.builder()
-            .setProperty(ICALToJsonAttribute.DESTINATION_ATTRIBUTE_NAME, "")
-            .build());
+    void initShouldThrowOnEmptyDestinationAttribute() {
+        assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder()
+                .setProperty(ICALToJsonAttribute.DESTINATION_ATTRIBUTE_NAME, "")
+                .build()))
+            .isInstanceOf(MessagingException.class);
     }
 
     @Test
-    public void initShouldSetAttributesWhenPresent() throws Exception {
+    void initShouldSetAttributesWhenPresent() throws Exception {
         String destination = "myDestination";
         String source = "mySource";
         String raw = "myRaw";
@@ -123,7 +120,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldFilterMailsWithoutICALs() throws Exception {
+    void serviceShouldFilterMailsWithoutICALs() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         Mail mail = FakeMail.builder()
@@ -138,7 +135,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldNotFailOnWrongAttributeType() throws Exception {
+    void serviceShouldNotFailOnWrongAttributeType() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         Mail mail = FakeMail.builder()
@@ -154,7 +151,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldNotFailOnWrongRawAttributeType() throws Exception {
+    void serviceShouldNotFailOnWrongRawAttributeType() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         Mail mail = FakeMail.builder()
@@ -170,7 +167,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldNotFailOnWrongAttributeParameter() throws Exception {
+    void serviceShouldNotFailOnWrongAttributeParameter() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         ImmutableMap<String, String> wrongParametrizedMap = ImmutableMap.of("key", "value");
@@ -187,7 +184,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldNotFailOnWrongRawAttributeParameter() throws Exception {
+    void serviceShouldNotFailOnWrongRawAttributeParameter() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         ImmutableMap<String, String> wrongParametrizedMap = ImmutableMap.of("key", "value");
@@ -204,7 +201,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldFilterMailsWithoutSender() throws Exception {
+    void serviceShouldFilterMailsWithoutSender() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -224,7 +221,7 @@ public class ICALToJsonAttributeTest {
 
     @SuppressWarnings("unchecked")
     @Test
-    public void serviceShouldAttachEmptyListWhenNoRecipient() throws Exception {
+    void serviceShouldAttachEmptyListWhenNoRecipient() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -245,7 +242,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldAttachJson() throws Exception {
+    void serviceShouldAttachJson() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -270,6 +267,7 @@ public class ICALToJsonAttributeTest {
                     .isEqualTo("{" +
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + recipient.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
@@ -284,8 +282,99 @@ public class ICALToJsonAttributeTest {
         return new String(BufferRecyclers.getJsonStringEncoder().quoteAsUTF8(new String(ics, StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
     }
 
+    @ParameterizedTest
+    @MethodSource("validReplyToHeaders")
+    void serviceShouldAttachJsonWithTheReplyToAttributeValueWhenPresent(String replyToHeader) throws Exception {
+        testee.init(FakeMailetConfig.builder().build());
+
+        byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
+        Calendar calendar = new CalendarBuilder().build(new ByteArrayInputStream(ics));
+        ImmutableMap<String, Calendar> icals = ImmutableMap.of("key", calendar);
+        ImmutableMap<String, byte[]> rawIcals = ImmutableMap.of("key", ics);
+        MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
+        MailAddress replyTo = MailAddressFixture.OTHER_AT_JAMES;
+        Mail mail = FakeMail.builder()
+            .name("mail")
+            .sender(SENDER)
+            .recipient(recipient)
+            .attribute(new Attribute(ICALToJsonAttribute.DEFAULT_SOURCE, AttributeValue.ofAny(icals)))
+            .attribute(new Attribute(ICALToJsonAttribute.DEFAULT_RAW_SOURCE, AttributeValue.ofAny(rawIcals)))
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addHeader(ICALToJsonAttribute.REPLY_TO_HEADER_NAME, replyToHeader))
+            .build();
+        testee.service(mail);
+
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+            .isPresent()
+            .hasValueSatisfying(jsons -> {
+                assertThat(jsons).hasSize(1);
+                assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                    .isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"replyTo\": \"" + replyTo.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+            });
+    }
+
+    private static Stream<Arguments> validReplyToHeaders() {
+        String address = MailAddressFixture.OTHER_AT_JAMES.asString();
+        return Stream.of(
+                address,
+                "<" + address + ">",
+                "\"Bob\" <" + address + ">",
+                "\"Bob\"\n      <" + address + ">",
+                " =?UTF-8?Q?Beno=c3=aet_TELLIER?= <" + address + ">")
+            .map(Arguments::of);
+    };
+
+    @Test
+    void serviceShouldAttachJsonWithTheSenderAsReplyToAttributeValueWhenReplyToIsInvalid() throws Exception {
+        testee.init(FakeMailetConfig.builder().build());
+
+        byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
+        Calendar calendar = new CalendarBuilder().build(new ByteArrayInputStream(ics));
+        ImmutableMap<String, Calendar> icals = ImmutableMap.of("key", calendar);
+        ImmutableMap<String, byte[]> rawIcals = ImmutableMap.of("key", ics);
+        MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
+        Mail mail = FakeMail.builder()
+            .name("mail")
+            .sender(SENDER)
+            .recipient(recipient)
+            .attribute(new Attribute(ICALToJsonAttribute.DEFAULT_SOURCE, AttributeValue.ofAny(icals)))
+            .attribute(new Attribute(ICALToJsonAttribute.DEFAULT_RAW_SOURCE, AttributeValue.ofAny(rawIcals)))
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+                .addHeader(ICALToJsonAttribute.REPLY_TO_HEADER_NAME, "inv@lid.m@il.adr"))
+            .build();
+        testee.service(mail);
+
+        assertThat(AttributeUtils.getValueAndCastFromMail(mail, ICALToJsonAttribute.DEFAULT_DESTINATION, MAP_STRING_BYTES_CLASS))
+            .isPresent()
+            .hasValueSatisfying(jsons -> {
+                assertThat(jsons).hasSize(1);
+                assertThatJson(new String(jsons.values().iterator().next(), StandardCharsets.UTF_8))
+                    .isEqualTo("{" +
+                        "\"ical\": \"" + toJsonValue(ics) + "\"," +
+                        "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
+                        "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+                        "\"sequence\": \"0\"," +
+                        "\"dtstamp\": \"20170106T115036Z\"," +
+                        "\"method\": \"REQUEST\"," +
+                        "\"recurrence-id\": null" +
+                        "}");
+            });
+    }
+
     @Test
-    public void serviceShouldAttachJsonForSeveralRecipient() throws Exception {
+    void serviceShouldAttachJsonForSeveralRecipient() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -311,6 +400,7 @@ public class ICALToJsonAttributeTest {
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + MailAddressFixture.ANY_AT_JAMES2.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
                         "\"dtstamp\": \"20170106T115036Z\"," +
@@ -321,6 +411,7 @@ public class ICALToJsonAttributeTest {
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + MailAddressFixture.OTHER_AT_JAMES.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
                         "\"dtstamp\": \"20170106T115036Z\"," +
@@ -331,7 +422,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldAttachJsonForSeveralICALs() throws Exception {
+    void serviceShouldAttachJsonForSeveralICALs() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -360,6 +451,7 @@ public class ICALToJsonAttributeTest {
                         "\"ical\": \"" + toJsonValue(ics2) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047feb2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe\"," +
                         "\"sequence\": \"0\"," +
                         "\"dtstamp\": \"20170103T103250Z\"," +
@@ -370,6 +462,7 @@ public class ICALToJsonAttributeTest {
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
                         "\"dtstamp\": \"20170106T115036Z\"," +
@@ -380,7 +473,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldFilterInvalidICS() throws Exception {
+    void serviceShouldFilterInvalidICS() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -409,6 +502,7 @@ public class ICALToJsonAttributeTest {
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + recipient.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
                         "\"dtstamp\": \"20170106T115036Z\"," +
@@ -419,7 +513,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldFilterNonExistingKeys() throws Exception {
+    void serviceShouldFilterNonExistingKeys() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -447,6 +541,7 @@ public class ICALToJsonAttributeTest {
                     assertThatJson(actual.get(0)).isEqualTo("{" +
                         "\"ical\": \"" + toJsonValue(ics) + "\"," +
                         "\"sender\": \"" + SENDER.asString() + "\"," +
+                        "\"replyTo\": \"" + SENDER.asString() + "\"," +
                         "\"recipient\": \"" + recipient.asString() + "\"," +
                         "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                         "\"sequence\": \"0\"," +
@@ -458,7 +553,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldUseFromWhenSpecified() throws Exception {
+    void serviceShouldUseFromWhenSpecified() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -487,6 +582,7 @@ public class ICALToJsonAttributeTest {
                             "\"ical\": \"" + toJsonValue(ics) + "\"," +
                             "\"sender\": \"" + from + "\"," +
                             "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"replyTo\": \"" + from + "\"," +
                             "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                             "\"sequence\": \"0\"," +
                             "\"dtstamp\": \"20170106T115036Z\"," +
@@ -497,7 +593,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldSupportMimeMessagesWithoutFromFields() throws Exception {
+    void serviceShouldSupportMimeMessagesWithoutFromFields() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -524,6 +620,7 @@ public class ICALToJsonAttributeTest {
                             "\"ical\": \"" + toJsonValue(ics) + "\"," +
                             "\"sender\": \"" + SENDER.asString() + "\"," +
                             "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"replyTo\": \"" + SENDER.asString() + "\"," +
                             "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                             "\"sequence\": \"0\"," +
                             "\"dtstamp\": \"20170106T115036Z\"," +
@@ -534,7 +631,7 @@ public class ICALToJsonAttributeTest {
     }
 
     @Test
-    public void serviceShouldUseFromWhenSpecifiedAndNoSender() throws Exception {
+    void serviceShouldUseFromWhenSpecifiedAndNoSender() throws Exception {
         testee.init(FakeMailetConfig.builder().build());
 
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
@@ -562,6 +659,7 @@ public class ICALToJsonAttributeTest {
                             "\"ical\": \"" + toJsonValue(ics) + "\"," +
                             "\"sender\": \"" + from + "\"," +
                             "\"recipient\": \"" + recipient.asString() + "\"," +
+                            "\"replyTo\": \"" + from + "\"," +
                             "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
                             "\"sequence\": \"0\"," +
                             "\"dtstamp\": \"20170106T115036Z\"," +
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALAttributeDTOTest.java
similarity index 74%
rename from mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java
rename to mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALAttributeDTOTest.java
index dc530a1..5c69a99 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALAttributeDTOTest.java
@@ -36,7 +36,7 @@ import net.fortuna.ical4j.data.CalendarBuilder;
 import net.fortuna.ical4j.model.Calendar;
 import nl.jqno.equalsverifier.EqualsVerifier;
 
-public class ICALTest {
+public class ICALAttributeDTOTest {
 
     @BeforeClass
     public static void setUpIcal4J() {
@@ -47,54 +47,17 @@ public class ICALTest {
     public ExpectedException expectedException = ExpectedException.none();
 
     @Test
-    public void buildShouldFailWhenNoCalendar() throws Exception {
-        expectedException.expect(NullPointerException.class);
-
-        ICAL.builder()
-            .recipient(MailAddressFixture.ANY_AT_JAMES)
-            .sender(MailAddressFixture.OTHER_AT_JAMES.asString())
-            .build();
-    }
-
-    @Test
-    public void buildShouldFailWhenNoSender() throws Exception {
-        expectedException.expect(NullPointerException.class);
-
-        byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
-        Calendar calendar = new CalendarBuilder().build(new ByteArrayInputStream(ics));
-
-        ICAL.builder()
-            .recipient(MailAddressFixture.ANY_AT_JAMES)
-            .from(calendar, ics)
-            .build();
-    }
-
-    @Test
-    public void buildShouldFailWhenNoRecipient() throws Exception {
-        expectedException.expect(NullPointerException.class);
-
-        byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
-        Calendar calendar = new CalendarBuilder().build(new ByteArrayInputStream(ics));
-
-        ICAL.builder()
-            .sender(MailAddressFixture.OTHER_AT_JAMES.asString())
-            .from(calendar, ics)
-            .build();
-    }
-
-
-    @Test
     public void buildShouldWork() throws Exception {
         byte[] ics = ClassLoaderUtils.getSystemResourceAsByteArray("ics/meeting.ics");
         Calendar calendar = new CalendarBuilder().build(new ByteArrayInputStream(ics));
 
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
-        ICAL ical = ICAL.builder()
-            .recipient(recipient)
-            .sender(sender.asString())
+        ICALAttributeDTO ical = ICALAttributeDTO.builder()
             .from(calendar, ics)
-            .build();
+            .sender(sender)
+            .recipient(recipient)
+            .replyTo(sender);
 
         assertThat(ical.getRecipient()).isEqualTo(recipient.asString());
         assertThat(ical.getSender()).isEqualTo(sender.asString());
@@ -110,7 +73,7 @@ public class ICALTest {
 
     @Test
     public void equalsAndHashCodeShouldBeWellImplemented() {
-        EqualsVerifier.forClass(ICAL.class).verify();
+        EqualsVerifier.forClass(ICALAttributeDTO.class).verify();
     }
 
     @Test
@@ -122,11 +85,11 @@ public class ICALTest {
 
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
-        ICAL.builder()
-            .recipient(recipient)
-            .sender(sender.asString())
+        ICALAttributeDTO.builder()
             .from(calendar, ics)
-            .build();
+            .sender(sender)
+            .recipient(recipient)
+            .replyTo(sender);
     }
 
     @Test
@@ -138,11 +101,11 @@ public class ICALTest {
 
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
-        ICAL.builder()
-            .recipient(recipient)
-            .sender(sender.asString())
+        ICALAttributeDTO.builder()
             .from(calendar, ics)
-            .build();
+            .sender(sender)
+            .recipient(recipient)
+            .replyTo(sender);
     }
 
     @Test
@@ -154,11 +117,11 @@ public class ICALTest {
 
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
-        ICAL.builder()
-            .recipient(recipient)
-            .sender(sender.asString())
+        ICALAttributeDTO.builder()
             .from(calendar, ics)
-            .build();
+            .sender(sender)
+            .recipient(recipient)
+            .replyTo(sender);
     }
 
     @Test
@@ -168,12 +131,12 @@ public class ICALTest {
 
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
-        ICAL ical = ICAL.builder()
-            .recipient(recipient)
-            .sender(sender.asString())
+        ICALAttributeDTO ical = ICALAttributeDTO.builder()
             .from(calendar, ics)
-            .build();
+            .sender(sender)
+            .recipient(recipient)
+            .replyTo(sender);
 
-        assertThat(ical.getSequence()).isEqualTo(ICAL.DEFAULT_SEQUENCE_VALUE);
+        assertThat(ical.getSequence()).isEqualTo(ICALAttributeDTO.DEFAULT_SEQUENCE_VALUE);
     }
 }


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