JAMES-2132 Introduce a MDN top level object

This also removes the dependency to mailet-base


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

Branch: refs/heads/master
Commit: 1f443cd1b1418886388b3977f600face45d0d375
Parents: 7c8ecec
Author: benwa <btell...@linagora.com>
Authored: Wed Aug 30 14:15:03 2017 +0700
Committer: benwa <btell...@linagora.com>
Committed: Fri Sep 1 08:16:14 2017 +0700

----------------------------------------------------------------------
 mdn/pom.xml                                     |   8 +-
 mdn/src/main/java/org/apache/james/mdn/MDN.java | 127 ++++
 .../java/org/apache/james/mdn/MDNFactory.java   |  68 --
 .../org/apache/james/mdn/MDNFactoryTest.java    | 727 -------------------
 .../james/mdn/MDNReportFormattingTest.java      | 727 +++++++++++++++++++
 .../test/java/org/apache/james/mdn/MDNTest.java | 130 ++++
 .../transport/mailets/jsieve/RejectAction.java  |  35 +-
 7 files changed, 1009 insertions(+), 813 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/pom.xml
----------------------------------------------------------------------
diff --git a/mdn/pom.xml b/mdn/pom.xml
index 3094c9d..7eb7d4b 100644
--- a/mdn/pom.xml
+++ b/mdn/pom.xml
@@ -34,8 +34,12 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.james</groupId>
-            <artifactId>apache-mailet-base</artifactId>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
         </dependency>
         <dependency>
             <groupId>junit</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/src/main/java/org/apache/james/mdn/MDN.java
----------------------------------------------------------------------
diff --git a/mdn/src/main/java/org/apache/james/mdn/MDN.java 
b/mdn/src/main/java/org/apache/james/mdn/MDN.java
new file mode 100644
index 0000000..06f6ebb
--- /dev/null
+++ b/mdn/src/main/java/org/apache/james/mdn/MDN.java
@@ -0,0 +1,127 @@
+/****************************************************************
+ * 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.mdn;
+
+import java.util.Objects;
+import java.util.Properties;
+
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+
+public class MDN {
+    public static class Builder {
+        private String humanReadableText;
+        private MDNReport report;
+
+        public Builder report(MDNReport report) {
+            Preconditions.checkNotNull(report);
+            this.report = report;
+            return this;
+        }
+
+        public Builder humanReadableText(String humanReadableText) {
+            Preconditions.checkNotNull(humanReadableText);
+            this.humanReadableText = humanReadableText;
+            return this;
+        }
+
+        public MDN build() {
+            Preconditions.checkState(report != null);
+            Preconditions.checkState(humanReadableText != null);
+            return new MDN(humanReadableText, report);
+        }
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    private final String humanReadableText;
+    private final MDNReport report;
+
+    public MDN(String humanReadableText, MDNReport report) {
+        this.humanReadableText = humanReadableText;
+        this.report = report;
+    }
+
+    public String getHumanReadableText() {
+        return humanReadableText;
+    }
+
+    public MDNReport getReport() {
+        return report;
+    }
+
+    public MimeMultipart asMultipart() throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.setSubType("report");
+        multipart.addBodyPart(computeHumanReadablePart());
+        multipart.addBodyPart(computeReportPart());
+        // The optional third part, the original message is omitted.
+        // We don't want to propogate over-sized, virus infected or
+        // other undesirable mail!
+        // There is the option of adding a Text/RFC822-Headers part, which
+        // includes only the RFC 822 headers of the failed message. This is
+        // described in RFC 1892. It would be a useful addition!
+        return multipart;
+    }
+
+    public MimeMessage asMimeMessage() throws MessagingException {
+        MimeMessage mimeMessage = new 
MimeMessage(Session.getDefaultInstance(new Properties()));
+        mimeMessage.setContent(asMultipart());
+        return mimeMessage;
+    }
+
+    public BodyPart computeHumanReadablePart() throws MessagingException {
+        MimeBodyPart textPart = new MimeBodyPart();
+        textPart.setText(humanReadableText, Charsets.UTF_8.displayName());
+        textPart.setDisposition(MimeMessage.INLINE);
+        return textPart;
+    }
+
+    public BodyPart computeReportPart() throws MessagingException {
+        MimeBodyPart mdnPart = new MimeBodyPart();
+        mdnPart.setContent(report.formattedValue(), 
"message/disposition-notification");
+        return mdnPart;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof MDN) {
+            MDN mdn = (MDN) o;
+
+            return Objects.equals(this.humanReadableText, 
mdn.humanReadableText)
+                && Objects.equals(this.report, mdn.report);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(humanReadableText, report);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/src/main/java/org/apache/james/mdn/MDNFactory.java
----------------------------------------------------------------------
diff --git a/mdn/src/main/java/org/apache/james/mdn/MDNFactory.java 
b/mdn/src/main/java/org/apache/james/mdn/MDNFactory.java
deleted file mode 100644
index 57ff29a..0000000
--- a/mdn/src/main/java/org/apache/james/mdn/MDNFactory.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************
- * 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.mdn;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeBodyPart;
-
-import org.apache.mailet.base.mail.MimeMultipartReport;
-
-/**
- * Class <code>MDNFactory</code> creates MimeMultipartReports containing
- * Message Delivery Notifications as specified by RFC 2298.
- */
-public class MDNFactory {
-    
-    /**
-     * Answers a MimeMultipartReport containing a
-     * Message Delivery Notification as specified by RFC 2298.
-     * 
-     * @param humanText
-     * @param mdnReport
-     * @return MimeMultipartReport
-     * @throws MessagingException
-     */
-    public static MimeMultipartReport create(String humanText,
-            MDNReport mdnReport) throws MessagingException {
-        // Create the message parts. According to RFC 2298, there are two
-        // compulsory parts and one optional part...
-        MimeMultipartReport multiPart = new MimeMultipartReport();
-        multiPart.setReportType("disposition-notification");
-        
-        // Part 1: The 'human-readable' part
-        MimeBodyPart humanPart = new MimeBodyPart();
-        humanPart.setText(humanText);
-        multiPart.addBodyPart(humanPart);
-
-        // Part 2: MDN Report Part
-        MimeBodyPart mdnPart = new MimeBodyPart();
-        mdnPart.setContent(mdnReport.formattedValue(), 
"message/disposition-notification");
-        multiPart.addBodyPart(mdnPart);
-
-        // Part 3: The optional third part, the original message is omitted.
-        // We don't want to propogate over-sized, virus infected or
-        // other undesirable mail!
-        // There is the option of adding a Text/RFC822-Headers part, which
-        // includes only the RFC 822 headers of the failed message. This is
-        // described in RFC 1892. It would be a useful addition!        
-        return multiPart;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/src/test/java/org/apache/james/mdn/MDNFactoryTest.java
----------------------------------------------------------------------
diff --git a/mdn/src/test/java/org/apache/james/mdn/MDNFactoryTest.java 
b/mdn/src/test/java/org/apache/james/mdn/MDNFactoryTest.java
deleted file mode 100644
index eaad55c..0000000
--- a/mdn/src/test/java/org/apache/james/mdn/MDNFactoryTest.java
+++ /dev/null
@@ -1,727 +0,0 @@
-/****************************************************************
- * 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.mdn;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.mdn.action.mode.DispositionActionMode;
-import org.apache.james.mdn.fields.Disposition;
-import org.apache.james.mdn.fields.Error;
-import org.apache.james.mdn.fields.ExtensionField;
-import org.apache.james.mdn.fields.FinalRecipient;
-import org.apache.james.mdn.fields.Gateway;
-import org.apache.james.mdn.fields.OriginalMessageId;
-import org.apache.james.mdn.fields.OriginalRecipient;
-import org.apache.james.mdn.fields.ReportingUserAgent;
-import org.apache.james.mdn.fields.Text;
-import org.apache.james.mdn.modifier.DispositionModifier;
-import org.apache.james.mdn.sending.mode.DispositionSendingMode;
-import org.apache.james.mdn.type.DispositionType;
-import org.junit.Test;
-
-public class MDNFactoryTest {
-
-    @Test
-    public void generateMDNReportShouldFormatAutomaticActions() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatManualActions() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatTypeDispatcher() {
-        Disposition disposition = Disposition.builder()
-        .actionMode(DispositionActionMode.Manual)
-        .sendingMode(DispositionSendingMode.Manual)
-        .type(DispositionType.Dispatched)
-        .addModifier(DispositionModifier.Error)
-        .addModifier(DispositionModifier.Failed)
-        .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;dispatched/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatTypeDisplayed() {
-        Disposition disposition = Disposition.builder()
-        .actionMode(DispositionActionMode.Manual)
-        .sendingMode(DispositionSendingMode.Manual)
-        .type(DispositionType.Displayed)
-        .addModifier(DispositionModifier.Error)
-        .addModifier(DispositionModifier.Failed)
-        .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;displayed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatTypeDeleted() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Deleted)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;deleted/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatAllModifier() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Deleted)
-            .addModifiers(DispositionModifier.Error, 
DispositionModifier.Expired, DispositionModifier.Failed,
-                DispositionModifier.MailboxTerminated, 
DispositionModifier.Superseded, DispositionModifier.Warning)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;deleted/error,expired,failed,mailbox-terminated,superseded,warning\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatOneModifier() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Deleted)
-            .addModifier(DispositionModifier.Error)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;deleted/error\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatUnknownModifier() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Deleted)
-            .addModifier(new DispositionModifier("new"))
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-manually;deleted/new\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatNoModifier() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Manual)
-            .type(DispositionType.Deleted)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: manual-action/MDN-sent-manually;deleted\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatNullUserAgentProduct() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Deleted)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent("UA_name"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; \r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatNullOriginalRecipient() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Deleted)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatWhenMissingOriginalMessageId() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Manual)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Deleted)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatGateway() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .gatewayField(new Gateway(Text.fromRawText("host.com")))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "MDN-Gateway: dns;host.com\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatGatewayWithExoticNameType() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .gatewayField(new Gateway("postal", Text.fromRawText("5 rue 
Charles mercier")))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "MDN-Gateway: postal;5 rue Charles mercier\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void 
generateMDNReportShouldFormatExoticAddressTypeForOriginalRecipient() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new OriginalRecipient("roomNumber", 
Text.fromRawText("385")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: roomNumber; 385\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatMultilineAddresses() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .gatewayField(new Gateway("postal", Text.fromRawText("8 rue 
Charles mercier\n 36555 Saint Coincoin\n France")))
-            .finalRecipientField(new FinalRecipient("postal", 
Text.fromRawText("5 rue Mercier\n 36555 Saint Coincoin\n France")))
-            .originalRecipientField(new OriginalRecipient("postal", 
Text.fromRawText("3 rue Mercier\n 36555 Saint Coincoin\n France")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "MDN-Gateway: postal;8 rue Charles mercier\r\n" +
-                " 36555 Saint Coincoin\r\n" +
-                " France\r\n" +
-                "Original-Recipient: postal; 3 rue Mercier\r\n" +
-                " 36555 Saint Coincoin\r\n" +
-                " France\r\n" +
-                "Final-Recipient: postal; 5 rue Mercier\r\n" +
-                " 36555 Saint Coincoin\r\n" +
-                " France\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void 
generateMDNReportShouldFormatUnknownAddressTypeForOriginalRecipient() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            
.originalRecipientField(OriginalRecipient.ofUnknown(Text.fromRawText("#$%*")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: unknown; #$%*\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatExoticFinalRecipientAddressType() 
{
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new FinalRecipient("roomNumber", 
Text.fromRawText("781")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: roomNumber; 781\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatErrorField() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .addErrorField(new Error(Text.fromRawText("An error message")))
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
-                "Error: An error message\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatErrorFields() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .addErrorFields(
-                new Error(Text.fromRawText("An error message")),
-                new Error(Text.fromRawText("A second error message")))
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
-                "Error: An error message\r\n" +
-                "Error: A second error message\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatErrorFieldsOnSeveralLines() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .addErrorField(new Error(Text.fromRawText("An error message\non 
several lines")))
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
-                "Error: An error message\r\n" +
-                " on several lines\r\n");
-    }
-
-    @Test
-    public void generateMDNReportShouldFormatOneExtension() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-         .withExtensionField(new ExtensionField("X-OPENPAAS-IP", 
"177.177.177.77"))
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
-                "X-OPENPAAS-IP: 177.177.177.77\r\n");
-    }
-
-
-    @Test
-    public void generateMDNReportShouldFormatManyExtensions() {
-        Disposition disposition = Disposition.builder()
-            .actionMode(DispositionActionMode.Automatic)
-            .sendingMode(DispositionSendingMode.Automatic)
-            .type(DispositionType.Processed)
-            .addModifier(DispositionModifier.Error)
-            .addModifier(DispositionModifier.Failed)
-            .build();
-
-        String report = MDNReport.builder()
-            .reportingUserAgentField(new ReportingUserAgent(
-                "UA_name",
-                "UA_product"))
-            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
-            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
-            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
-            .dispositionField(disposition)
-            .withExtensionFields(
-                new ExtensionField("X-OPENPAAS-IP", "177.177.177.77"),
-                new ExtensionField("X-OPENPAAS-PORT", "8000"))
-            .build()
-            .formattedValue();
-
-        assertThat(report)
-            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
-                "Original-Recipient: rfc822; originalRecipient\r\n" +
-                "Final-Recipient: rfc822; final_recipient\r\n" +
-                "Original-Message-ID: original_message_id\r\n" +
-                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
-                "X-OPENPAAS-IP: 177.177.177.77\r\n" +
-                "X-OPENPAAS-PORT: 8000\r\n");
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/src/test/java/org/apache/james/mdn/MDNReportFormattingTest.java
----------------------------------------------------------------------
diff --git 
a/mdn/src/test/java/org/apache/james/mdn/MDNReportFormattingTest.java 
b/mdn/src/test/java/org/apache/james/mdn/MDNReportFormattingTest.java
new file mode 100644
index 0000000..8168915
--- /dev/null
+++ b/mdn/src/test/java/org/apache/james/mdn/MDNReportFormattingTest.java
@@ -0,0 +1,727 @@
+/****************************************************************
+ * 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.mdn;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.james.mdn.action.mode.DispositionActionMode;
+import org.apache.james.mdn.fields.Disposition;
+import org.apache.james.mdn.fields.Error;
+import org.apache.james.mdn.fields.ExtensionField;
+import org.apache.james.mdn.fields.FinalRecipient;
+import org.apache.james.mdn.fields.Gateway;
+import org.apache.james.mdn.fields.OriginalMessageId;
+import org.apache.james.mdn.fields.OriginalRecipient;
+import org.apache.james.mdn.fields.ReportingUserAgent;
+import org.apache.james.mdn.fields.Text;
+import org.apache.james.mdn.modifier.DispositionModifier;
+import org.apache.james.mdn.sending.mode.DispositionSendingMode;
+import org.apache.james.mdn.type.DispositionType;
+import org.junit.Test;
+
+public class MDNReportFormattingTest {
+
+    @Test
+    public void generateMDNReportShouldFormatAutomaticActions() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatManualActions() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatTypeDispatcher() {
+        Disposition disposition = Disposition.builder()
+        .actionMode(DispositionActionMode.Manual)
+        .sendingMode(DispositionSendingMode.Manual)
+        .type(DispositionType.Dispatched)
+        .addModifier(DispositionModifier.Error)
+        .addModifier(DispositionModifier.Failed)
+        .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;dispatched/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatTypeDisplayed() {
+        Disposition disposition = Disposition.builder()
+        .actionMode(DispositionActionMode.Manual)
+        .sendingMode(DispositionSendingMode.Manual)
+        .type(DispositionType.Displayed)
+        .addModifier(DispositionModifier.Error)
+        .addModifier(DispositionModifier.Failed)
+        .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;displayed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatTypeDeleted() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Deleted)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;deleted/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatAllModifier() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Deleted)
+            .addModifiers(DispositionModifier.Error, 
DispositionModifier.Expired, DispositionModifier.Failed,
+                DispositionModifier.MailboxTerminated, 
DispositionModifier.Superseded, DispositionModifier.Warning)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;deleted/error,expired,failed,mailbox-terminated,superseded,warning\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatOneModifier() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Deleted)
+            .addModifier(DispositionModifier.Error)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;deleted/error\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatUnknownModifier() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Deleted)
+            .addModifier(new DispositionModifier("new"))
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-manually;deleted/new\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatNoModifier() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Manual)
+            .type(DispositionType.Deleted)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: manual-action/MDN-sent-manually;deleted\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatNullUserAgentProduct() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Deleted)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent("UA_name"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; \r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatNullOriginalRecipient() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Deleted)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatWhenMissingOriginalMessageId() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Manual)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Deleted)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Disposition: 
manual-action/MDN-sent-automatically;deleted/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatGateway() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .gatewayField(new Gateway(Text.fromRawText("host.com")))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "MDN-Gateway: dns;host.com\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatGatewayWithExoticNameType() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .gatewayField(new Gateway("postal", Text.fromRawText("5 rue 
Charles mercier")))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "MDN-Gateway: postal;5 rue Charles mercier\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void 
generateMDNReportShouldFormatExoticAddressTypeForOriginalRecipient() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new OriginalRecipient("roomNumber", 
Text.fromRawText("385")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: roomNumber; 385\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatMultilineAddresses() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .gatewayField(new Gateway("postal", Text.fromRawText("8 rue 
Charles mercier\n 36555 Saint Coincoin\n France")))
+            .finalRecipientField(new FinalRecipient("postal", 
Text.fromRawText("5 rue Mercier\n 36555 Saint Coincoin\n France")))
+            .originalRecipientField(new OriginalRecipient("postal", 
Text.fromRawText("3 rue Mercier\n 36555 Saint Coincoin\n France")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "MDN-Gateway: postal;8 rue Charles mercier\r\n" +
+                " 36555 Saint Coincoin\r\n" +
+                " France\r\n" +
+                "Original-Recipient: postal; 3 rue Mercier\r\n" +
+                " 36555 Saint Coincoin\r\n" +
+                " France\r\n" +
+                "Final-Recipient: postal; 5 rue Mercier\r\n" +
+                " 36555 Saint Coincoin\r\n" +
+                " France\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void 
generateMDNReportShouldFormatUnknownAddressTypeForOriginalRecipient() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            
.originalRecipientField(OriginalRecipient.ofUnknown(Text.fromRawText("#$%*")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: unknown; #$%*\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatExoticFinalRecipientAddressType() 
{
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new FinalRecipient("roomNumber", 
Text.fromRawText("781")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: roomNumber; 781\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatErrorField() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .addErrorField(new Error(Text.fromRawText("An error message")))
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
+                "Error: An error message\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatErrorFields() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .addErrorFields(
+                new Error(Text.fromRawText("An error message")),
+                new Error(Text.fromRawText("A second error message")))
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
+                "Error: An error message\r\n" +
+                "Error: A second error message\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatErrorFieldsOnSeveralLines() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .addErrorField(new Error(Text.fromRawText("An error message\non 
several lines")))
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
+                "Error: An error message\r\n" +
+                " on several lines\r\n");
+    }
+
+    @Test
+    public void generateMDNReportShouldFormatOneExtension() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+         .withExtensionField(new ExtensionField("X-OPENPAAS-IP", 
"177.177.177.77"))
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
+                "X-OPENPAAS-IP: 177.177.177.77\r\n");
+    }
+
+
+    @Test
+    public void generateMDNReportShouldFormatManyExtensions() {
+        Disposition disposition = Disposition.builder()
+            .actionMode(DispositionActionMode.Automatic)
+            .sendingMode(DispositionSendingMode.Automatic)
+            .type(DispositionType.Processed)
+            .addModifier(DispositionModifier.Error)
+            .addModifier(DispositionModifier.Failed)
+            .build();
+
+        String report = MDNReport.builder()
+            .reportingUserAgentField(new ReportingUserAgent(
+                "UA_name",
+                "UA_product"))
+            .finalRecipientField(new 
FinalRecipient(Text.fromRawText("final_recipient")))
+            .originalRecipientField(new 
OriginalRecipient(Text.fromRawText("originalRecipient")))
+            .originalMessageIdField(new 
OriginalMessageId("original_message_id"))
+            .dispositionField(disposition)
+            .withExtensionFields(
+                new ExtensionField("X-OPENPAAS-IP", "177.177.177.77"),
+                new ExtensionField("X-OPENPAAS-PORT", "8000"))
+            .build()
+            .formattedValue();
+
+        assertThat(report)
+            .isEqualTo("Reporting-UA: UA_name; UA_product\r\n" +
+                "Original-Recipient: rfc822; originalRecipient\r\n" +
+                "Final-Recipient: rfc822; final_recipient\r\n" +
+                "Original-Message-ID: original_message_id\r\n" +
+                "Disposition: 
automatic-action/MDN-sent-automatically;processed/error,failed\r\n" +
+                "X-OPENPAAS-IP: 177.177.177.77\r\n" +
+                "X-OPENPAAS-PORT: 8000\r\n");
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f443cd1/mdn/src/test/java/org/apache/james/mdn/MDNTest.java
----------------------------------------------------------------------
diff --git a/mdn/src/test/java/org/apache/james/mdn/MDNTest.java 
b/mdn/src/test/java/org/apache/james/mdn/MDNTest.java
new file mode 100644
index 0000000..cf8b522
--- /dev/null
+++ b/mdn/src/test/java/org/apache/james/mdn/MDNTest.java
@@ -0,0 +1,130 @@
+/****************************************************************
+ * 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.mdn;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.mdn.action.mode.DispositionActionMode;
+import org.apache.james.mdn.fields.Disposition;
+import org.apache.james.mdn.sending.mode.DispositionSendingMode;
+import org.apache.james.mdn.type.DispositionType;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.base.Charsets;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class MDNTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(MDN.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+
+    @Test
+    public void asMimeMessageShouldComportExplanationPartAndReportPart() 
throws Exception {
+        MimeMessage mimeMessage = MDN.builder()
+            .humanReadableText("Explanation")
+            .report(MDNReport.builder()
+                .finalRecipientField("fi...@domain.com")
+                .dispositionField(Disposition.builder()
+                    .actionMode(DispositionActionMode.Automatic)
+                    .sendingMode(DispositionSendingMode.Automatic)
+                    .type(DispositionType.Deleted)
+                    .build())
+                .build())
+            .build()
+            .asMimeMessage();
+
+        ByteArrayOutputStream byteArrayOutputStream = new 
ByteArrayOutputStream();
+        mimeMessage.writeTo(byteArrayOutputStream);
+        assertThat(new String(byteArrayOutputStream.toByteArray(), 
Charsets.UTF_8))
+            .contains(
+                "Content-Type: text/plain; charset=UTF-8\r\n" +
+                "Content-Transfer-Encoding: 7bit\r\n" +
+                "Content-Disposition: inline\r\n" +
+                "\r\n" +
+                "Explanation")
+            .contains(
+                "Content-Type: message/disposition-notification\r\n" +
+                    "Content-Transfer-Encoding: 7bit\r\n" +
+                    "\r\n" +
+                    "Final-Recipient: rfc822; fi...@domain.com\r\n" +
+                    "Disposition: 
automatic-action/MDN-sent-automatically;deleted");
+    }
+
+    @Test
+    public void asMimeMessageShouldDisplayEmptyExplanation() throws Exception {
+        MimeMessage mimeMessage = MDN.builder()
+            .humanReadableText("")
+            .report(MDNReport.builder()
+                .finalRecipientField("fi...@domain.com")
+                .dispositionField(Disposition.builder()
+                    .actionMode(DispositionActionMode.Automatic)
+                    .sendingMode(DispositionSendingMode.Automatic)
+                    .type(DispositionType.Deleted)
+                    .build())
+                .build())
+            .build()
+            .asMimeMessage();
+
+        ByteArrayOutputStream byteArrayOutputStream = new 
ByteArrayOutputStream();
+        mimeMessage.writeTo(byteArrayOutputStream);
+        assertThat(new String(byteArrayOutputStream.toByteArray(), 
Charsets.UTF_8))
+            .contains(
+                "Content-Type: text/plain; charset=UTF-8\r\n" +
+                    "Content-Transfer-Encoding: 7bit\r\n" +
+                    "Content-Disposition: inline\r\n" +
+                    "\r\n")
+            .contains(
+                "Content-Type: message/disposition-notification\r\n" +
+                    "Content-Transfer-Encoding: 7bit\r\n" +
+                    "\r\n" +
+                    "Final-Recipient: rfc822; fi...@domain.com\r\n" +
+                    "Disposition: 
automatic-action/MDN-sent-automatically;deleted");
+    }
+
+    @Test
+    public void reportShouldThrowOnNullValue() {
+        expectedException.expect(NullPointerException.class);
+
+        MDN.builder()
+            .report(null);
+    }
+
+    @Test
+    public void humanReadableTextShouldThrowOnNullValue() {
+        expectedException.expect(NullPointerException.class);
+
+        MDN.builder()
+            .humanReadableText(null);
+    }
+}


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

Reply via email to