You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/04/07 13:43:54 UTC

[camel-quarkus] 04/04: Improve mail test coverage #3674

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

jamesnetherton pushed a commit to branch 2.7.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 858b9e73fab7fb0649da8baf8cd2bd21b649bb19
Author: JiriOndrusek <on...@gmail.com>
AuthorDate: Tue Apr 5 09:48:49 2022 +0200

    Improve mail test coverage #3674
---
 integration-tests/mail/pom.xml                     |  58 ++++-
 .../quarkus/component/mail/CamelResource.java      | 188 +++++++++++++-
 .../camel/quarkus/component/mail/CamelRoute.java   | 205 ++++++++++++++-
 .../camel/quarkus/component/mail/MockMailbox.java  |  55 ----
 .../mail/src/main/resources/application.properties |  17 ++
 .../mail/src/main/resources/data/logo.jpeg         | Bin 0 -> 10249 bytes
 .../camel/quarkus/component/mail/MailTest.java     | 283 +++++++++++++++++++--
 .../quarkus/component/mail/MailTestResource.java   |  88 +++++++
 pom.xml                                            |   2 +
 poms/bom-test/pom.xml                              |   6 +
 poms/bom/src/main/generated/flattened-full-pom.xml |  22 +-
 .../generated/flattened-reduced-verbose-pom.xml    |  22 +-
 12 files changed, 824 insertions(+), 122 deletions(-)

diff --git a/integration-tests/mail/pom.xml b/integration-tests/mail/pom.xml
index 2d0fb26678..d3f43fc6da 100644
--- a/integration-tests/mail/pom.xml
+++ b/integration-tests/mail/pom.xml
@@ -39,20 +39,18 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-direct</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-seda</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.jvnet.mock-javamail</groupId>
-            <artifactId>mock-javamail</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>junit</groupId>
-                    <artifactId>junit</artifactId>
-                </exclusion>
-            </exclusions>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy-jsonb</artifactId>
         </dependency>
 
         <!-- test dependencies -->
@@ -72,7 +70,38 @@
                 </exclusion>
             </exclusions>
         </dependency>
-
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>junit</artifactId>
+                    <groupId>junit</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.icegreen</groupId>
+            <artifactId>greenmail</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <artifactId>junit</artifactId>
+                    <groupId>junit</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit4-mock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -149,6 +178,17 @@
                 </dependency>
             </dependencies>
         </profile>
+        <profile>
+            <id>skip-testcontainers-tests</id>
+            <activation>
+                <property>
+                    <name>skip-testcontainers-tests</name>
+                </property>
+            </activation>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </profile>
     </profiles>
 
 
diff --git a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelResource.java b/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelResource.java
index 0bc7b44a17..a1e9f671f7 100644
--- a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelResource.java
+++ b/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelResource.java
@@ -16,44 +16,129 @@
  */
 package org.apache.camel.quarkus.component.mail;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.activation.FileDataSource;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
+import javax.inject.Named;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
 import javax.mail.util.ByteArrayDataSource;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import com.sun.mail.imap.SortTerm;
+import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.ServiceStatus;
 import org.apache.camel.attachment.AttachmentMessage;
 import org.apache.camel.attachment.DefaultAttachment;
+import org.apache.camel.component.mail.DefaultJavaMailSender;
+import org.apache.camel.component.mail.JavaMailSender;
+import org.apache.camel.component.mail.MailSorter;
 
 @Path("/mail")
 @ApplicationScoped
 public class CamelResource {
 
     @Inject
-    ProducerTemplate template;
+    ProducerTemplate producerTemplate;
+
+    @Inject
+    CamelContext camelContext;
+
+    @Inject
+    @Named("mailReceivedMessages")
+    List<Map<String, Object>> mailReceivedMessages;
+
+    @Path("/send")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    public void sendMail(
+            @QueryParam("subject") String subject,
+            @QueryParam("from") String from,
+            @QueryParam("to") String to,
+            @QueryParam("secured") Boolean secured,
+            String body) {
+
+        String path = (secured != null && secured) ? "sendMailSecured" : "sendMail";
+        producerTemplate.send("direct:" + path, exchange -> {
+            org.apache.camel.Message message = exchange.getMessage();
+            message.setHeader("Subject", subject);
+            message.setHeader("From", from);
+            message.setHeader("To", to);
+            message.setBody(body);
+        });
+    }
+
+    @Path("/send/attachment/{fileName}")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    public void sendMailWithAttachment(
+            @PathParam("fileName") String fileName,
+            @QueryParam("subject") String subject,
+            @QueryParam("from") String from,
+            @QueryParam("to") String to,
+            String body) {
+
+        producerTemplate.send("direct:sendMail", exchange -> {
+            AttachmentMessage in = exchange.getMessage(AttachmentMessage.class);
+
+            DefaultAttachment attachment;
+            if (fileName.startsWith("/")) {
+                attachment = new DefaultAttachment(new FileDataSource(fileName));
+            } else {
+                attachment = new DefaultAttachment(
+                        new ByteArrayDataSource(
+                                Thread.currentThread().getContextClassLoader().getResourceAsStream("data/" + fileName),
+                                "image/jpeg"));
+            }
+
+            in.addAttachmentObject(fileName, attachment);
+
+            org.apache.camel.Message message = exchange.getMessage();
+            message.setHeader("Subject", subject);
+            message.setHeader("From", from);
+            message.setHeader("To", to);
+            message.setBody(body);
+        });
+    }
 
-    @Path("/route/{route}")
+    @Path("/mimeMultipartUnmarshalMarshal")
     @POST
     @Consumes(MediaType.TEXT_PLAIN)
     @Produces(MediaType.TEXT_PLAIN)
-    public String route(String statement, @PathParam("route") String route) throws Exception {
-        return template.requestBody("direct:" + route, statement, String.class);
+    public String mimeMultipartUnmarshalMarshal(String body) {
+        return producerTemplate.requestBody("direct:mimeMultipartUnmarshalMarshal", body, String.class);
     }
 
     @Path("/mimeMultipartMarshal/{fileName}/{fileContent}")
     @POST
     @Consumes(MediaType.TEXT_PLAIN)
     @Produces(MediaType.TEXT_PLAIN)
-    public String mimeMultipart(String body, @PathParam("fileName") String fileName,
-            @PathParam("fileContent") String fileContent) throws Exception {
+    public String mimeMultipart(
+            @PathParam("fileName") String fileName,
+            @PathParam("fileContent") String fileContent,
+            String body) {
 
-        return template.request("direct:mimeMultipartMarshal", e -> {
+        return producerTemplate.request("direct:mimeMultipartMarshal", e -> {
             AttachmentMessage in = e.getMessage(AttachmentMessage.class);
             in.setBody(body);
             in.setHeader(Exchange.CONTENT_TYPE, "text/plain;charset=iso8859-1;other-parameter=true");
@@ -67,4 +152,93 @@ public class CamelResource {
         }).getMessage().getBody(String.class);
     }
 
+    // ------------------------------------------------
+
+    @Path("/getReceived")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<Map<String, Object>> getReceived() {
+        return mailReceivedMessages;
+    }
+
+    @Path("/getReceivedAsString")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<Map<String, Object>> getReceivedAsString() throws MessagingException, IOException {
+        List<Map<String, Object>> result = new LinkedList();
+        for (Map<String, Object> email : mailReceivedMessages) {
+            InputStream is = (InputStream) email.get("convertedStream");
+            result.add(Collections.singletonMap("body", camelContext.getTypeConverter().convertTo(String.class, is)));
+        }
+        mailReceivedMessages.clear();
+        return result;
+
+    }
+
+    @Path("/clear")
+    @GET
+    public void clear() {
+        mailReceivedMessages.clear();
+    }
+
+    @GET
+    @Path("/route/{routeId}/{operation}")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String controlRoute(@PathParam("routeId") String routeId, @PathParam("operation") String operation)
+            throws Exception {
+        switch (operation) {
+        case "stop":
+            camelContext.getRouteController().stopRoute(routeId);
+            break;
+        case "start":
+            camelContext.getRouteController().startRoute(routeId);
+            break;
+        case "status":
+            return camelContext.getRouteController().getRouteStatus(routeId).name();
+        }
+        return null;
+    }
+
+    @GET
+    @Path("/stopConsumers")
+    @Produces(MediaType.TEXT_PLAIN)
+    public void stopConsumers()
+            throws Exception {
+        Arrays.stream(CamelRoute.Routes.values()).forEach(r -> {
+            try {
+                if (camelContext.getRouteController().getRouteStatus(r.name()) == ServiceStatus.Started) {
+                    camelContext.getRouteController().stopRoute(r.name());
+                }
+            } catch (Exception e) {
+                //ignore
+            }
+        });
+    }
+
+    @Path("/sort")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<String> sort(List<String> messages) throws Exception {
+        JavaMailSender sender = new DefaultJavaMailSender();
+        // inserts new messages
+        Message[] msgs = new Message[messages.size()];
+        int i = 0;
+        for (String msg : messages) {
+            msgs[i] = new MimeMessage(sender.getSession());
+            msgs[i].setHeader("Subject", msg);
+            msgs[i++].setText(msg);
+        }
+        MailSorter.sortMessages(msgs, new SortTerm[] {
+                SortTerm.SUBJECT });
+
+        return Stream.of(msgs).map(m -> {
+            try {
+                return String.valueOf(m.getContent());
+            } catch (Exception e) {
+                return "error";
+            }
+        }).collect(Collectors.toList());
+    }
+
 }
diff --git a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelRoute.java b/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelRoute.java
index 6efc00ee7b..b48c9e491d 100644
--- a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelRoute.java
+++ b/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/CamelRoute.java
@@ -16,38 +16,215 @@
  */
 package org.apache.camel.quarkus.component.mail;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.CopyOnWriteArrayList;
 
+import javax.activation.DataHandler;
+import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.inject.Produces;
-import javax.mail.Session;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObjectBuilder;
+import javax.mail.Folder;
+import javax.mail.MessagingException;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.attachment.AttachmentMessage;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.mail.MailComponent;
+import org.apache.camel.component.mail.MailConverters;
+import org.apache.camel.component.mail.MailMessage;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 
+@ApplicationScoped
 public class CamelRoute extends RouteBuilder {
+
+    enum Routes {
+        convertersRoute, batchReceiveRoute, imapReceiveRoute, imapsReceiveRoute, pop3ReceiveRoute, pop3sReceiveRoute;
+    }
+
+    @Inject
+    @Named("mailReceivedMessages")
+    List<Map<String, Object>> mailReceivedMessages;
+
+    @Inject
+    CamelContext camelContext;
+
+    static final String EMAIL_ADDRESS = "test@localhost";
+    static final String USERNAME = "test";
+    static final String PASSWORD = "s3cr3t";
+
+    @ConfigProperty(name = "mail.smtp.port")
+    int smtpPort;
+
+    @ConfigProperty(name = "mail.smtps.port")
+    int smtpsPort;
+
+    @ConfigProperty(name = "mail.pop3.port")
+    int pop3Port;
+
+    @ConfigProperty(name = "mail.pop3s.port")
+    int pop3sPort;
+
+    @ConfigProperty(name = "mail.imap.port")
+    int imapPort;
+
+    @ConfigProperty(name = "mail.imaps.port")
+    int imapsPort;
+
     @Override
     public void configure() {
-        bindToRegistry("smtp", smtp());
 
-        from("direct:mailtext")
-                .setHeader("Subject", constant("Hello World"))
-                .setHeader("To", constant("james@localhost"))
-                .setHeader("From", constant("claus@localhost"))
-                .to("smtp://localhost?initialDelay=100&delay=100");
+        from("direct:sendMail")
+                .toF("smtp://localhost:%d?username=%s&password=%s", smtpPort, USERNAME, PASSWORD);
+
+        from("direct:sendMailSecured").toF(
+                "smtps://localhost:%d?username=%s&password=%s&sslContextParameters=#sslContextParameters&additionalJavaMailProperties=#additionalProperties",
+                smtpsPort, USERNAME, PASSWORD);
 
         from("direct:mimeMultipartMarshal")
                 .marshal().mimeMultipart();
+
         from("direct:mimeMultipartUnmarshalMarshal")
                 .unmarshal().mimeMultipart()
                 .marshal().mimeMultipart();
 
+        fromF("pop3://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s&delete=true", pop3Port, USERNAME,
+                PASSWORD)
+                        .id(Routes.pop3ReceiveRoute.name())
+                        .autoStartup(false)
+                        .process(exchange -> handleMail(exchange));
+
+        fromF("pop3s://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s&delete=true&sslContextParameters=#sslContextParameters&additionalJavaMailProperties=#additionalProperties",
+                pop3sPort, USERNAME,
+                PASSWORD)
+                        .id(Routes.pop3sReceiveRoute.name())
+                        .autoStartup(false)
+                        .process(exchange -> handleMail(exchange));
+
+        fromF("imap://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s&delete=true", imapPort, USERNAME,
+                PASSWORD)
+                        .id(Routes.imapReceiveRoute.name())
+                        .autoStartup(false)
+                        .process(exchange -> handleMail(exchange));
+
+        fromF("imaps://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s&delete=true&sslContextParameters=#sslContextParameters&additionalJavaMailProperties=#additionalProperties",
+                imapsPort, USERNAME,
+                PASSWORD)
+                        .id(Routes.imapsReceiveRoute.name())
+                        .autoStartup(false)
+                        .process(exchange -> handleMail(exchange));
+
+        fromF("pop3://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s"
+                + "&delete=true&maxMessagesPerPoll=3", pop3Port, USERNAME, PASSWORD)
+                        .id(Routes.batchReceiveRoute.name())
+                        .autoStartup(false)
+                        .process(e -> {
+                            Map<String, Object> map = handleMail(e);
+                            map.put(ExchangePropertyKey.BATCH_INDEX.getName(), e.getProperty(ExchangePropertyKey.BATCH_INDEX));
+                            map.put(ExchangePropertyKey.BATCH_COMPLETE.getName(),
+                                    e.getProperty(ExchangePropertyKey.BATCH_COMPLETE));
+                            map.put(ExchangePropertyKey.BATCH_SIZE.getName(), e.getProperty(ExchangePropertyKey.BATCH_SIZE));
+                        });
+
+        fromF("pop3://localhost:%d?initialDelay=100&delay=500&username=%s&password=%s&delete=true", pop3Port, USERNAME,
+                PASSWORD)
+                        .id(Routes.convertersRoute.name())
+                        .autoStartup(false)
+                        .process(e -> {
+                            MailConverters.toInputStream(e.getIn().getBody(MailMessage.class).getMessage());
+                            InputStream is = MailConverters.toInputStream(e.getIn().getBody(MailMessage.class).getMessage());
+                            Map<String, Object> map = handleMail(e);
+                            map.put("convertedStream", is);
+                        });
+
+    }
+
+    private Map<String, Object> handleMail(Exchange exchange) throws MessagingException {
+        Map<String, Object> result = new HashMap<>();
+        MailMessage mailMessage = exchange.getMessage(MailMessage.class);
+        AttachmentMessage attachmentMessage = exchange.getMessage(AttachmentMessage.class);
+        Map<String, DataHandler> attachments = attachmentMessage.getAttachments();
+        if (attachments != null) {
+            JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
+            attachments.forEach((id, dataHandler) -> {
+                JsonObjectBuilder attachmentObject = Json.createObjectBuilder();
+                attachmentObject.add("attachmentFilename", dataHandler.getName());
+                attachmentObject.add("attachmentContentType", dataHandler.getContentType());
+
+                if (dataHandler.getName().endsWith(".txt")) {
+                    try {
+                        String content = camelContext.getTypeConverter().convertTo(String.class,
+                                dataHandler.getInputStream());
+                        attachmentObject.add("attachmentContent", content);
+                    } catch (IOException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+
+                arrayBuilder.add(attachmentObject.build());
+            });
+
+            result.put("attachments", arrayBuilder.build());
+        }
+
+        Folder folder = mailMessage.getOriginalMessage().getFolder();
+        if (!folder.isOpen()) {
+            folder.open(Folder.READ_ONLY);
+        }
+
+        result.put("subject", mailMessage.getMessage().getSubject());
+        result.put("content", mailMessage.getBody(String.class).trim());
+
+        mailReceivedMessages.add(result);
+
+        return result;
     }
 
-    @Produces
-    MailComponent smtp() {
-        MailComponent mail = new MailComponent(getContext());
-        Session session = Session.getInstance(new Properties());
-        mail.getConfiguration().setSession(session);
-        return mail;
+    static class Producers {
+
+        @Singleton
+        @Produces
+        @Named("mailReceivedMessages")
+        List<Map<String, Object>> mailReceivedMessages() {
+            return new CopyOnWriteArrayList<>();
+        }
+
+        @Singleton
+        @Named
+        public SSLContextParameters sslContextParameters() {
+            TrustManagersParameters trustManagersParameters = new TrustManagersParameters();
+            SSLContextParameters sslContextParameters = new SSLContextParameters();
+            sslContextParameters.setTrustManagers(trustManagersParameters);
+
+            KeyManagersParameters keyManagersParameters = new KeyManagersParameters();
+            sslContextParameters.setKeyManagers(keyManagersParameters);
+
+            return sslContextParameters;
+        }
+
+        @Singleton
+        @Named
+        public Properties additionalProperties() {
+            Properties prop = new Properties();
+
+            prop.setProperty("mail.smtps.ssl.trust", "*");
+            prop.setProperty("mail.pop3s.ssl.trust", "*");
+            prop.setProperty("mail.imaps.ssl.trust", "*");
+
+            return prop;
+        }
     }
 }
diff --git a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/MockMailbox.java b/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/MockMailbox.java
deleted file mode 100644
index c0e16e5649..0000000000
--- a/integration-tests/mail/src/main/java/org/apache/camel/quarkus/component/mail/MockMailbox.java
+++ /dev/null
@@ -1,55 +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.camel.quarkus.component.mail;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-import org.jvnet.mock_javamail.Mailbox;
-
-@Path("/mock/{username}")
-@ApplicationScoped
-public class MockMailbox {
-
-    @GET
-    @Path("/size")
-    @Produces(MediaType.TEXT_PLAIN)
-    public String getSize(@PathParam("username") String username) throws Exception {
-        Mailbox mailbox = Mailbox.get(username);
-        return Integer.toString(mailbox.size());
-    }
-
-    @GET
-    @Path("/{id}/content")
-    @Produces(MediaType.TEXT_PLAIN)
-    public String getContent(@PathParam("username") String username, @PathParam("id") int id) throws Exception {
-        Mailbox mailbox = Mailbox.get(username);
-        return mailbox.get(id).getContent().toString();
-    }
-
-    @GET
-    @Path("/{id}/subject")
-    @Produces(MediaType.TEXT_PLAIN)
-    public String getSubject(@PathParam("username") String username, @PathParam("id") int id) throws Exception {
-        Mailbox mailbox = Mailbox.get(username);
-        return mailbox.get(id).getSubject();
-    }
-}
diff --git a/integration-tests/mail/src/main/resources/application.properties b/integration-tests/mail/src/main/resources/application.properties
new file mode 100644
index 0000000000..7508c1d5ed
--- /dev/null
+++ b/integration-tests/mail/src/main/resources/application.properties
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+quarkus.native.resources.includes = data/logo.jpeg
\ No newline at end of file
diff --git a/integration-tests/mail/src/main/resources/data/logo.jpeg b/integration-tests/mail/src/main/resources/data/logo.jpeg
new file mode 100644
index 0000000000..b635017d1e
Binary files /dev/null and b/integration-tests/mail/src/main/resources/data/logo.jpeg differ
diff --git a/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTest.java b/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTest.java
index 359e87a03f..3503fea28e 100644
--- a/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTest.java
+++ b/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTest.java
@@ -16,18 +16,43 @@
  */
 package org.apache.camel.quarkus.component.mail;
 
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
+import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.ServiceStatus;
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.testcontainers.shaded.org.awaitility.Awaitility;
 
-import static org.hamcrest.core.Is.is;
+import static org.apache.camel.quarkus.component.mail.CamelRoute.EMAIL_ADDRESS;
+import static org.apache.camel.quarkus.component.mail.CamelRoute.PASSWORD;
+import static org.apache.camel.quarkus.component.mail.CamelRoute.USERNAME;
 
 @QuarkusTest
+@QuarkusTestResource(MailTestResource.class)
 public class MailTest {
     private static final Pattern DELIMITER_PATTERN = Pattern.compile("\r\n[^\r\n]+");
     private static final String EXPECTED_TEMPLATE = "${delimiter}\r\n"
@@ -45,27 +70,79 @@ public class MailTest {
             + "Hello attachment!"
             + "${delimiter}--\r\n";
 
-    @Test
-    public void testSendAsMail() {
+    @BeforeEach
+    public void beforeEach() {
+        // Configure users
+        Config config = ConfigProvider.getConfig();
+        String userJson = String.format("{ \"email\": \"%s\", \"login\": \"%s\", \"password\": \"%s\"}", EMAIL_ADDRESS,
+                USERNAME, PASSWORD);
         RestAssured.given()
-                .contentType(ContentType.TEXT)
-                .body("Hi how are you")
-                .post("/mail/route/mailtext")
+                .contentType(ContentType.JSON)
+                .body(userJson)
+                .post("http://localhost:" + config.getValue("mail.api.port", Integer.class) + "/api/user")
                 .then()
                 .statusCode(200);
+    }
 
+    @AfterEach
+    public void afterEach() {
+        // Clear mailboxes
+        Config config = ConfigProvider.getConfig();
         RestAssured.given()
-                .get("/mock/{username}/size", "james@localhost")
+                .port(config.getValue("mail.api.port", Integer.class))
+                .post("/api/service/reset")
                 .then()
-                .body(is("1"));
-        RestAssured.given()
-                .get("/mock/{username}/{id}/content", "james@localhost", 0)
+                .statusCode(200)
+                .body("message", Matchers.is("Performed reset"));
+
+        RestAssured.get("/mail/stopConsumers")
+                .then()
+                .statusCode(204);
+
+        RestAssured.get("/mail/clear")
                 .then()
-                .body(is("Hi how are you"));
+                .statusCode(204);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "pop3", "imap" })
+    public void receive(String protocol) {
+        //start route
+        startRoute("pop3".equals(protocol) ? CamelRoute.Routes.pop3ReceiveRoute : CamelRoute.Routes.imapReceiveRoute);
+
+        send(false);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "pop3s", "imaps" })
+    public void receiveSecured(String protocol) {
+        //start route
+        startRoute("pop3s".equals(protocol) ? CamelRoute.Routes.pop3sReceiveRoute : CamelRoute.Routes.imapsReceiveRoute);
+
+        send(true);
+    }
+
+    private void send(boolean secured) {
         RestAssured.given()
-                .get("/mock/{username}/{id}/subject", "james@localhost", 0)
+                .contentType(ContentType.TEXT)
+                .queryParam("subject", "Hello World")
+                .queryParam("from", "camel@localhost")
+                .queryParam("to", EMAIL_ADDRESS)
+                .queryParam("secured", secured)
+                .body("Hi how are you")
+                .post("/mail/send")
                 .then()
-                .body(is("Hello World"));
+                .statusCode(204);
+
+        Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> {
+            //receive
+            return (List<Map<String, Object>>) RestAssured.get("/mail/getReceived/")
+                    .then()
+                    .statusCode(200)
+                    .extract().as(List.class);
+        }, list -> list.size() == 1
+                && "Hi how are you".equals(list.get(0).get("content"))
+                && "Hello World".equals(list.get(0).get("subject")));
     }
 
     @Test
@@ -82,13 +159,12 @@ public class MailTest {
         final String unmarshalMarshal = RestAssured.given()
                 .contentType(ContentType.TEXT)
                 .body(actual)
-                .post("/mail/route/mimeMultipartUnmarshalMarshal")
+                .post("/mail/mimeMultipartUnmarshalMarshal")
                 .then()
                 .statusCode(200)
                 .extract().body().asString();
 
         assertMultipart(EXPECTED_TEMPLATE, unmarshalMarshal);
-
     }
 
     private void assertMultipart(final String expectedPattern, final String actual) {
@@ -101,4 +177,181 @@ public class MailTest {
         Assertions.assertEquals(expected, actual);
     }
 
+    @Test
+    public void testAttachments() throws IOException, URISyntaxException {
+        startRoute(CamelRoute.Routes.pop3ReceiveRoute);
+
+        String mailBodyContent = "Test mail content";
+        String attachmentContent = "Attachment " + mailBodyContent;
+        java.nio.file.Path attachmentPath = Files.createTempFile("cq-attachment", ".txt");
+        Files.write(attachmentPath, attachmentContent.getBytes(StandardCharsets.UTF_8));
+
+        try {
+            RestAssured.given()
+                    .contentType(ContentType.TEXT)
+                    .queryParam("subject", "Test attachment message")
+                    .queryParam("from", "camel@localhost")
+                    .queryParam("to", EMAIL_ADDRESS)
+                    .body(mailBodyContent)
+                    .post("/mail/send/attachment/{fileName}", attachmentPath.toAbsolutePath().toString())
+                    .then()
+                    .statusCode(204);
+
+            RestAssured.given()
+                    .contentType(ContentType.TEXT)
+                    .queryParam("subject", "Test attachment message")
+                    .queryParam("from", "camel@localhost")
+                    .queryParam("to", EMAIL_ADDRESS)
+                    .body(mailBodyContent)
+                    .post("/mail/send/attachment/{fileName}", "logo.jpeg")
+                    .then()
+                    .statusCode(204);
+
+            Awaitility.await().atMost(20, TimeUnit.SECONDS).until(() -> {
+                return (List<Map<String, Object>>) RestAssured.get("/mail/getReceived/")
+                        .then()
+                        .statusCode(200)
+                        .extract().as(List.class);
+            },
+                    list -> {
+                        if (list.size() == 2) {
+                            Map<String, Object> msg1 = list.get(0);
+                            List<Map<String, Object>> attch1 = (List<Map<String, Object>>) msg1.get("attachments");
+                            Map<String, Object> msg2 = list.get(1);
+                            List<Map<String, Object>> attch2 = (List<Map<String, Object>>) msg2.get("attachments");
+
+                            return "Test mail content".equals(msg1.get("content"))
+                                    && "Test attachment message".equals(msg1.get("subject"))
+                                    && attachmentPath.getFileName().toString().equals(attch1.get(0).get("attachmentFilename"))
+                                    && attachmentContent.equals(attch1.get(0).get("attachmentContent"))
+                                    && (attch1.get(0).get("attachmentContentType").toString().startsWith("text/plain")
+                                            || attch1.get(0).get("attachmentContentType").toString()
+                                                    .startsWith("application/octet-stream"))
+
+                                    && "Test mail content".equals(msg2.get("content"))
+                                    && "Test attachment message".equals(msg2.get("subject"))
+                                    && "logo.jpeg".equals(attch2.get(0).get("attachmentFilename"))
+                                    && (attch2.get(0).get("attachmentContentType").toString().startsWith("image/jpeg")
+                                            || attch2.get(0).get("attachmentContentType").toString().toString()
+                                                    .startsWith("application/octet-stream"));
+                        }
+                        return false;
+                    });
+
+        } finally {
+            Files.deleteIfExists(attachmentPath);
+        }
+    }
+
+    @Test
+    public void testBatchConsumer() {
+        //start route
+        startRoute(CamelRoute.Routes.batchReceiveRoute);
+        //send messages
+        IntStream.range(1, 5).boxed().forEach(i -> RestAssured.given()
+                .contentType(ContentType.JSON)
+                .contentType(ContentType.TEXT)
+                .queryParam("subject", "Test batch consumer")
+                .queryParam("from", "camel@localhost")
+                .queryParam("to", EMAIL_ADDRESS)
+                .body("message " + i)
+                .post("/mail/send")
+                .then()
+                .statusCode(204));
+
+        Awaitility.await().atMost(20, TimeUnit.SECONDS).until(() -> {
+            //receive
+            return (List<Map<String, Object>>) RestAssured.get("/mail/getReceived/")
+                    .then()
+                    .statusCode(200)
+                    .extract().as(List.class);
+        }, list -> list.size() == 4
+
+                && "message 1".equals(list.get(0).get("content"))
+                && "Test batch consumer".equals(list.get(0).get("subject"))
+                && "0".equals(list.get(0).get(ExchangePropertyKey.BATCH_INDEX.getName()).toString())
+                && "3".equals(list.get(0).get(ExchangePropertyKey.BATCH_SIZE.getName()).toString())
+                && !((Boolean) list.get(0).get(ExchangePropertyKey.BATCH_COMPLETE.getName()))
+
+                && "message 2".equals(list.get(1).get("content"))
+                && "Test batch consumer".equals(list.get(1).get("subject"))
+                && "1".equals(list.get(1).get(ExchangePropertyKey.BATCH_INDEX.getName()).toString())
+                && !((Boolean) list.get(1).get(ExchangePropertyKey.BATCH_COMPLETE.getName()))
+
+                && "message 3".equals(list.get(2).get("content"))
+                && "Test batch consumer".equals(list.get(2).get("subject"))
+                && "2".equals(list.get(2).get(ExchangePropertyKey.BATCH_INDEX.getName()).toString())
+                && ((Boolean) list.get(2).get(ExchangePropertyKey.BATCH_COMPLETE.getName()))
+
+                && "message 4".equals(list.get(3).get("content"))
+                && "Test batch consumer".equals(list.get(3).get("subject"))
+                && "0".equals(list.get(3).get(ExchangePropertyKey.BATCH_INDEX.getName()).toString()));
+
+    }
+
+    @Test
+    public void testConverters() throws Exception {
+        startRoute(CamelRoute.Routes.convertersRoute);
+
+        RestAssured.given()
+                .contentType(ContentType.JSON)
+                .contentType(ContentType.TEXT)
+                .queryParam("subject", "Camel Rocks")
+                .queryParam("from", "camel@localhost")
+                .queryParam("to", EMAIL_ADDRESS)
+                .body("Hello World ")
+                .post("/mail/send")
+                .then()
+                .statusCode(204);
+
+        Awaitility.await().atMost(20, TimeUnit.SECONDS).until(() -> {
+            //receive
+            return (List<Map<String, Object>>) RestAssured.get("/mail/getReceivedAsString/")
+                    .then()
+                    .statusCode(200)
+                    .extract().as(List.class);
+        }, list -> list.size() == 1
+                && ((String) list.get(0).get("body")).matches("Hello World\\s*"));
+    }
+
+    @Test
+    public void testSort() {
+        List<String> msgs = IntStream.range(1, 5).boxed().map(i -> ("message " + i)).collect(Collectors.toList());
+        //messages will be sent in reverse order
+        Collections.reverse(msgs);
+
+        List<String> sorted = RestAssured.given()
+                .contentType(ContentType.JSON)
+                .body(msgs)
+                .post("/mail/sort")
+                .then()
+                .statusCode(200)
+                .extract().as(List.class);
+
+        Assertions.assertEquals(4, sorted.size());
+        Assertions.assertTrue(sorted.get(0).contains("message 1"));
+        Assertions.assertTrue(sorted.get(1).contains("message 2"));
+        Assertions.assertTrue(sorted.get(2).contains("message 3"));
+        Assertions.assertTrue(sorted.get(3).contains("message 4"));
+    }
+
+    // helper methods
+
+    private void startRoute(CamelRoute.Routes route) {
+        RestAssured.given()
+                .get("/mail/route/" + route.name() + "/start")
+                .then().statusCode(204);
+
+        //wait for finish
+        Awaitility.await().atMost(5, TimeUnit.SECONDS).until(
+                () -> {
+                    String status = RestAssured
+                            .get("/mail/route/" + route.name() + "/status")
+                            .then()
+                            .statusCode(200)
+                            .extract().asString();
+
+                    return status.equals(ServiceStatus.Started.name());
+                });
+    }
 }
diff --git a/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTestResource.java b/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTestResource.java
new file mode 100644
index 0000000000..f7e6abb497
--- /dev/null
+++ b/integration-tests/mail/src/test/java/org/apache/camel/quarkus/component/mail/MailTestResource.java
@@ -0,0 +1,88 @@
+/*
+ * 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.camel.quarkus.component.mail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
+import org.testcontainers.utility.DockerImageName;
+
+public class MailTestResource implements QuarkusTestResourceLifecycleManager {
+
+    private static final String GREENMAIL_IMAGE_NAME = "greenmail/standalone:1.6.7";
+    private GenericContainer<?> container;
+
+    @Override
+    public Map<String, String> start() {
+        container = new GenericContainer<>(DockerImageName.parse(GREENMAIL_IMAGE_NAME))
+                .withExposedPorts(MailProtocol.allPorts())
+                .waitingFor(new HttpWaitStrategy()
+                        .forPort(MailProtocol.API.getPort())
+                        .forPath("/api/service/readiness")
+                        .forStatusCode(200));
+
+        container.start();
+
+        Map<String, String> options = new HashMap<>();
+        for (MailProtocol protocol : MailProtocol.values()) {
+            String optionName = String.format("mail.%s.port", protocol.name().toLowerCase());
+            Integer mappedPort = container.getMappedPort(protocol.getPort());
+            options.put(optionName, mappedPort.toString());
+        }
+
+        return options;
+    }
+
+    @Override
+    public void stop() {
+        if (container != null) {
+            container.stop();
+        }
+    }
+
+    enum MailProtocol {
+        SMTP(3025),
+        POP3(3110),
+        IMAP(3143),
+        SMTPS(3465),
+        IMAPS(3993),
+        POP3s(3995),
+        API(8080);
+
+        private final int port;
+
+        MailProtocol(int port) {
+            this.port = port;
+        }
+
+        public int getPort() {
+            return port;
+        }
+
+        public static Integer[] allPorts() {
+            MailProtocol[] values = values();
+            Integer[] ports = new Integer[values.length];
+            for (int i = 0; i < values.length; i++) {
+                ports[i] = values[i].getPort();
+            }
+            return ports;
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
index 8834903967..4fbdf0e0ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,6 +143,7 @@
         <commons-logging.version>1.2</commons-logging.version><!-- Mess in the transitive dependencies of hbase-testing-util -->
         <consul-client.version>${consul-client-version}</consul-client.version>
         <ftpserver.version>1.1.1</ftpserver.version>
+        <greenmail.version>1.6.7</greenmail.version>
         <istack-commons-runtime.version>3.0.10</istack-commons-runtime.version>
         <jakarta.mail.version>${jakarta-mail-version}</jakarta.mail.version>
         <htmlunit-driver.version>2.47.1</htmlunit-driver.version>
@@ -477,6 +478,7 @@
                             <exclude>**/*.graphql</exclude>
                             <exclude>**/*.ics</exclude>
                             <exclude>**/*.jks</exclude>
+                            <exclude>**/*.jpeg</exclude>
                             <exclude>**/*.key</exclude>
                             <exclude>**/*.kts</exclude>
                             <exclude>**/*.lock</exclude>
diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml
index a75f432b65..068869fc24 100644
--- a/poms/bom-test/pom.xml
+++ b/poms/bom-test/pom.xml
@@ -327,6 +327,12 @@
                 <artifactId>aws-java-sdk-core</artifactId>
                 <version>${aws-java-sdk.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.icegreen</groupId>
+                <artifactId>greenmail</artifactId>
+                <version>${greenmail.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml b/poms/bom/src/main/generated/flattened-full-pom.xml
index fb52bb0eeb..5bf60a7abf 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -17,24 +17,24 @@
   </licenses>
   <developers>
     <developer>
-      <name>The Apache Camel Team</name><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 229 -->
-      <email>dev@camel.apache.org</email><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 230 -->
-      <url>http://camel.apache.org</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 231 -->
-      <organization>Apache Software Foundation</organization><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 232 -->
-      <organizationUrl>http://apache.org/</organizationUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 233 -->
+      <name>The Apache Camel Team</name><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 230 -->
+      <email>dev@camel.apache.org</email><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 231 -->
+      <url>http://camel.apache.org</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 232 -->
+      <organization>Apache Software Foundation</organization><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 233 -->
+      <organizationUrl>http://apache.org/</organizationUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 234 -->
       <properties>
-        <picUrl>http://camel.apache.org/banner.data/apache-camel-7.png</picUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 235 -->
+        <picUrl>http://camel.apache.org/banner.data/apache-camel-7.png</picUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 236 -->
       </properties>
     </developer>
   </developers>
   <scm>
-    <connection>scm:git:http://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</connection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 262 -->
-    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</developerConnection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 263 -->
-    <url>https://gitbox.apache.org/repos/asf?p=camel-quarkus.git;a=summary/camel-quarkus-poms/camel-quarkus-bom</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 264 -->
+    <connection>scm:git:http://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</connection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 263 -->
+    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</developerConnection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 264 -->
+    <url>https://gitbox.apache.org/repos/asf?p=camel-quarkus.git;a=summary/camel-quarkus-poms/camel-quarkus-bom</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 265 -->
   </scm>
   <issueManagement>
-    <system>GitHub</system><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 269 -->
-    <url>https://github.com/apache/camel-quarkus/issues</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 270 -->
+    <system>GitHub</system><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 270 -->
+    <url>https://github.com/apache/camel-quarkus/issues</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 271 -->
   </issueManagement>
   <distributionManagement>
     <repository>
diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
index 9f7e2d6a48..6efbf96143 100644
--- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
@@ -17,24 +17,24 @@
   </licenses>
   <developers>
     <developer>
-      <name>The Apache Camel Team</name><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 229 -->
-      <email>dev@camel.apache.org</email><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 230 -->
-      <url>http://camel.apache.org</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 231 -->
-      <organization>Apache Software Foundation</organization><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 232 -->
-      <organizationUrl>http://apache.org/</organizationUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 233 -->
+      <name>The Apache Camel Team</name><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 230 -->
+      <email>dev@camel.apache.org</email><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 231 -->
+      <url>http://camel.apache.org</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 232 -->
+      <organization>Apache Software Foundation</organization><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 233 -->
+      <organizationUrl>http://apache.org/</organizationUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 234 -->
       <properties>
-        <picUrl>http://camel.apache.org/banner.data/apache-camel-7.png</picUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 235 -->
+        <picUrl>http://camel.apache.org/banner.data/apache-camel-7.png</picUrl><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 236 -->
       </properties>
     </developer>
   </developers>
   <scm>
-    <connection>scm:git:http://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</connection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 262 -->
-    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</developerConnection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 263 -->
-    <url>https://gitbox.apache.org/repos/asf?p=camel-quarkus.git;a=summary/camel-quarkus-poms/camel-quarkus-bom</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 264 -->
+    <connection>scm:git:http://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</connection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 263 -->
+    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/camel-quarkus.git/camel-quarkus-poms/camel-quarkus-bom</developerConnection><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 264 -->
+    <url>https://gitbox.apache.org/repos/asf?p=camel-quarkus.git;a=summary/camel-quarkus-poms/camel-quarkus-bom</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 265 -->
   </scm>
   <issueManagement>
-    <system>GitHub</system><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 269 -->
-    <url>https://github.com/apache/camel-quarkus/issues</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 270 -->
+    <system>GitHub</system><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 270 -->
+    <url>https://github.com/apache/camel-quarkus/issues</url><!-- org.apache.camel.quarkus:camel-quarkus:2.7.2-SNAPSHOT, line 271 -->
   </issueManagement>
   <distributionManagement>
     <repository>