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

acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new 1328be8  [CAMEL-12605] Refactoring for compression support.
1328be8 is described below

commit 1328be84d5add8b9d94d1821155be3b0025242ee
Author: William Collins <punkhor...@gmail.com>
AuthorDate: Wed Nov 28 11:30:54 2018 -0500

    [CAMEL-12605] Refactoring for compression support.
---
 .../camel/component/as2/api/AS2ClientManager.java  | 122 +++++++++++++++++++--
 ...Structure.java => AS2CompressionAlgorithm.java} |  36 +++---
 .../component/as2/api/AS2MessageStructure.java     |  10 +-
 ...> ApplicationPkcs7MimeEnvelopedDataEntity.java} |   9 +-
 .../component/as2/api/entity/EntityParser.java     |   4 +-
 .../CompressionUtils.java}                         |  36 +++---
 .../camel/component/as2/api/AS2MessageTest.java    |  41 +++----
 .../component/as2/api/entity/EntityParserTest.java |   2 +-
 .../src/main/docs/as2-component.adoc               |   3 +-
 .../camel/component/as2/AS2Configuration.java      |  17 ++-
 .../as2/AS2ClientManagerIntegrationTest.java       |   6 +-
 .../as2/AS2ServerManagerIntegrationTest.java       |   4 +-
 .../as2/springboot/AS2ComponentConfiguration.java  |  14 +++
 13 files changed, 216 insertions(+), 88 deletions(-)

diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
index ecd1f7a..8e1905c 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java
@@ -21,9 +21,11 @@ import java.security.PrivateKey;
 import java.security.cert.Certificate;
 
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeCompressedDataEntity;
+import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import org.apache.camel.component.as2.api.entity.EntityParser;
 import org.apache.camel.component.as2.api.entity.MultipartSignedEntity;
+import org.apache.camel.component.as2.api.util.CompressionUtils;
 import org.apache.camel.component.as2.api.util.EncryptingUtils;
 import org.apache.camel.component.as2.api.util.EntityUtils;
 import org.apache.camel.component.as2.api.util.SigningUtils;
@@ -33,7 +35,9 @@ import org.apache.http.entity.ContentType;
 import org.apache.http.message.BasicHttpEntityEnclosingRequest;
 import org.apache.http.protocol.HttpCoreContext;
 import org.apache.http.util.Args;
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
 import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.operator.OutputCompressor;
 import org.bouncycastle.operator.OutputEncryptor;
 
 /**
@@ -157,6 +161,12 @@ public class AS2ClientManager {
     public static final String ENCRYPTING_PRIVATE_KEY = 
CAMEL_AS2_CLIENT_PREFIX + "encrypting-private-key";
 
     /**
+     * The HTTP Context Attribute containing the algorithm used to compress EDI
+     * message
+     */
+    public static final String COMPRESSION_ALGORITHM = CAMEL_AS2_CLIENT_PREFIX 
+ "compression-algorithm-name";
+
+    /**
      * The HTTP Context Attribute containing the internet e-mail address of
      * sending system requesting a message disposition notification.
      */
@@ -213,6 +223,7 @@ public class AS2ClientManager {
                                 AS2SignatureAlgorithm signingAlgorithm,
                                 Certificate[] signingCertificateChain,
                                 PrivateKey signingPrivateKey,
+                                AS2CompressionAlgorithm compressionAlgorithm,
                                 String dispositionNotificationTo,
                                 String[] signedReceiptMicAlgorithms,
                                 AS2EncryptionAlgorithm encryptingAlgorithm,
@@ -238,6 +249,7 @@ public class AS2ClientManager {
         httpContext.setAttribute(AS2ClientManager.SIGNING_ALGORITHM, 
signingAlgorithm);
         httpContext.setAttribute(AS2ClientManager.SIGNING_CERTIFICATE_CHAIN, 
signingCertificateChain);
         httpContext.setAttribute(AS2ClientManager.SIGNING_PRIVATE_KEY, 
signingPrivateKey);
+        httpContext.setAttribute(AS2ClientManager.COMPRESSION_ALGORITHM, 
compressionAlgorithm);
         httpContext.setAttribute(AS2ClientManager.DISPOSITION_NOTIFICATION_TO, 
dispositionNotificationTo);
         
httpContext.setAttribute(AS2ClientManager.SIGNED_RECEIPT_MIC_ALGORITHMS, 
signedReceiptMicAlgorithms);
         httpContext.setAttribute(AS2ClientManager.ENCRYPTING_ALGORITHM, 
encryptingAlgorithm);
@@ -256,35 +268,112 @@ public class AS2ClientManager {
         }
         switch (as2MessageStructure) {
         case PLAIN: {
+            // Add EDI Entity to main body of request.
             applicationEDIEntity.setMainBody(true);
             EntityUtils.setMessageEntity(request, applicationEDIEntity);
             break;
         }
         case SIGNED: {
-            AS2SignedDataGenerator gen = createSigningGenerator(httpContext);
-            // Create Multipart Signed Entity
-            MultipartSignedEntity multipartSignedEntity = new 
MultipartSignedEntity(applicationEDIEntity, gen,
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = 
createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new 
MultipartSignedEntity(applicationEDIEntity, signingGenrator,
                     AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, 
null);
-            multipartSignedEntity.setMainBody(true);
+            
+            // Add Multipart Signed Entity to main body of request.
             EntityUtils.setMessageEntity(request, multipartSignedEntity);
             break;
         }
         case ENCRYPTED: {
+            // Create Enveloped Entity containing EDI Entity
             CMSEnvelopedDataGenerator envelopedDataGenerator = 
createEncryptingGenerator(httpContext);
             OutputEncryptor encryptor = createEncryptor(httpContext);
-            ApplicationPkcs7MimeEntity pkcs7MimeEntity = new 
ApplicationPkcs7MimeEntity(applicationEDIEntity, envelopedDataGenerator, 
encryptor, AS2TransferEncoding.BASE64, true);
-            EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
+            ApplicationPkcs7MimeEnvelopedDataEntity 
pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    applicationEDIEntity, envelopedDataGenerator, encryptor, 
AS2TransferEncoding.BASE64, true);
+
+            // Add Multipart Enveloped Entity to main body of request.
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeEnvelopedDataEntity);
             break;
         }
-        case ENCRYPTED_SIGNED: {
+        case SIGNED_ENCRYPTED: {
+            // Create Multipart Signed Entity containing EDI Entity
             AS2SignedDataGenerator signingGenrator = 
createSigningGenerator(httpContext);
             MultipartSignedEntity multipartSignedEntity = new 
MultipartSignedEntity(applicationEDIEntity,
                     signingGenrator, AS2Charset.US_ASCII, 
AS2TransferEncoding.BASE64, false, null);
              
+            // Create Enveloped Entity containing Multipart Signed Entity
+            CMSEnvelopedDataGenerator envelopedDataGenerator = 
createEncryptingGenerator(httpContext);
+            OutputEncryptor encryptor = createEncryptor(httpContext);
+            ApplicationPkcs7MimeEnvelopedDataEntity 
pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    multipartSignedEntity, envelopedDataGenerator, encryptor, 
AS2TransferEncoding.BASE64, true);
+
+            // Add Multipart Enveloped Entity to main body of request.
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeEnvelopedDataEntity);
+            break;
+        }
+        case PLAIN_COMPRESSED: {
+            // Create Compressed Entity containing EDI Entity
+            CMSCompressedDataGenerator compressedDataGenerator = 
createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity 
pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    applicationEDIEntity, compressedDataGenerator, compressor, 
AS2TransferEncoding.BASE64, false);
+
+            // Add Compressed Entity to main body of request.
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeCompressedDataEntity);
+            break;
+        }
+        case SIGNED_COMPRESSED: {
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = 
createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new 
MultipartSignedEntity(applicationEDIEntity,
+                    signingGenrator, AS2Charset.US_ASCII, 
AS2TransferEncoding.BASE64, false, null);
+            
+            // Create Compressed Entity containing Multipart Signed Entity
+            CMSCompressedDataGenerator compressedDataGenerator = 
createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity 
pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    multipartSignedEntity, compressedDataGenerator, 
compressor, AS2TransferEncoding.BASE64, false);
+
+            // Add Compressed Entity to main body of request.
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeCompressedDataEntity);
+            break;
+        }
+        case ENCRYPTED_COMPRESSED: {
+            // Create Compressed Entity containing EDI Entity
+            CMSCompressedDataGenerator compressedDataGenerator = 
createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity 
pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    applicationEDIEntity, compressedDataGenerator, compressor, 
AS2TransferEncoding.BASE64, false);
+            
+            // Create Enveloped Entity containing Compressed Entity
             CMSEnvelopedDataGenerator envelopedDataGenerator = 
createEncryptingGenerator(httpContext);
             OutputEncryptor encryptor = createEncryptor(httpContext);
-            ApplicationPkcs7MimeEntity pkcs7MimeEntity = new 
ApplicationPkcs7MimeEntity(multipartSignedEntity, envelopedDataGenerator, 
encryptor, AS2TransferEncoding.BASE64, true);
-            EntityUtils.setMessageEntity(request, pkcs7MimeEntity);
+            ApplicationPkcs7MimeEnvelopedDataEntity 
pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    pkcs7MimeCompressedDataEntity, envelopedDataGenerator, 
encryptor, AS2TransferEncoding.BASE64, true);
+            
+            // Add Enveloped Entity to main body of request
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeEnvelopedDataEntity);
+            break;
+        }
+        case SIGNED_ENCRYPTED_COMPRESSED: {
+            // Create Multipart Signed Entity containing EDI Entity
+            AS2SignedDataGenerator signingGenrator = 
createSigningGenerator(httpContext);
+            MultipartSignedEntity multipartSignedEntity = new 
MultipartSignedEntity(applicationEDIEntity, signingGenrator,
+                    AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, 
null);
+            
+            // Create Compressed Entity containing Multipart Signed Entity
+            CMSCompressedDataGenerator compressedDataGenerator = 
createCompressorGenerator(httpContext);
+            OutputCompressor compressor = createCompressor(httpContext);
+            ApplicationPkcs7MimeCompressedDataEntity 
pkcs7MimeCompressedDataEntity = new ApplicationPkcs7MimeCompressedDataEntity(
+                    multipartSignedEntity, compressedDataGenerator, 
compressor, AS2TransferEncoding.BASE64, false);
+
+            // Create Enveloped Entity containing Compressed Entity
+            CMSEnvelopedDataGenerator envelopedDataGenerator = 
createEncryptingGenerator(httpContext);
+            OutputEncryptor encryptor = createEncryptor(httpContext);
+            ApplicationPkcs7MimeEnvelopedDataEntity 
pkcs7MimeEnvelopedDataEntity = new ApplicationPkcs7MimeEnvelopedDataEntity(
+                    pkcs7MimeCompressedDataEntity, envelopedDataGenerator, 
encryptor, AS2TransferEncoding.BASE64, true);
+            
+            // Add Enveloped Entity to main body of request
+            EntityUtils.setMessageEntity(request, 
pkcs7MimeEnvelopedDataEntity);
             break;
         }
         default:
@@ -335,6 +424,10 @@ public class AS2ClientManager {
 
     }
     
+    public CMSCompressedDataGenerator 
createCompressorGenerator(HttpCoreContext httpContext) {
+        return CompressionUtils.createCompressedDataGenerator();
+    }
+    
     public OutputEncryptor createEncryptor(HttpCoreContext httpContext) throws 
HttpException {
         
         AS2EncryptionAlgorithm encryptionAlgorithm = 
httpContext.getAttribute(ENCRYPTING_ALGORITHM, AS2EncryptionAlgorithm.class);
@@ -344,5 +437,14 @@ public class AS2ClientManager {
 
         return EncryptingUtils.createEncryptor(encryptionAlgorithm);
     }
+    
+    public OutputCompressor createCompressor(HttpCoreContext httpContext) 
throws HttpException {
+        AS2CompressionAlgorithm compressionAlgorithm = 
httpContext.getAttribute(COMPRESSION_ALGORITHM, AS2CompressionAlgorithm.class);
+        if (compressionAlgorithm == null) {
+            throw new HttpException("Compression algorithm missing");
+        }
+        
+        return CompressionUtils.createCompressor(compressionAlgorithm);
+    }
 
 }
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java
similarity index 56%
copy from 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
copy to 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java
index 3c8210a..b08b5ca 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2CompressionAlgorithm.java
@@ -16,29 +16,29 @@
  */
 package org.apache.camel.component.as2.api;
 
-public enum AS2MessageStructure {
-    PLAIN(false, false, false),
-    SIGNED(false, false, false),
-    ENCRYPTED(false, false, false),
-    ENCRYPTED_SIGNED(false, false, false);
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.cms.jcajce.ZlibCompressor;
+import org.bouncycastle.operator.OutputCompressor;
 
-    private final boolean isSigned;
-    private final boolean isEncrypted;
-    private final boolean isCompressed;
+public enum AS2CompressionAlgorithm {
+    ZLIB(new ZlibCompressor());
+    
+    private OutputCompressor outputCompressor;
 
-    private AS2MessageStructure(boolean isSigned, boolean isEncrypted, boolean 
isCompressed) {
-        this.isSigned = isSigned;
-        this.isEncrypted = isEncrypted;
-        this.isCompressed = isCompressed;
+    private AS2CompressionAlgorithm(OutputCompressor outputCompressor) {
+        this.outputCompressor = outputCompressor;
     }
 
-    public boolean isSigned() {
-        return isSigned;
+    public String getAlgorithmName() {
+        return this.name();
     }
-    public boolean isEncrypted() {
-        return isEncrypted;
+    
+    public ASN1ObjectIdentifier getAlgorithmOID() {
+        return outputCompressor.getAlgorithmIdentifier().getAlgorithm();
     }
-    public boolean isCompressed() {
-        return isCompressed;
+
+    public OutputCompressor getOutputCompressor() {
+        return outputCompressor;
     }
+
 }
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
index 3c8210a..760d9f0 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
@@ -18,9 +18,13 @@ package org.apache.camel.component.as2.api;
 
 public enum AS2MessageStructure {
     PLAIN(false, false, false),
-    SIGNED(false, false, false),
-    ENCRYPTED(false, false, false),
-    ENCRYPTED_SIGNED(false, false, false);
+    SIGNED(true, false, false),
+    ENCRYPTED(false, true, false),
+    SIGNED_ENCRYPTED(true, true, false),
+    PLAIN_COMPRESSED(false, false, true),
+    SIGNED_COMPRESSED(true, false, true),
+    ENCRYPTED_COMPRESSED(false, true, true),
+    SIGNED_ENCRYPTED_COMPRESSED(true, true, true);
 
     private final boolean isSigned;
     private final boolean isEncrypted;
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
similarity index 94%
rename from 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java
rename to 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
index 5487055..4bb9866 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEntity.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/ApplicationPkcs7MimeEnvelopedDataEntity.java
@@ -37,13 +37,13 @@ import org.bouncycastle.cms.CMSProcessableByteArray;
 import org.bouncycastle.cms.CMSTypedData;
 import org.bouncycastle.operator.OutputEncryptor;
 
-public class ApplicationPkcs7MimeEntity extends MimeEntity {
+public class ApplicationPkcs7MimeEnvelopedDataEntity extends MimeEntity {
     
     private static final String CONTENT_DISPOSITION = "attachment; 
filename=\"smime.p7m\"";
     
     private byte[] encryptedData;
     
-    public ApplicationPkcs7MimeEntity(MimeEntity entity2Encrypt,
+    public ApplicationPkcs7MimeEnvelopedDataEntity(MimeEntity entity2Encrypt,
                                 CMSEnvelopedDataGenerator dataGenerator,
                                 OutputEncryptor encryptor,
                                 String encryptedContentTransferEncoding,
@@ -61,7 +61,7 @@ public class ApplicationPkcs7MimeEntity extends MimeEntity {
         }
     }
     
-    public ApplicationPkcs7MimeEntity(byte[] encryptedData, String 
encryptedContentTransferEncoding, boolean isMainBody) {
+    public ApplicationPkcs7MimeEnvelopedDataEntity(byte[] encryptedData, 
String encryptedContentTransferEncoding, boolean isMainBody) {
         this.encryptedData = Args.notNull(encryptedData, "encryptedData");
         
         setContentType(ContentType.create("application/pkcs7-mime", new 
BasicNameValuePair("smime-type", "enveloped-datat"),
@@ -101,10 +101,7 @@ public class ApplicationPkcs7MimeEntity extends MimeEntity 
{
     }
     
     public MimeEntity getEncryptedEntity(PrivateKey privateKey) throws 
HttpException {
-        
         return EntityParser.parseEnvelopedEntity(encryptedData, privateKey);
-        
-        
     }
     
     private byte[] createEncryptedData(MimeEntity entity2Encrypt, 
CMSEnvelopedDataGenerator envelopedDataGenerator, OutputEncryptor encryptor) 
throws Exception {
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
index 4d8a2b2..5fb23f4 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
@@ -882,7 +882,7 @@ public final class EntityParser {
         }
     }
 
-    public static ApplicationPkcs7MimeEntity 
parseApplicationPkcs7MimeEntityBody(AS2SessionInputBuffer inbuffer,
+    public static ApplicationPkcs7MimeEnvelopedDataEntity 
parseApplicationPkcs7MimeEntityBody(AS2SessionInputBuffer inbuffer,
                                                                                
       String boundary,
                                                                                
       ContentType contentType,
                                                                                
       String contentTransferEncoding)
@@ -903,7 +903,7 @@ public final class EntityParser {
 
             byte[] encryptedContent = 
EntityUtils.decode(pkcs7EncryptedBodyContent.getBytes(charset), 
contentTransferEncoding);
 
-            ApplicationPkcs7MimeEntity applicationPkcs7MimeEntity = new 
ApplicationPkcs7MimeEntity(
+            ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEntity 
= new ApplicationPkcs7MimeEnvelopedDataEntity(
                     encryptedContent, contentTransferEncoding, false);
             return applicationPkcs7MimeEntity;
         } catch (Exception e) {
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java
similarity index 52%
copy from 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
copy to 
components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java
index 3c8210a..89e243f 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2MessageStructure.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/CompressionUtils.java
@@ -14,31 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.as2.api;
+package org.apache.camel.component.as2.api.util;
 
-public enum AS2MessageStructure {
-    PLAIN(false, false, false),
-    SIGNED(false, false, false),
-    ENCRYPTED(false, false, false),
-    ENCRYPTED_SIGNED(false, false, false);
+import org.apache.camel.component.as2.api.AS2CompressionAlgorithm;
+import org.bouncycastle.cms.CMSCompressedDataGenerator;
+import org.bouncycastle.operator.OutputCompressor;
 
-    private final boolean isSigned;
-    private final boolean isEncrypted;
-    private final boolean isCompressed;
-
-    private AS2MessageStructure(boolean isSigned, boolean isEncrypted, boolean 
isCompressed) {
-        this.isSigned = isSigned;
-        this.isEncrypted = isEncrypted;
-        this.isCompressed = isCompressed;
-    }
-
-    public boolean isSigned() {
-        return isSigned;
+public final class CompressionUtils {
+    
+    private CompressionUtils() {
     }
-    public boolean isEncrypted() {
-        return isEncrypted;
+    
+    public static CMSCompressedDataGenerator createCompressedDataGenerator() {
+        return new CMSCompressedDataGenerator();
     }
-    public boolean isCompressed() {
-        return isCompressed;
+    
+    public static OutputCompressor createCompressor(AS2CompressionAlgorithm 
compressionAlgorithm) {
+        return compressionAlgorithm.getOutputCompressor();
     }
+
 }
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
index 3cdd384..9a43f10 100644
--- 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java
@@ -32,7 +32,7 @@ import 
org.apache.camel.component.as2.api.entity.AS2DispositionType;
 import 
org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIFACTEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity;
 import org.apache.camel.component.as2.api.entity.DispositionMode;
 import 
org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity;
@@ -270,7 +270,7 @@ public class AS2MessageTest {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.PLAIN, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, null, null, null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, 
request.getRequestLine().getMethod());
@@ -313,8 +313,8 @@ public class AS2MessageTest {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.SIGNED, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(),
+                null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, 
request.getRequestLine().getMethod());
@@ -472,10 +472,11 @@ public class AS2MessageTest {
         LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
-                AS2MessageStructure.ENCRYPTED, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, 
certList.toArray(new Certificate[0]),
-                signingKP.getPrivate());
+                AS2MessageStructure.ENCRYPTED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, 
AS2Charset.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new 
Certificate[0]), signingKP.getPrivate(), null,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, 
encryptionAlgorithm,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate());
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, 
request.getRequestLine().getMethod());
@@ -503,8 +504,8 @@ public class AS2MessageTest {
         assertTrue("Request does not contain entity", request instanceof 
BasicHttpEntityEnclosingRequest);
         HttpEntity entity = ((BasicHttpEntityEnclosingRequest) 
request).getEntity();
         assertNotNull("Request does not contain entity", entity);
-        assertTrue("Unexpected request entity type", entity instanceof 
ApplicationPkcs7MimeEntity);
-        ApplicationPkcs7MimeEntity envelopedEntity = 
(ApplicationPkcs7MimeEntity) entity;
+        assertTrue("Unexpected request entity type", entity instanceof 
ApplicationPkcs7MimeEnvelopedDataEntity);
+        ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = 
(ApplicationPkcs7MimeEnvelopedDataEntity) entity;
         assertTrue("Entity not set as main body of request", 
envelopedEntity.isMainBody());
 
         // Validated enveloped part.
@@ -532,10 +533,11 @@ public class AS2MessageTest {
         LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm());
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
-                AS2MessageStructure.ENCRYPTED_SIGNED, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, 
certList.toArray(new Certificate[0]),
-                signingKP.getPrivate());
+                AS2MessageStructure.SIGNED_ENCRYPTED,
+                ContentType.create(AS2MediaType.APPLICATION_EDIFACT, 
AS2Charset.US_ASCII), null,
+                AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new 
Certificate[0]), signingKP.getPrivate(), null,
+                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, 
encryptionAlgorithm,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate());
 
         HttpRequest request = httpContext.getRequest();
         assertEquals("Unexpected method value", METHOD, 
request.getRequestLine().getMethod());
@@ -563,8 +565,8 @@ public class AS2MessageTest {
         assertTrue("Request does not contain entity", request instanceof 
BasicHttpEntityEnclosingRequest);
         HttpEntity entity = ((BasicHttpEntityEnclosingRequest) 
request).getEntity();
         assertNotNull("Request does not contain entity", entity);
-        assertTrue("Unexpected request entity type", entity instanceof 
ApplicationPkcs7MimeEntity);
-        ApplicationPkcs7MimeEntity envelopedEntity = 
(ApplicationPkcs7MimeEntity) entity;
+        assertTrue("Unexpected request entity type", entity instanceof 
ApplicationPkcs7MimeEnvelopedDataEntity);
+        ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity = 
(ApplicationPkcs7MimeEnvelopedDataEntity) entity;
         assertTrue("Entity not set as main body of request", 
envelopedEntity.isMainBody());
 
         // Validated enveloped part.
@@ -601,8 +603,8 @@ public class AS2MessageTest {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.SIGNED, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
DISPOSITION_NOTIFICATION_TO,
-                SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, AS2SignatureAlgorithm.SHA256WITHRSA, 
certList.toArray(new Certificate[0]), signingKP.getPrivate(),
+                null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         HttpRequest request = httpContext.getRequest();
         assertTrue("Request does not contain entity", request instanceof 
BasicHttpEntityEnclosingRequest);
@@ -630,7 +632,8 @@ public class AS2MessageTest {
 
         HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, 
REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME,
                 AS2MessageStructure.PLAIN, 
ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII),
-                null, null, null, null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
+                null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null,
+                null);
 
         HttpResponse response = httpContext.getResponse();
         assertEquals("Unexpected method value", HttpVersion.HTTP_1_1, 
response.getStatusLine().getProtocolVersion());
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
index cd47c82..d5b3a0d 100644
--- 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
@@ -317,7 +317,7 @@ public class EntityParserTest {
         // Build Enveloped Entity
         //
         TextPlainEntity textEntity = new TextPlainEntity("This is a super 
secret messatge!", "US-ASCII", "7bit", false);
-        ApplicationPkcs7MimeEntity applicationPkcs7MimeEntity = new 
ApplicationPkcs7MimeEntity(textEntity, cmsEnvelopeDataGenerator, 
contentEncryptor, "binary", true);
+        ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEntity = 
new ApplicationPkcs7MimeEnvelopedDataEntity(textEntity, 
cmsEnvelopeDataGenerator, contentEncryptor, "binary", true);
         
         MimeEntity decryptedMimeEntity = 
applicationPkcs7MimeEntity.getEncryptedEntity(encryptKP.getPrivate());
         assertEquals("Decrypted entity has unexpected content type", 
"text/plain; charset=US-ASCII", decryptedMimeEntity.getContentTypeValue());
diff --git 
a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc 
b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
index aef14ca..11bfb22 100644
--- a/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
+++ b/components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc
@@ -70,7 +70,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (30 parameters):
+==== Query Parameters (31 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -81,6 +81,7 @@ with the following path and query parameters:
 | *as2To* (common) | The value of the AS2To header of AS2 message. |  | String
 | *as2Version* (common) | The version of the AS2 protocol. | 1.1 | String
 | *clientFqdn* (common) | The Client Fully Qualified Domain Name (FQDN). Used 
in message ids sent by endpoint. | camel.apache.org | String
+| *compressionAlgorithm* (common) | The algorithm used to compress EDI 
message. |  | AS2Compression Algorithm
 | *dispositionNotificationTo* (common) | The value of the 
Disposition-Notification-To header. Assigning a value to this parameter 
requests a message disposition notification (MDN) for the AS2 message. |  | 
String
 | *ediMessageTransferEncoding* (common) | The transfer encoding of EDI 
message. |  | String
 | *ediMessageType* (common) | The content type of EDI message. One of 
application/edifact, application/edi-x12, application/edi-consent |  | 
ContentType
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
index bd5a347..c92b50e 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
@@ -20,6 +20,7 @@ import java.security.PrivateKey;
 import java.security.cert.Certificate;
 
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.as2.api.AS2CompressionAlgorithm;
 import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm;
 import org.apache.camel.component.as2.api.AS2MessageStructure;
 import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
@@ -102,6 +103,9 @@ public class AS2Configuration {
     private PrivateKey signingPrivateKey;
 
     @UriParam
+    private AS2CompressionAlgorithm compressionAlgorithm;
+
+    @UriParam
     private String dispositionNotificationTo;
 
     @UriParam
@@ -388,6 +392,17 @@ public class AS2Configuration {
         this.signingPrivateKey = signingPrivateKey;
     }
 
+    public AS2CompressionAlgorithm getCompressionAlgorithm() {
+        return compressionAlgorithm;
+    }
+
+    /**
+     * The algorithm used to compress EDI message.
+     */
+    public void setCompressionAlgorithm(AS2CompressionAlgorithm 
compressionAlgorithm) {
+        this.compressionAlgorithm = compressionAlgorithm;
+    }
+
     public String getDispositionNotificationTo() {
         return dispositionNotificationTo;
     }
@@ -415,7 +430,7 @@ public class AS2Configuration {
         this.signedReceiptMicAlgorithms = signedReceiptMicAlgorithms;
     }
 
-    public AS2EncryptionAlgorithm getEncryptingingAlgorithm() {
+    public AS2EncryptionAlgorithm getEncryptingAlgorithm() {
         return encryptingAlgorithm;
     }
 
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
index ca14bf6..36c0386 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java
@@ -45,7 +45,7 @@ import 
org.apache.camel.component.as2.api.entity.AS2DispositionModifier;
 import org.apache.camel.component.as2.api.entity.AS2DispositionType;
 import 
org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity;
 import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity;
-import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEntity;
+import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
 import 
org.apache.camel.component.as2.api.entity.ApplicationPkcs7SignatureEntity;
 import org.apache.camel.component.as2.api.entity.DispositionMode;
 import 
org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity;
@@ -326,8 +326,8 @@ public class AS2ClientManagerIntegrationTest extends 
AbstractAS2TestSupport {
         assertTrue("Request does not contain body", request instanceof 
HttpEntityEnclosingRequest);
         HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
         assertNotNull("Request body", entity);
-        assertTrue("Request body does not contain ApplicationPkcs7Mime 
entity", entity instanceof ApplicationPkcs7MimeEntity);
-        MimeEntity envelopeEntity = 
((ApplicationPkcs7MimeEntity)entity).getEncryptedEntity(signingKP.getPrivate());
+        assertTrue("Request body does not contain ApplicationPkcs7Mime 
entity", entity instanceof ApplicationPkcs7MimeEnvelopedDataEntity);
+        MimeEntity envelopeEntity = 
((ApplicationPkcs7MimeEnvelopedDataEntity)entity).getEncryptedEntity(signingKP.getPrivate());
         assertTrue("Enveloped entity is not an EDI entity", envelopeEntity 
instanceof ApplicationEDIEntity);
         String ediMessage = 
((ApplicationEDIEntity)envelopeEntity).getEdiMessage();
         assertEquals("EDI message is different", 
EDI_MESSAGE.replaceAll("[\n\r]", ""), ediMessage.replaceAll("[\n\r]", ""));
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
index 9cb635f..0f6b931 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java
@@ -128,7 +128,7 @@ public class AS2ServerManagerIntegrationTest extends 
AbstractAS2TestSupport {
 
         clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, 
AS2_NAME, AS2MessageStructure.PLAIN,
                 ContentType.create(AS2MediaType.APPLICATION_EDIFACT, 
AS2Charset.US_ASCII), null, null, null, null,
-                DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, 
null, null, null);
+                null, DISPOSITION_NOTIFICATION_TO, 
SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs");
         mockEndpoint.expectedMinimumMessageCount(1);
@@ -185,7 +185,7 @@ public class AS2ServerManagerIntegrationTest extends 
AbstractAS2TestSupport {
 
         clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, 
AS2_NAME, AS2MessageStructure.SIGNED,
                 ContentType.create(AS2MediaType.APPLICATION_EDIFACT, 
AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA,
-                certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
DISPOSITION_NOTIFICATION_TO,
+                certList.toArray(new Certificate[0]), signingKP.getPrivate(), 
null, DISPOSITION_NOTIFICATION_TO,
                 SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null);
 
         MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs");
diff --git 
a/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java
index d5d84d5..eda444f 100644
--- 
a/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-as2-starter/src/main/java/org/apache/camel/component/as2/springboot/AS2ComponentConfiguration.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.as2.springboot;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import javax.annotation.Generated;
+import org.apache.camel.component.as2.api.AS2CompressionAlgorithm;
 import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm;
 import org.apache.camel.component.as2.api.AS2MessageStructure;
 import org.apache.camel.component.as2.api.AS2SignatureAlgorithm;
@@ -167,6 +168,10 @@ public class AS2ComponentConfiguration
          */
         private PrivateKey signingPrivateKey;
         /**
+         * The algorithm used to compress EDI message.
+         */
+        private AS2CompressionAlgorithm compressionAlgorithm;
+        /**
          * The value of the Disposition-Notification-To header. Assigning a
          * value to this parameter requests a message disposition notification
          * (MDN) for the AS2 message.
@@ -362,6 +367,15 @@ public class AS2ComponentConfiguration
             this.signingPrivateKey = signingPrivateKey;
         }
 
+        public AS2CompressionAlgorithm getCompressionAlgorithm() {
+            return compressionAlgorithm;
+        }
+
+        public void setCompressionAlgorithm(
+                AS2CompressionAlgorithm compressionAlgorithm) {
+            this.compressionAlgorithm = compressionAlgorithm;
+        }
+
         public String getDispositionNotificationTo() {
             return dispositionNotificationTo;
         }

Reply via email to