You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2026/01/27 12:56:46 UTC

(camel) 01/02: Polly

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

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

commit 4295ff4544b73a613160b291c532ff6d6f7342fd
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Mon Jan 19 12:15:30 2026 +0100

    Polly
    
    Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
 catalog/camel-allcomponents/pom.xml                |   5 +
 components/camel-aws/camel-aws2-polly/pom.xml      |  83 +++
 .../aws2/polly/Polly2ComponentConfigurer.java      | 219 ++++++++
 .../aws2/polly/Polly2EndpointConfigurer.java       | 191 +++++++
 .../aws2/polly/Polly2EndpointUriFactory.java       |  99 ++++
 .../camel/component/aws2/polly/aws2-polly.json     | 103 ++++
 .../services/org/apache/camel/component.properties |   7 +
 .../services/org/apache/camel/component/aws2-polly |   2 +
 .../apache/camel/configurer/aws2-polly-component   |   2 +
 .../apache/camel/configurer/aws2-polly-endpoint    |   2 +
 .../apache/camel/urifactory/aws2-polly-endpoint    |   2 +
 .../src/main/docs/aws2-polly-component.adoc        | 171 ++++++
 .../component/aws2/polly/Polly2Component.java      |  72 +++
 .../component/aws2/polly/Polly2Configuration.java  | 368 ++++++++++++
 .../component/aws2/polly/Polly2Constants.java      |  61 ++
 .../camel/component/aws2/polly/Polly2Endpoint.java | 108 ++++
 .../component/aws2/polly/Polly2Operations.java     |  30 +
 .../camel/component/aws2/polly/Polly2Producer.java | 624 +++++++++++++++++++++
 .../aws2/polly/Polly2ProducerHealthCheck.java      |  71 +++
 .../aws2/polly/client/Polly2ClientFactory.java     |  42 ++
 .../aws2/polly/AmazonPollyClientMock.java          | 187 ++++++
 .../aws2/polly/Polly2ClientFactoryTest.java        |  50 ++
 .../component/aws2/polly/Polly2ProducerTest.java   | 282 ++++++++++
 components/camel-aws/pom.xml                       |   1 +
 parent/pom.xml                                     |   5 +
 .../apache/camel/maven/packaging/MojoHelper.java   |   2 +-
 26 files changed, 2788 insertions(+), 1 deletion(-)

diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml
index 83fff97272da..3becdd4fdf14 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -227,6 +227,11 @@
             <artifactId>camel-aws2-msk</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-aws2-polly</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-aws2-redshift</artifactId>
diff --git a/components/camel-aws/camel-aws2-polly/pom.xml b/components/camel-aws/camel-aws2-polly/pom.xml
new file mode 100644
index 000000000000..961fb42357d6
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-aws-parent</artifactId>
+        <version>4.18.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-aws2-polly</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel :: AWS2 Polly</name>
+    <description>Synthesize speech using AWS Polly Service</description>
+
+    <properties>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-aws-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>polly</artifactId>
+            <version>${aws-java-sdk2-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>sts</artifactId>
+            <version>${aws-java-sdk2-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>apache-client</artifactId>
+            <version>${aws-java-sdk2-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-health</artifactId>
+        </dependency>
+
+        <!-- for testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-spring-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- test infra -->
+       <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-aws-v2</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2ComponentConfigurer.java b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2ComponentConfigurer.java
new file mode 100644
index 000000000000..e6e5c007b225
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2ComponentConfigurer.java
@@ -0,0 +1,219 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.aws2.polly;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo")
+@SuppressWarnings("unchecked")
+public class Polly2ComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    private org.apache.camel.component.aws2.polly.Polly2Configuration getOrCreateConfiguration(Polly2Component target) {
+        if (target.getConfiguration() == null) {
+            target.setConfiguration(new org.apache.camel.component.aws2.polly.Polly2Configuration());
+        }
+        return target.getConfiguration();
+    }
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        Polly2Component target = (Polly2Component) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": getOrCreateConfiguration(target).setAccessKey(property(camelContext, java.lang.String.class, value)); return true;
+        case "autowiredenabled":
+        case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true;
+        case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.aws2.polly.Polly2Configuration.class, value)); return true;
+        case "engine": getOrCreateConfiguration(target).setEngine(property(camelContext, software.amazon.awssdk.services.polly.model.Engine.class, value)); return true;
+        case "healthcheckconsumerenabled":
+        case "healthCheckConsumerEnabled": target.setHealthCheckConsumerEnabled(property(camelContext, boolean.class, value)); return true;
+        case "healthcheckproducerenabled":
+        case "healthCheckProducerEnabled": target.setHealthCheckProducerEnabled(property(camelContext, boolean.class, value)); return true;
+        case "languagecode":
+        case "languageCode": getOrCreateConfiguration(target).setLanguageCode(property(camelContext, java.lang.String.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "lexiconnames":
+        case "lexiconNames": getOrCreateConfiguration(target).setLexiconNames(property(camelContext, java.lang.String.class, value)); return true;
+        case "operation": getOrCreateConfiguration(target).setOperation(property(camelContext, org.apache.camel.component.aws2.polly.Polly2Operations.class, value)); return true;
+        case "outputformat":
+        case "outputFormat": getOrCreateConfiguration(target).setOutputFormat(property(camelContext, software.amazon.awssdk.services.polly.model.OutputFormat.class, value)); return true;
+        case "overrideendpoint":
+        case "overrideEndpoint": getOrCreateConfiguration(target).setOverrideEndpoint(property(camelContext, boolean.class, value)); return true;
+        case "pojorequest":
+        case "pojoRequest": getOrCreateConfiguration(target).setPojoRequest(property(camelContext, boolean.class, value)); return true;
+        case "pollyclient":
+        case "pollyClient": getOrCreateConfiguration(target).setPollyClient(property(camelContext, software.amazon.awssdk.services.polly.PollyClient.class, value)); return true;
+        case "profilecredentialsname":
+        case "profileCredentialsName": getOrCreateConfiguration(target).setProfileCredentialsName(property(camelContext, java.lang.String.class, value)); return true;
+        case "proxyhost":
+        case "proxyHost": getOrCreateConfiguration(target).setProxyHost(property(camelContext, java.lang.String.class, value)); return true;
+        case "proxyport":
+        case "proxyPort": getOrCreateConfiguration(target).setProxyPort(property(camelContext, java.lang.Integer.class, value)); return true;
+        case "proxyprotocol":
+        case "proxyProtocol": getOrCreateConfiguration(target).setProxyProtocol(property(camelContext, software.amazon.awssdk.core.Protocol.class, value)); return true;
+        case "region": getOrCreateConfiguration(target).setRegion(property(camelContext, java.lang.String.class, value)); return true;
+        case "samplerate":
+        case "sampleRate": getOrCreateConfiguration(target).setSampleRate(property(camelContext, java.lang.String.class, value)); return true;
+        case "secretkey":
+        case "secretKey": getOrCreateConfiguration(target).setSecretKey(property(camelContext, java.lang.String.class, value)); return true;
+        case "sessiontoken":
+        case "sessionToken": getOrCreateConfiguration(target).setSessionToken(property(camelContext, java.lang.String.class, value)); return true;
+        case "texttype":
+        case "textType": getOrCreateConfiguration(target).setTextType(property(camelContext, software.amazon.awssdk.services.polly.model.TextType.class, value)); return true;
+        case "trustallcertificates":
+        case "trustAllCertificates": getOrCreateConfiguration(target).setTrustAllCertificates(property(camelContext, boolean.class, value)); return true;
+        case "uriendpointoverride":
+        case "uriEndpointOverride": getOrCreateConfiguration(target).setUriEndpointOverride(property(camelContext, java.lang.String.class, value)); return true;
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": getOrCreateConfiguration(target).setUseDefaultCredentialsProvider(property(camelContext, boolean.class, value)); return true;
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": getOrCreateConfiguration(target).setUseProfileCredentialsProvider(property(camelContext, boolean.class, value)); return true;
+        case "usesessioncredentials":
+        case "useSessionCredentials": getOrCreateConfiguration(target).setUseSessionCredentials(property(camelContext, boolean.class, value)); return true;
+        case "voiceid":
+        case "voiceId": getOrCreateConfiguration(target).setVoiceId(property(camelContext, software.amazon.awssdk.services.polly.model.VoiceId.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public String[] getAutowiredNames() {
+        return new String[]{"pollyClient"};
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": return java.lang.String.class;
+        case "autowiredenabled":
+        case "autowiredEnabled": return boolean.class;
+        case "configuration": return org.apache.camel.component.aws2.polly.Polly2Configuration.class;
+        case "engine": return software.amazon.awssdk.services.polly.model.Engine.class;
+        case "healthcheckconsumerenabled":
+        case "healthCheckConsumerEnabled": return boolean.class;
+        case "healthcheckproducerenabled":
+        case "healthCheckProducerEnabled": return boolean.class;
+        case "languagecode":
+        case "languageCode": return java.lang.String.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        case "lexiconnames":
+        case "lexiconNames": return java.lang.String.class;
+        case "operation": return org.apache.camel.component.aws2.polly.Polly2Operations.class;
+        case "outputformat":
+        case "outputFormat": return software.amazon.awssdk.services.polly.model.OutputFormat.class;
+        case "overrideendpoint":
+        case "overrideEndpoint": return boolean.class;
+        case "pojorequest":
+        case "pojoRequest": return boolean.class;
+        case "pollyclient":
+        case "pollyClient": return software.amazon.awssdk.services.polly.PollyClient.class;
+        case "profilecredentialsname":
+        case "profileCredentialsName": return java.lang.String.class;
+        case "proxyhost":
+        case "proxyHost": return java.lang.String.class;
+        case "proxyport":
+        case "proxyPort": return java.lang.Integer.class;
+        case "proxyprotocol":
+        case "proxyProtocol": return software.amazon.awssdk.core.Protocol.class;
+        case "region": return java.lang.String.class;
+        case "samplerate":
+        case "sampleRate": return java.lang.String.class;
+        case "secretkey":
+        case "secretKey": return java.lang.String.class;
+        case "sessiontoken":
+        case "sessionToken": return java.lang.String.class;
+        case "texttype":
+        case "textType": return software.amazon.awssdk.services.polly.model.TextType.class;
+        case "trustallcertificates":
+        case "trustAllCertificates": return boolean.class;
+        case "uriendpointoverride":
+        case "uriEndpointOverride": return java.lang.String.class;
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": return boolean.class;
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": return boolean.class;
+        case "usesessioncredentials":
+        case "useSessionCredentials": return boolean.class;
+        case "voiceid":
+        case "voiceId": return software.amazon.awssdk.services.polly.model.VoiceId.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        Polly2Component target = (Polly2Component) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": return getOrCreateConfiguration(target).getAccessKey();
+        case "autowiredenabled":
+        case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "configuration": return target.getConfiguration();
+        case "engine": return getOrCreateConfiguration(target).getEngine();
+        case "healthcheckconsumerenabled":
+        case "healthCheckConsumerEnabled": return target.isHealthCheckConsumerEnabled();
+        case "healthcheckproducerenabled":
+        case "healthCheckProducerEnabled": return target.isHealthCheckProducerEnabled();
+        case "languagecode":
+        case "languageCode": return getOrCreateConfiguration(target).getLanguageCode();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        case "lexiconnames":
+        case "lexiconNames": return getOrCreateConfiguration(target).getLexiconNames();
+        case "operation": return getOrCreateConfiguration(target).getOperation();
+        case "outputformat":
+        case "outputFormat": return getOrCreateConfiguration(target).getOutputFormat();
+        case "overrideendpoint":
+        case "overrideEndpoint": return getOrCreateConfiguration(target).isOverrideEndpoint();
+        case "pojorequest":
+        case "pojoRequest": return getOrCreateConfiguration(target).isPojoRequest();
+        case "pollyclient":
+        case "pollyClient": return getOrCreateConfiguration(target).getPollyClient();
+        case "profilecredentialsname":
+        case "profileCredentialsName": return getOrCreateConfiguration(target).getProfileCredentialsName();
+        case "proxyhost":
+        case "proxyHost": return getOrCreateConfiguration(target).getProxyHost();
+        case "proxyport":
+        case "proxyPort": return getOrCreateConfiguration(target).getProxyPort();
+        case "proxyprotocol":
+        case "proxyProtocol": return getOrCreateConfiguration(target).getProxyProtocol();
+        case "region": return getOrCreateConfiguration(target).getRegion();
+        case "samplerate":
+        case "sampleRate": return getOrCreateConfiguration(target).getSampleRate();
+        case "secretkey":
+        case "secretKey": return getOrCreateConfiguration(target).getSecretKey();
+        case "sessiontoken":
+        case "sessionToken": return getOrCreateConfiguration(target).getSessionToken();
+        case "texttype":
+        case "textType": return getOrCreateConfiguration(target).getTextType();
+        case "trustallcertificates":
+        case "trustAllCertificates": return getOrCreateConfiguration(target).isTrustAllCertificates();
+        case "uriendpointoverride":
+        case "uriEndpointOverride": return getOrCreateConfiguration(target).getUriEndpointOverride();
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": return getOrCreateConfiguration(target).isUseDefaultCredentialsProvider();
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": return getOrCreateConfiguration(target).isUseProfileCredentialsProvider();
+        case "usesessioncredentials":
+        case "useSessionCredentials": return getOrCreateConfiguration(target).isUseSessionCredentials();
+        case "voiceid":
+        case "voiceId": return getOrCreateConfiguration(target).getVoiceId();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointConfigurer.java b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointConfigurer.java
new file mode 100644
index 000000000000..2612e0e6ba74
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointConfigurer.java
@@ -0,0 +1,191 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.aws2.polly;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo")
+@SuppressWarnings("unchecked")
+public class Polly2EndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        Polly2Endpoint target = (Polly2Endpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": target.getConfiguration().setAccessKey(property(camelContext, java.lang.String.class, value)); return true;
+        case "engine": target.getConfiguration().setEngine(property(camelContext, software.amazon.awssdk.services.polly.model.Engine.class, value)); return true;
+        case "languagecode":
+        case "languageCode": target.getConfiguration().setLanguageCode(property(camelContext, java.lang.String.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "lexiconnames":
+        case "lexiconNames": target.getConfiguration().setLexiconNames(property(camelContext, java.lang.String.class, value)); return true;
+        case "operation": target.getConfiguration().setOperation(property(camelContext, org.apache.camel.component.aws2.polly.Polly2Operations.class, value)); return true;
+        case "outputformat":
+        case "outputFormat": target.getConfiguration().setOutputFormat(property(camelContext, software.amazon.awssdk.services.polly.model.OutputFormat.class, value)); return true;
+        case "overrideendpoint":
+        case "overrideEndpoint": target.getConfiguration().setOverrideEndpoint(property(camelContext, boolean.class, value)); return true;
+        case "pojorequest":
+        case "pojoRequest": target.getConfiguration().setPojoRequest(property(camelContext, boolean.class, value)); return true;
+        case "pollyclient":
+        case "pollyClient": target.getConfiguration().setPollyClient(property(camelContext, software.amazon.awssdk.services.polly.PollyClient.class, value)); return true;
+        case "profilecredentialsname":
+        case "profileCredentialsName": target.getConfiguration().setProfileCredentialsName(property(camelContext, java.lang.String.class, value)); return true;
+        case "proxyhost":
+        case "proxyHost": target.getConfiguration().setProxyHost(property(camelContext, java.lang.String.class, value)); return true;
+        case "proxyport":
+        case "proxyPort": target.getConfiguration().setProxyPort(property(camelContext, java.lang.Integer.class, value)); return true;
+        case "proxyprotocol":
+        case "proxyProtocol": target.getConfiguration().setProxyProtocol(property(camelContext, software.amazon.awssdk.core.Protocol.class, value)); return true;
+        case "region": target.getConfiguration().setRegion(property(camelContext, java.lang.String.class, value)); return true;
+        case "samplerate":
+        case "sampleRate": target.getConfiguration().setSampleRate(property(camelContext, java.lang.String.class, value)); return true;
+        case "secretkey":
+        case "secretKey": target.getConfiguration().setSecretKey(property(camelContext, java.lang.String.class, value)); return true;
+        case "sessiontoken":
+        case "sessionToken": target.getConfiguration().setSessionToken(property(camelContext, java.lang.String.class, value)); return true;
+        case "texttype":
+        case "textType": target.getConfiguration().setTextType(property(camelContext, software.amazon.awssdk.services.polly.model.TextType.class, value)); return true;
+        case "trustallcertificates":
+        case "trustAllCertificates": target.getConfiguration().setTrustAllCertificates(property(camelContext, boolean.class, value)); return true;
+        case "uriendpointoverride":
+        case "uriEndpointOverride": target.getConfiguration().setUriEndpointOverride(property(camelContext, java.lang.String.class, value)); return true;
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": target.getConfiguration().setUseDefaultCredentialsProvider(property(camelContext, boolean.class, value)); return true;
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": target.getConfiguration().setUseProfileCredentialsProvider(property(camelContext, boolean.class, value)); return true;
+        case "usesessioncredentials":
+        case "useSessionCredentials": target.getConfiguration().setUseSessionCredentials(property(camelContext, boolean.class, value)); return true;
+        case "voiceid":
+        case "voiceId": target.getConfiguration().setVoiceId(property(camelContext, software.amazon.awssdk.services.polly.model.VoiceId.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public String[] getAutowiredNames() {
+        return new String[]{"pollyClient"};
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": return java.lang.String.class;
+        case "engine": return software.amazon.awssdk.services.polly.model.Engine.class;
+        case "languagecode":
+        case "languageCode": return java.lang.String.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        case "lexiconnames":
+        case "lexiconNames": return java.lang.String.class;
+        case "operation": return org.apache.camel.component.aws2.polly.Polly2Operations.class;
+        case "outputformat":
+        case "outputFormat": return software.amazon.awssdk.services.polly.model.OutputFormat.class;
+        case "overrideendpoint":
+        case "overrideEndpoint": return boolean.class;
+        case "pojorequest":
+        case "pojoRequest": return boolean.class;
+        case "pollyclient":
+        case "pollyClient": return software.amazon.awssdk.services.polly.PollyClient.class;
+        case "profilecredentialsname":
+        case "profileCredentialsName": return java.lang.String.class;
+        case "proxyhost":
+        case "proxyHost": return java.lang.String.class;
+        case "proxyport":
+        case "proxyPort": return java.lang.Integer.class;
+        case "proxyprotocol":
+        case "proxyProtocol": return software.amazon.awssdk.core.Protocol.class;
+        case "region": return java.lang.String.class;
+        case "samplerate":
+        case "sampleRate": return java.lang.String.class;
+        case "secretkey":
+        case "secretKey": return java.lang.String.class;
+        case "sessiontoken":
+        case "sessionToken": return java.lang.String.class;
+        case "texttype":
+        case "textType": return software.amazon.awssdk.services.polly.model.TextType.class;
+        case "trustallcertificates":
+        case "trustAllCertificates": return boolean.class;
+        case "uriendpointoverride":
+        case "uriEndpointOverride": return java.lang.String.class;
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": return boolean.class;
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": return boolean.class;
+        case "usesessioncredentials":
+        case "useSessionCredentials": return boolean.class;
+        case "voiceid":
+        case "voiceId": return software.amazon.awssdk.services.polly.model.VoiceId.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        Polly2Endpoint target = (Polly2Endpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "accesskey":
+        case "accessKey": return target.getConfiguration().getAccessKey();
+        case "engine": return target.getConfiguration().getEngine();
+        case "languagecode":
+        case "languageCode": return target.getConfiguration().getLanguageCode();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        case "lexiconnames":
+        case "lexiconNames": return target.getConfiguration().getLexiconNames();
+        case "operation": return target.getConfiguration().getOperation();
+        case "outputformat":
+        case "outputFormat": return target.getConfiguration().getOutputFormat();
+        case "overrideendpoint":
+        case "overrideEndpoint": return target.getConfiguration().isOverrideEndpoint();
+        case "pojorequest":
+        case "pojoRequest": return target.getConfiguration().isPojoRequest();
+        case "pollyclient":
+        case "pollyClient": return target.getConfiguration().getPollyClient();
+        case "profilecredentialsname":
+        case "profileCredentialsName": return target.getConfiguration().getProfileCredentialsName();
+        case "proxyhost":
+        case "proxyHost": return target.getConfiguration().getProxyHost();
+        case "proxyport":
+        case "proxyPort": return target.getConfiguration().getProxyPort();
+        case "proxyprotocol":
+        case "proxyProtocol": return target.getConfiguration().getProxyProtocol();
+        case "region": return target.getConfiguration().getRegion();
+        case "samplerate":
+        case "sampleRate": return target.getConfiguration().getSampleRate();
+        case "secretkey":
+        case "secretKey": return target.getConfiguration().getSecretKey();
+        case "sessiontoken":
+        case "sessionToken": return target.getConfiguration().getSessionToken();
+        case "texttype":
+        case "textType": return target.getConfiguration().getTextType();
+        case "trustallcertificates":
+        case "trustAllCertificates": return target.getConfiguration().isTrustAllCertificates();
+        case "uriendpointoverride":
+        case "uriEndpointOverride": return target.getConfiguration().getUriEndpointOverride();
+        case "usedefaultcredentialsprovider":
+        case "useDefaultCredentialsProvider": return target.getConfiguration().isUseDefaultCredentialsProvider();
+        case "useprofilecredentialsprovider":
+        case "useProfileCredentialsProvider": return target.getConfiguration().isUseProfileCredentialsProvider();
+        case "usesessioncredentials":
+        case "useSessionCredentials": return target.getConfiguration().isUseSessionCredentials();
+        case "voiceid":
+        case "voiceId": return target.getConfiguration().getVoiceId();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointUriFactory.java b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointUriFactory.java
new file mode 100644
index 000000000000..5e29378eb593
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/java/org/apache/camel/component/aws2/polly/Polly2EndpointUriFactory.java
@@ -0,0 +1,99 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.aws2.polly;
+
+import javax.annotation.processing.Generated;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.EndpointUriFactory;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo")
+public class Polly2EndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory {
+
+    private static final String BASE = ":label";
+
+    private static final Set<String> PROPERTY_NAMES;
+    private static final Set<String> SECRET_PROPERTY_NAMES;
+    private static final Map<String, String> MULTI_VALUE_PREFIXES;
+    static {
+        Set<String> props = new HashSet<>(26);
+        props.add("accessKey");
+        props.add("engine");
+        props.add("label");
+        props.add("languageCode");
+        props.add("lazyStartProducer");
+        props.add("lexiconNames");
+        props.add("operation");
+        props.add("outputFormat");
+        props.add("overrideEndpoint");
+        props.add("pojoRequest");
+        props.add("pollyClient");
+        props.add("profileCredentialsName");
+        props.add("proxyHost");
+        props.add("proxyPort");
+        props.add("proxyProtocol");
+        props.add("region");
+        props.add("sampleRate");
+        props.add("secretKey");
+        props.add("sessionToken");
+        props.add("textType");
+        props.add("trustAllCertificates");
+        props.add("uriEndpointOverride");
+        props.add("useDefaultCredentialsProvider");
+        props.add("useProfileCredentialsProvider");
+        props.add("useSessionCredentials");
+        props.add("voiceId");
+        PROPERTY_NAMES = Collections.unmodifiableSet(props);
+        Set<String> secretProps = new HashSet<>(3);
+        secretProps.add("accessKey");
+        secretProps.add("secretKey");
+        secretProps.add("sessionToken");
+        SECRET_PROPERTY_NAMES = Collections.unmodifiableSet(secretProps);
+        MULTI_VALUE_PREFIXES = Collections.emptyMap();
+    }
+
+    @Override
+    public boolean isEnabled(String scheme) {
+        return "aws2-polly".equals(scheme);
+    }
+
+    @Override
+    public String buildUri(String scheme, Map<String, Object> properties, boolean encode) throws URISyntaxException {
+        String syntax = scheme + BASE;
+        String uri = syntax;
+
+        Map<String, Object> copy = new HashMap<>(properties);
+
+        uri = buildPathParameter(syntax, uri, "label", null, true, copy);
+        uri = buildQueryParameters(uri, copy, encode);
+        return uri;
+    }
+
+    @Override
+    public Set<String> propertyNames() {
+        return PROPERTY_NAMES;
+    }
+
+    @Override
+    public Set<String> secretPropertyNames() {
+        return SECRET_PROPERTY_NAMES;
+    }
+
+    @Override
+    public Map<String, String> multiValuePrefixes() {
+        return MULTI_VALUE_PREFIXES;
+    }
+
+    @Override
+    public boolean isLenientProperties() {
+        return false;
+    }
+}
+
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/org/apache/camel/component/aws2/polly/aws2-polly.json b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/org/apache/camel/component/aws2/polly/aws2-polly.json
new file mode 100644
index 000000000000..b4e3a41215ec
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/org/apache/camel/component/aws2/polly/aws2-polly.json
@@ -0,0 +1,103 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "aws2-polly",
+    "title": "AWS Polly",
+    "description": "Synthesize speech using AWS Polly and AWS SDK version 2.x.",
+    "deprecated": false,
+    "firstVersion": "4.18.0",
+    "label": "cloud,ai",
+    "javaType": "org.apache.camel.component.aws2.polly.Polly2Component",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-aws2-polly",
+    "version": "4.18.0-SNAPSHOT",
+    "scheme": "aws2-polly",
+    "extendsScheme": "",
+    "syntax": "aws2-polly:label",
+    "async": false,
+    "api": false,
+    "consumerOnly": false,
+    "producerOnly": true,
+    "lenientProperties": false,
+    "browsable": false,
+    "remote": true
+  },
+  "componentProperties": {
+    "configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.aws2.polly.Polly2Configuration", "deprecated": false, "autowired": false, "secret": false, "description": "Component configuration" },
+    "engine": { "index": 1, "kind": "property", "displayName": "Engine", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.Engine", "enum": [ "standard", "neural", "long-form", "generative", "null" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The engine to use f [...]
+    "languageCode": { "index": 2, "kind": "property", "displayName": "Language Code", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The language code for the synthesis" },
+    "lazyStartProducer": { "index": 3, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
+    "lexiconNames": { "index": 4, "kind": "property", "displayName": "Lexicon Names", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Lexicon names to apply during synthesis" },
+    "operation": { "index": 5, "kind": "property", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.aws2.polly.Polly2Operations", "enum": [ "synthesizeSpeech", "describeVoices", "listLexicons", "getLexicon", "putLexicon", "deleteLexicon", "startSpeechSynthesisTask", "getSpeechSynthesisTask", "listSpeechSynthesisTasks" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, " [...]
+    "outputFormat": { "index": 6, "kind": "property", "displayName": "Output Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.OutputFormat", "enum": [ "json", "mp3", "ogg_opus", "ogg_vorbis", "pcm", "null" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MP3", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configurat [...]
+    "overrideEndpoint": { "index": 7, "kind": "property", "displayName": "Override Endpoint", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set the need for overriding the endpoint. This option needs to be used in combinatio [...]
+    "pojoRequest": { "index": 8, "kind": "property", "displayName": "Pojo Request", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If we want to use a POJO request as body or not" },
+    "region": { "index": 9, "kind": "property", "displayName": "Region", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ap-south-2", "ap-south-1", "eu-south-1", "eu-south-2", "us-gov-east-1", "me-central-1", "il-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "eu-central-2", "eu-isoe-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-north [...]
+    "sampleRate": { "index": 10, "kind": "property", "displayName": "Sample Rate", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The sample rate in Hz for the audio output" },
+    "textType": { "index": 11, "kind": "property", "displayName": "Text Type", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.TextType", "enum": [ "ssml", "text", "null" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TEXT", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The type of text inp [...]
+    "uriEndpointOverride": { "index": 12, "kind": "property", "displayName": "Uri Endpoint Override", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set the overriding uri endpoint. This option needs to be used in combination with overrideE [...]
+    "voiceId": { "index": 13, "kind": "property", "displayName": "Voice Id", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.VoiceId", "enum": [ "Aditi", "Amy", "Astrid", "Bianca", "Brian", "Camila", "Carla", "Carmen", "Celine", "Chantal", "Conchita", "Cristiano", "Dora", "Emma", "Enrique", "Ewa", "Filiz", "Gabrielle", "Geraint", "Giorgio", "Gwyneth", "Hans", "Ines", "Ivy", "Jacek", "Jan", "Joanna", "Joey", "Ju [...]
+    "autowiredEnabled": { "index": 14, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching  [...]
+    "pollyClient": { "index": 15, "kind": "property", "displayName": "Polly Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "software.amazon.awssdk.services.polly.PollyClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To use an existing configured AWS Polly client" },
+    "healthCheckConsumerEnabled": { "index": 16, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
+    "healthCheckProducerEnabled": { "index": 17, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
+    "proxyHost": { "index": 18, "kind": "property", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy host when instantiating the Polly client" },
+    "proxyPort": { "index": 19, "kind": "property", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy port when instantiating the Polly client" },
+    "proxyProtocol": { "index": 20, "kind": "property", "displayName": "Proxy Protocol", "group": "proxy", "label": "proxy", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.core.Protocol", "enum": [ "HTTP", "HTTPS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "HTTPS", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy protocol whe [...]
+    "accessKey": { "index": 21, "kind": "property", "displayName": "Access Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Access Key" },
+    "profileCredentialsName": { "index": 22, "kind": "property", "displayName": "Profile Credentials Name", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If using a profile credentials provider, this parameter will set the profile  [...]
+    "secretKey": { "index": 23, "kind": "property", "displayName": "Secret Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Secret Key" },
+    "sessionToken": { "index": 24, "kind": "property", "displayName": "Session Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Session Token used when the user needs to assume an IAM role" },
+    "trustAllCertificates": { "index": 25, "kind": "property", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If we want to trust all certificates in case of overriding the end [...]
+    "useDefaultCredentialsProvider": { "index": 26, "kind": "property", "displayName": "Use Default Credentials Provider", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to l [...]
+    "useProfileCredentialsProvider": { "index": 27, "kind": "property", "displayName": "Use Profile Credentials Provider", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to l [...]
+    "useSessionCredentials": { "index": 28, "kind": "property", "displayName": "Use Session Credentials", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to use Session Creden [...]
+  },
+  "headers": {
+    "CamelAwsPollyOperation": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation we want to perform", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#OPERATION" },
+    "CamelAwsPollyVoiceId": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "software.amazon.awssdk.services.polly.model.VoiceId", "enum": [ "Aditi", "Amy", "Astrid", "Bianca", "Brian", "Camila", "Carla", "Carmen", "Celine", "Chantal", "Conchita", "Cristiano", "Dora", "Emma", "Enrique", "Ewa", "Filiz", "Gabrielle", "Geraint", "Giorgio", "Gwyneth", "Hans", "Ines", "Ivy", "Jacek", "Jan", "Joanna", "Joey", "Justin", "Karl", [...]
+    "CamelAwsPollyOutputFormat": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "software.amazon.awssdk.services.polly.model.OutputFormat", "enum": [ "json", "mp3", "ogg_opus", "ogg_vorbis", "pcm", "null" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The output format for the audio stream", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#OUTPUT [...]
+    "CamelAwsPollyTextType": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "software.amazon.awssdk.services.polly.model.TextType", "enum": [ "ssml", "text", "null" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The type of text input (text or ssml)", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#TEXT_TYPE" },
+    "CamelAwsPollySampleRate": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The sample rate in Hz", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#SAMPLE_RATE" },
+    "CamelAwsPollyEngine": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "software.amazon.awssdk.services.polly.model.Engine", "enum": [ "standard", "neural", "long-form", "generative", "null" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The engine to use (standard, neural, long-form, generative)", "constantName": "org.apache.camel.component.aws2.polly.Polly2Consta [...]
+    "CamelAwsPollyLanguageCode": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The language code", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#LANGUAGE_CODE" },
+    "CamelAwsPollyLexiconNames": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Comma-separated list of lexicon names", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#LEXICON_NAMES" },
+    "CamelAwsPollyLexiconName": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The name of the lexicon", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#LEXICON_NAME" },
+    "CamelAwsPollyLexiconContent": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content of the lexicon in PLS format", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#LEXICON_CONTENT" },
+    "CamelAwsPollyTaskId": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The task ID for speech synthesis task", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#TASK_ID" },
+    "CamelAwsPollyS3Bucket": { "index": 11, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The S3 bucket name for output", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#S3_BUCKET" },
+    "CamelAwsPollyS3KeyPrefix": { "index": 12, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The S3 key prefix for output", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#S3_KEY_PREFIX" },
+    "CamelAwsPollySnsTopicArn": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The SNS topic ARN for notifications", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#SNS_TOPIC_ARN" },
+    "CamelAwsPollyContentType": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content type of the audio stream", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#CONTENT_TYPE" },
+    "CamelAwsPollyRequestCharacters": { "index": 15, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Number of characters synthesized", "constantName": "org.apache.camel.component.aws2.polly.Polly2Constants#REQUEST_CHARACTERS" }
+  },
+  "properties": {
+    "label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Logical name" },
+    "engine": { "index": 1, "kind": "parameter", "displayName": "Engine", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.Engine", "enum": [ "standard", "neural", "long-form", "generative", "null" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The engine to use  [...]
+    "languageCode": { "index": 2, "kind": "parameter", "displayName": "Language Code", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The language code for the synthesis" },
+    "lexiconNames": { "index": 3, "kind": "parameter", "displayName": "Lexicon Names", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Lexicon names to apply during synthesis" },
+    "operation": { "index": 4, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.aws2.polly.Polly2Operations", "enum": [ "synthesizeSpeech", "describeVoices", "listLexicons", "getLexicon", "putLexicon", "deleteLexicon", "startSpeechSynthesisTask", "getSpeechSynthesisTask", "listSpeechSynthesisTasks" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false,  [...]
+    "outputFormat": { "index": 5, "kind": "parameter", "displayName": "Output Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.OutputFormat", "enum": [ "json", "mp3", "ogg_opus", "ogg_vorbis", "pcm", "null" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MP3", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configura [...]
+    "overrideEndpoint": { "index": 6, "kind": "parameter", "displayName": "Override Endpoint", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set the need for overriding the endpoint. This option needs to be used in combinati [...]
+    "pojoRequest": { "index": 7, "kind": "parameter", "displayName": "Pojo Request", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If we want to use a POJO request as body or not" },
+    "region": { "index": 8, "kind": "parameter", "displayName": "Region", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ap-south-2", "ap-south-1", "eu-south-1", "eu-south-2", "us-gov-east-1", "me-central-1", "il-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "eu-central-2", "eu-isoe-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-nort [...]
+    "sampleRate": { "index": 9, "kind": "parameter", "displayName": "Sample Rate", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The sample rate in Hz for the audio output" },
+    "textType": { "index": 10, "kind": "parameter", "displayName": "Text Type", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.TextType", "enum": [ "ssml", "text", "null" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TEXT", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "The type of text in [...]
+    "uriEndpointOverride": { "index": 11, "kind": "parameter", "displayName": "Uri Endpoint Override", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set the overriding uri endpoint. This option needs to be used in combination with override [...]
+    "voiceId": { "index": 12, "kind": "parameter", "displayName": "Voice Id", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.services.polly.model.VoiceId", "enum": [ "Aditi", "Amy", "Astrid", "Bianca", "Brian", "Camila", "Carla", "Carmen", "Celine", "Chantal", "Conchita", "Cristiano", "Dora", "Emma", "Enrique", "Ewa", "Filiz", "Gabrielle", "Geraint", "Giorgio", "Gwyneth", "Hans", "Ines", "Ivy", "Jacek", "Jan", "Joanna", "Joey", "J [...]
+    "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
+    "pollyClient": { "index": 14, "kind": "parameter", "displayName": "Polly Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "software.amazon.awssdk.services.polly.PollyClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To use an existing configured AWS Polly client" },
+    "proxyHost": { "index": 15, "kind": "parameter", "displayName": "Proxy Host", "group": "proxy", "label": "proxy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy host when instantiating the Polly client" },
+    "proxyPort": { "index": 16, "kind": "parameter", "displayName": "Proxy Port", "group": "proxy", "label": "proxy", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy port when instantiating the Polly client" },
+    "proxyProtocol": { "index": 17, "kind": "parameter", "displayName": "Proxy Protocol", "group": "proxy", "label": "proxy", "required": false, "type": "enum", "javaType": "software.amazon.awssdk.core.Protocol", "enum": [ "HTTP", "HTTPS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "HTTPS", "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "To define a proxy protocol wh [...]
+    "accessKey": { "index": 18, "kind": "parameter", "displayName": "Access Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Access Key" },
+    "profileCredentialsName": { "index": 19, "kind": "parameter", "displayName": "Profile Credentials Name", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If using a profile credentials provider, this parameter will set the profile [...]
+    "secretKey": { "index": 20, "kind": "parameter", "displayName": "Secret Key", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Secret Key" },
+    "sessionToken": { "index": 21, "kind": "parameter", "displayName": "Session Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Amazon AWS Session Token used when the user needs to assume an IAM role" },
+    "trustAllCertificates": { "index": 22, "kind": "parameter", "displayName": "Trust All Certificates", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "If we want to trust all certificates in case of overriding the en [...]
+    "useDefaultCredentialsProvider": { "index": 23, "kind": "parameter", "displayName": "Use Default Credentials Provider", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to  [...]
+    "useProfileCredentialsProvider": { "index": 24, "kind": "parameter", "displayName": "Use Profile Credentials Provider", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to  [...]
+    "useSessionCredentials": { "index": 25, "kind": "parameter", "displayName": "Use Session Credentials", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.aws2.polly.Polly2Configuration", "configurationField": "configuration", "description": "Set whether the Polly client should expect to use Session Crede [...]
+  }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component.properties
new file mode 100644
index 000000000000..d38a2831caeb
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+components=aws2-polly
+groupId=org.apache.camel
+artifactId=camel-aws2-polly
+version=4.18.0-SNAPSHOT
+projectName=Camel :: AWS2 Polly
+projectDescription=Synthesize speech using AWS Polly Service
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component/aws2-polly b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component/aws2-polly
new file mode 100644
index 000000000000..e638ce90b3f3
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/component/aws2-polly
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws2.polly.Polly2Component
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-component b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-component
new file mode 100644
index 000000000000..1609c5101ccd
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-component
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws2.polly.Polly2ComponentConfigurer
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-endpoint b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-endpoint
new file mode 100644
index 000000000000..d7e3838fdf5d
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/configurer/aws2-polly-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws2.polly.Polly2EndpointConfigurer
diff --git a/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/urifactory/aws2-polly-endpoint b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/urifactory/aws2-polly-endpoint
new file mode 100644
index 000000000000..ed351d7890c2
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/generated/resources/META-INF/services/org/apache/camel/urifactory/aws2-polly-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.aws2.polly.Polly2EndpointUriFactory
diff --git a/components/camel-aws/camel-aws2-polly/src/main/docs/aws2-polly-component.adoc b/components/camel-aws/camel-aws2-polly/src/main/docs/aws2-polly-component.adoc
new file mode 100644
index 000000000000..0c475deea824
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/docs/aws2-polly-component.adoc
@@ -0,0 +1,171 @@
+= AWS Polly Component
+:doctitle: AWS Polly
+:shortname: aws2-polly
+:artifactid: camel-aws2-polly
+:description: Synthesize speech using AWS Polly and AWS SDK version 2.x.
+:since: 4.18
+:supportlevel: Preview
+:tabs-sync-option:
+:component-header: Only producer is supported
+//Manually maintained attributes
+:group: AWS
+:camel-spring-boot-name: aws2-polly
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The AWS2 Polly component supports text-to-speech synthesis using the AWS Polly service.
+https://aws.amazon.com/polly/[AWS Polly] is a cloud service that converts text into lifelike speech.
+
+Prerequisites
+
+You must have a valid Amazon Web Services developer account, and be
+signed up to use Amazon Polly. More information is available at
+https://aws.amazon.com/polly/[Amazon Polly].
+
+== URI Format
+
+-------------------------
+aws2-polly://label[?options]
+-------------------------
+
+You can append query options to the URI in the following format:
+
+`?options=value&option2=value&...`
+
+
+// component options: START
+include::partial$component-configure-options.adoc[]
+include::partial$component-endpoint-options.adoc[]
+include::partial$component-endpoint-headers.adoc[]
+// component options: END
+
+
+Required Polly component options
+
+You have to provide the amazonPollyClient in the
+Registry or your accessKey and secretKey to access
+the https://aws.amazon.com/polly/[Amazon Polly] service.
+
+== Usage
+
+=== Static credentials, Default Credential Provider and Profile Credentials Provider
+
+You have the possibility of avoiding the usage of explicit static credentials by specifying the useDefaultCredentialsProvider option and set it to true.
+
+The order of evaluation for Default Credentials Provider is the following:
+
+ - Java system properties - `aws.accessKeyId` and `aws.secretKey`
+ - Environment variables - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
+ - Web Identity Token from AWS STS.
+ - The shared credentials and config files.
+ - Amazon ECS container credentials - loaded from the Amazon ECS if the environment variable `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` is set.
+ - Amazon EC2 Instance profile credentials.
+
+You have also the possibility of using Profile Credentials Provider, by specifying the useProfileCredentialsProvider option to true and profileCredentialsName to the profile name.
+
+Only one of static, default and profile credentials could be used at the same time.
+
+For more information about this you can look at https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html[AWS credentials documentation]
+
+=== Polly Producer operations
+
+Camel-AWS Polly component provides the following operations on the producer side:
+
+- synthesizeSpeech
+- describeVoices
+- listLexicons
+- getLexicon
+- putLexicon
+- deleteLexicon
+- startSpeechSynthesisTask
+- getSpeechSynthesisTask
+- listSpeechSynthesisTasks
+
+== Examples
+
+=== Synthesize Speech example
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+from("direct:start")
+  .setHeader(Polly2Constants.VOICE_ID, constant(VoiceId.JOANNA))
+  .setBody(constant("Hello, this is a test of Amazon Polly text to speech synthesis."))
+  .to("aws2-polly://test?operation=synthesizeSpeech")
+  .to("file:output?fileName=speech.mp3");
+------------------------------------------------------------------------------------------------------
+
+As a result, you'll get an exchange containing the audio stream (InputStream) with the synthesized speech.
+
+=== Using Neural Voices
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+from("direct:start")
+  .setHeader(Polly2Constants.VOICE_ID, constant(VoiceId.MATTHEW))
+  .setHeader(Polly2Constants.ENGINE, constant(Engine.NEURAL))
+  .setBody(constant("This is synthesized using a neural voice."))
+  .to("aws2-polly://test?operation=synthesizeSpeech&outputFormat=MP3");
+------------------------------------------------------------------------------------------------------
+
+=== Describe Voices example
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+from("direct:start")
+  .to("aws2-polly://test?operation=describeVoices")
+  .log("Available voices: ${body}");
+------------------------------------------------------------------------------------------------------
+
+=== Asynchronous Speech Synthesis with S3
+
+For long text, you can use asynchronous synthesis which stores the result in S3:
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+from("direct:start")
+  .setHeader(Polly2Constants.VOICE_ID, constant(VoiceId.JOANNA))
+  .setHeader(Polly2Constants.S3_BUCKET, constant("my-audio-bucket"))
+  .setHeader(Polly2Constants.S3_KEY_PREFIX, constant("audio/"))
+  .setBody(constant("This is a very long text that will be synthesized asynchronously..."))
+  .to("aws2-polly://test?operation=startSpeechSynthesisTask");
+------------------------------------------------------------------------------------------------------
+
+=== Using a POJO as body
+
+Sometimes building an AWS Request can be complex because of multiple options. We introduce the possibility to use a POJO as the body.
+In AWS Polly, you can do something like:
+
+[source,java]
+------------------------------------------------------------------------------------------------------
+from("direct:start")
+  .setBody(SynthesizeSpeechRequest.builder()
+              .voiceId(VoiceId.JOANNA)
+              .outputFormat(OutputFormat.MP3)
+              .text("Hello from Camel!")
+              .build())
+  .to("aws2-polly://test?operation=synthesizeSpeech&pojoRequest=true");
+------------------------------------------------------------------------------------------------------
+
+In this way, you'll pass the request directly without the need of passing headers and options specifically related to this operation.
+
+== Dependencies
+
+Maven users will need to add the following dependency to their pom.xml.
+
+*pom.xml*
+
+[source,xml]
+---------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-aws2-polly</artifactId>
+    <version>${camel-version}</version>
+</dependency>
+---------------------------------------
+
+where `$\{camel-version}` must be replaced by the actual version of Camel.
+
+
+include::spring-boot:partial$starter.adoc[]
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Component.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Component.java
new file mode 100644
index 000000000000..d9ede2be6ea9
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Component.java
@@ -0,0 +1,72 @@
+/*
+ * 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.component.aws2.polly;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.HealthCheckComponent;
+
+/**
+ * For working with Amazon Polly SDK v2.
+ */
+@Component("aws2-polly")
+public class Polly2Component extends HealthCheckComponent {
+
+    @Metadata
+    private Polly2Configuration configuration = new Polly2Configuration();
+
+    public Polly2Component() {
+        this(null);
+    }
+
+    public Polly2Component(CamelContext context) {
+        super(context);
+    }
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        Polly2Configuration configuration
+                = this.configuration != null ? this.configuration.copy() : new Polly2Configuration();
+
+        Polly2Endpoint endpoint = new Polly2Endpoint(uri, this, configuration);
+        setProperties(endpoint, parameters);
+        if (Boolean.FALSE.equals(configuration.isUseDefaultCredentialsProvider())
+                && Boolean.FALSE.equals(configuration.isUseProfileCredentialsProvider())
+                && Boolean.FALSE.equals(configuration.isUseSessionCredentials())
+                && configuration.getPollyClient() == null
+                && (configuration.getAccessKey() == null || configuration.getSecretKey() == null)) {
+            throw new IllegalArgumentException(
+                    "useDefaultCredentialsProvider is set to false, useProfileCredentialsProvider is set to false, useSessionCredentials is set to false, Amazon Polly client or accessKey and secretKey must be specified");
+        }
+        return endpoint;
+    }
+
+    public Polly2Configuration getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * Component configuration
+     */
+    public void setConfiguration(Polly2Configuration configuration) {
+        this.configuration = configuration;
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Configuration.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Configuration.java
new file mode 100644
index 000000000000..4fe33b7cc4cd
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Configuration.java
@@ -0,0 +1,368 @@
+/*
+ * 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.component.aws2.polly;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.aws.common.AwsCommonConfiguration;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.apache.camel.spi.UriPath;
+import software.amazon.awssdk.core.Protocol;
+import software.amazon.awssdk.services.polly.PollyClient;
+import software.amazon.awssdk.services.polly.model.Engine;
+import software.amazon.awssdk.services.polly.model.OutputFormat;
+import software.amazon.awssdk.services.polly.model.TextType;
+import software.amazon.awssdk.services.polly.model.VoiceId;
+
+@UriParams
+public class Polly2Configuration implements Cloneable, AwsCommonConfiguration {
+
+    @UriPath(description = "Logical name")
+    @Metadata(required = true)
+    private String label;
+    @UriParam(label = "advanced")
+    @Metadata(autowired = true)
+    private PollyClient pollyClient;
+    @UriParam(label = "security", secret = true)
+    private String accessKey;
+    @UriParam(label = "security", secret = true)
+    private String secretKey;
+    @UriParam(label = "security", secret = true)
+    private String sessionToken;
+    @UriParam(defaultValue = "synthesizeSpeech")
+    @Metadata(required = true)
+    private Polly2Operations operation = Polly2Operations.synthesizeSpeech;
+    @UriParam(label = "proxy", enums = "HTTP,HTTPS", defaultValue = "HTTPS")
+    private Protocol proxyProtocol = Protocol.HTTPS;
+    @UriParam(label = "proxy")
+    private String proxyHost;
+    @UriParam(label = "proxy")
+    private Integer proxyPort;
+    @UriParam(enums = "ap-south-2,ap-south-1,eu-south-1,eu-south-2,us-gov-east-1,me-central-1,il-central-1,ca-central-1,eu-central-1,us-iso-west-1,eu-central-2,eu-isoe-west-1,us-west-1,us-west-2,af-south-1,eu-north-1,eu-west-3,eu-west-2,eu-west-1,ap-northeast-3,ap-northeast-2,ap-northeast-1,me-south-1,sa-east-1,ap-east-1,cn-north-1,ca-west-1,us-gov-west-1,ap-southeast-1,ap-southeast-2,us-iso-east-1,ap-southeast-3,ap-southeast-4,us-east-1,us-east-2,cn-northwest-1,us-isob-east-1,aws-global [...]
+    private String region;
+    @UriParam(description = "The voice ID to use for synthesis")
+    private VoiceId voiceId;
+    @UriParam(description = "The audio output format", defaultValue = "MP3")
+    private OutputFormat outputFormat = OutputFormat.MP3;
+    @UriParam(description = "The type of text input (text or ssml)", defaultValue = "TEXT")
+    private TextType textType = TextType.TEXT;
+    @UriParam(description = "The engine to use for synthesis (standard, neural, long-form, generative)")
+    private Engine engine;
+    @UriParam(description = "The sample rate in Hz for the audio output")
+    private String sampleRate;
+    @UriParam(description = "The language code for the synthesis")
+    private String languageCode;
+    @UriParam(description = "Lexicon names to apply during synthesis")
+    private String lexiconNames;
+    @UriParam
+    private boolean pojoRequest;
+    @UriParam(label = "security")
+    private boolean trustAllCertificates;
+    @UriParam
+    private boolean overrideEndpoint;
+    @UriParam
+    private String uriEndpointOverride;
+    @UriParam(label = "security")
+    private boolean useDefaultCredentialsProvider;
+    @UriParam(label = "security")
+    private boolean useProfileCredentialsProvider;
+    @UriParam(label = "security")
+    private boolean useSessionCredentials;
+    @UriParam(label = "security")
+    private String profileCredentialsName;
+
+    public PollyClient getPollyClient() {
+        return pollyClient;
+    }
+
+    /**
+     * To use an existing configured AWS Polly client
+     */
+    public void setPollyClient(PollyClient pollyClient) {
+        this.pollyClient = pollyClient;
+    }
+
+    public String getAccessKey() {
+        return accessKey;
+    }
+
+    /**
+     * Amazon AWS Access Key
+     */
+    public void setAccessKey(String accessKey) {
+        this.accessKey = accessKey;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    /**
+     * Amazon AWS Secret Key
+     */
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getSessionToken() {
+        return sessionToken;
+    }
+
+    /**
+     * Amazon AWS Session Token used when the user needs to assume an IAM role
+     */
+    public void setSessionToken(String sessionToken) {
+        this.sessionToken = sessionToken;
+    }
+
+    public Polly2Operations getOperation() {
+        return operation;
+    }
+
+    /**
+     * The operation to perform
+     */
+    public void setOperation(Polly2Operations operation) {
+        this.operation = operation;
+    }
+
+    public Protocol getProxyProtocol() {
+        return proxyProtocol;
+    }
+
+    /**
+     * To define a proxy protocol when instantiating the Polly client
+     */
+    public void setProxyProtocol(Protocol proxyProtocol) {
+        this.proxyProtocol = proxyProtocol;
+    }
+
+    public String getProxyHost() {
+        return proxyHost;
+    }
+
+    /**
+     * To define a proxy host when instantiating the Polly client
+     */
+    public void setProxyHost(String proxyHost) {
+        this.proxyHost = proxyHost;
+    }
+
+    public Integer getProxyPort() {
+        return proxyPort;
+    }
+
+    /**
+     * To define a proxy port when instantiating the Polly client
+     */
+    public void setProxyPort(Integer proxyPort) {
+        this.proxyPort = proxyPort;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    /**
+     * The region in which the Polly client needs to work. When using this parameter, the configuration will expect the
+     * lowercase name of the region (for example, ap-east-1) You'll need to use the name Region.EU_WEST_1.id()
+     */
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public VoiceId getVoiceId() {
+        return voiceId;
+    }
+
+    /**
+     * The voice ID to use for speech synthesis. If not set, it must be provided as a header.
+     */
+    public void setVoiceId(VoiceId voiceId) {
+        this.voiceId = voiceId;
+    }
+
+    public OutputFormat getOutputFormat() {
+        return outputFormat;
+    }
+
+    /**
+     * The audio format in which the resulting stream will be encoded
+     */
+    public void setOutputFormat(OutputFormat outputFormat) {
+        this.outputFormat = outputFormat;
+    }
+
+    public TextType getTextType() {
+        return textType;
+    }
+
+    /**
+     * Specifies whether the input text is plain text or SSML
+     */
+    public void setTextType(TextType textType) {
+        this.textType = textType;
+    }
+
+    public Engine getEngine() {
+        return engine;
+    }
+
+    /**
+     * Specifies the engine (standard, neural, long-form, generative) for Amazon Polly to use when processing input text
+     * for speech synthesis
+     */
+    public void setEngine(Engine engine) {
+        this.engine = engine;
+    }
+
+    public String getSampleRate() {
+        return sampleRate;
+    }
+
+    /**
+     * The audio frequency in Hz
+     */
+    public void setSampleRate(String sampleRate) {
+        this.sampleRate = sampleRate;
+    }
+
+    public String getLanguageCode() {
+        return languageCode;
+    }
+
+    /**
+     * Optional language code for voice synthesis. This is only necessary if using a bilingual voice.
+     */
+    public void setLanguageCode(String languageCode) {
+        this.languageCode = languageCode;
+    }
+
+    public String getLexiconNames() {
+        return lexiconNames;
+    }
+
+    /**
+     * Comma-separated list of lexicon names to apply during synthesis
+     */
+    public void setLexiconNames(String lexiconNames) {
+        this.lexiconNames = lexiconNames;
+    }
+
+    public boolean isPojoRequest() {
+        return pojoRequest;
+    }
+
+    /**
+     * If we want to use a POJO request as body or not
+     */
+    public void setPojoRequest(boolean pojoRequest) {
+        this.pojoRequest = pojoRequest;
+    }
+
+    public boolean isTrustAllCertificates() {
+        return trustAllCertificates;
+    }
+
+    /**
+     * If we want to trust all certificates in case of overriding the endpoint
+     */
+    public void setTrustAllCertificates(boolean trustAllCertificates) {
+        this.trustAllCertificates = trustAllCertificates;
+    }
+
+    public boolean isOverrideEndpoint() {
+        return overrideEndpoint;
+    }
+
+    /**
+     * Set the need for overriding the endpoint. This option needs to be used in combination with the
+     * uriEndpointOverride option
+     */
+    public void setOverrideEndpoint(boolean overrideEndpoint) {
+        this.overrideEndpoint = overrideEndpoint;
+    }
+
+    public String getUriEndpointOverride() {
+        return uriEndpointOverride;
+    }
+
+    /**
+     * Set the overriding uri endpoint. This option needs to be used in combination with overrideEndpoint option
+     */
+    public void setUriEndpointOverride(String uriEndpointOverride) {
+        this.uriEndpointOverride = uriEndpointOverride;
+    }
+
+    /**
+     * Set whether the Polly client should expect to load credentials through a default credentials provider or to
+     * expect static credentials to be passed in.
+     */
+    public void setUseDefaultCredentialsProvider(Boolean useDefaultCredentialsProvider) {
+        this.useDefaultCredentialsProvider = useDefaultCredentialsProvider;
+    }
+
+    public boolean isUseDefaultCredentialsProvider() {
+        return useDefaultCredentialsProvider;
+    }
+
+    public boolean isUseProfileCredentialsProvider() {
+        return useProfileCredentialsProvider;
+    }
+
+    /**
+     * Set whether the Polly client should expect to load credentials through a profile credentials provider.
+     */
+    public void setUseProfileCredentialsProvider(boolean useProfileCredentialsProvider) {
+        this.useProfileCredentialsProvider = useProfileCredentialsProvider;
+    }
+
+    public boolean isUseSessionCredentials() {
+        return useSessionCredentials;
+    }
+
+    /**
+     * Set whether the Polly client should expect to use Session Credentials. This is useful in a situation in which the
+     * user needs to assume an IAM role for doing operations in Polly.
+     */
+    public void setUseSessionCredentials(boolean useSessionCredentials) {
+        this.useSessionCredentials = useSessionCredentials;
+    }
+
+    public String getProfileCredentialsName() {
+        return profileCredentialsName;
+    }
+
+    /**
+     * If using a profile credentials provider, this parameter will set the profile name
+     */
+    public void setProfileCredentialsName(String profileCredentialsName) {
+        this.profileCredentialsName = profileCredentialsName;
+    }
+    // *************************************************
+    //
+    // *************************************************
+
+    public Polly2Configuration copy() {
+        try {
+            return (Polly2Configuration) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Constants.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Constants.java
new file mode 100644
index 000000000000..41e3a66632a5
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Constants.java
@@ -0,0 +1,61 @@
+/*
+ * 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.component.aws2.polly;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Constants used in Camel AWS2 Polly module
+ */
+public interface Polly2Constants {
+    @Metadata(description = "The operation we want to perform", javaType = "String")
+    String OPERATION = "CamelAwsPollyOperation";
+    @Metadata(description = "The voice ID to use for synthesis",
+              javaType = "software.amazon.awssdk.services.polly.model.VoiceId")
+    String VOICE_ID = "CamelAwsPollyVoiceId";
+    @Metadata(description = "The output format for the audio stream",
+              javaType = "software.amazon.awssdk.services.polly.model.OutputFormat")
+    String OUTPUT_FORMAT = "CamelAwsPollyOutputFormat";
+    @Metadata(description = "The type of text input (text or ssml)",
+              javaType = "software.amazon.awssdk.services.polly.model.TextType")
+    String TEXT_TYPE = "CamelAwsPollyTextType";
+    @Metadata(description = "The sample rate in Hz", javaType = "String")
+    String SAMPLE_RATE = "CamelAwsPollySampleRate";
+    @Metadata(description = "The engine to use (standard, neural, long-form, generative)",
+              javaType = "software.amazon.awssdk.services.polly.model.Engine")
+    String ENGINE = "CamelAwsPollyEngine";
+    @Metadata(description = "The language code", javaType = "String")
+    String LANGUAGE_CODE = "CamelAwsPollyLanguageCode";
+    @Metadata(description = "Comma-separated list of lexicon names", javaType = "String")
+    String LEXICON_NAMES = "CamelAwsPollyLexiconNames";
+    @Metadata(description = "The name of the lexicon", javaType = "String")
+    String LEXICON_NAME = "CamelAwsPollyLexiconName";
+    @Metadata(description = "The content of the lexicon in PLS format", javaType = "String")
+    String LEXICON_CONTENT = "CamelAwsPollyLexiconContent";
+    @Metadata(description = "The task ID for speech synthesis task", javaType = "String")
+    String TASK_ID = "CamelAwsPollyTaskId";
+    @Metadata(description = "The S3 bucket name for output", javaType = "String")
+    String S3_BUCKET = "CamelAwsPollyS3Bucket";
+    @Metadata(description = "The S3 key prefix for output", javaType = "String")
+    String S3_KEY_PREFIX = "CamelAwsPollyS3KeyPrefix";
+    @Metadata(description = "The SNS topic ARN for notifications", javaType = "String")
+    String SNS_TOPIC_ARN = "CamelAwsPollySnsTopicArn";
+    @Metadata(description = "The content type of the audio stream", javaType = "String")
+    String CONTENT_TYPE = "CamelAwsPollyContentType";
+    @Metadata(description = "Number of characters synthesized", javaType = "Integer")
+    String REQUEST_CHARACTERS = "CamelAwsPollyRequestCharacters";
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Endpoint.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Endpoint.java
new file mode 100644
index 000000000000..d9507dd51de9
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Endpoint.java
@@ -0,0 +1,108 @@
+/*
+ * 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.component.aws2.polly;
+
+import org.apache.camel.Category;
+import org.apache.camel.Component;
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.aws2.polly.client.Polly2ClientFactory;
+import org.apache.camel.spi.EndpointServiceLocation;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.support.ScheduledPollEndpoint;
+import org.apache.camel.util.ObjectHelper;
+import software.amazon.awssdk.services.polly.PollyClient;
+
+/**
+ * Synthesize speech using AWS Polly and AWS SDK version 2.x.
+ */
+@UriEndpoint(firstVersion = "4.18.0", scheme = "aws2-polly", title = "AWS Polly", syntax = "aws2-polly:label",
+             producerOnly = true, category = { Category.CLOUD, Category.AI }, headersClass = Polly2Constants.class)
+public class Polly2Endpoint extends ScheduledPollEndpoint implements EndpointServiceLocation {
+
+    private PollyClient pollyClient;
+
+    @UriParam
+    private Polly2Configuration configuration;
+
+    public Polly2Endpoint(String uri, Component component, Polly2Configuration configuration) {
+        super(uri, component);
+        this.configuration = configuration;
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+        throw new UnsupportedOperationException("You cannot receive messages from this endpoint");
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new Polly2Producer(this);
+    }
+
+    @Override
+    public Polly2Component getComponent() {
+        return (Polly2Component) super.getComponent();
+    }
+
+    @Override
+    public void doStart() throws Exception {
+        super.doStart();
+
+        pollyClient
+                = configuration.getPollyClient() != null
+                        ? configuration.getPollyClient()
+                        : Polly2ClientFactory.getPollyClient(configuration);
+    }
+
+    @Override
+    public void doStop() throws Exception {
+        if (ObjectHelper.isEmpty(configuration.getPollyClient())) {
+            if (pollyClient != null) {
+                pollyClient.close();
+            }
+        }
+        super.doStop();
+    }
+
+    public Polly2Configuration getConfiguration() {
+        return configuration;
+    }
+
+    public PollyClient getPollyClient() {
+        return pollyClient;
+    }
+
+    @Override
+    public String getServiceUrl() {
+        if (!configuration.isOverrideEndpoint()) {
+            if (ObjectHelper.isNotEmpty(configuration.getRegion())) {
+                return configuration.getRegion();
+            }
+        } else if (ObjectHelper.isNotEmpty(configuration.getUriEndpointOverride())) {
+            return configuration.getUriEndpointOverride();
+        }
+        return null;
+    }
+
+    @Override
+    public String getServiceProtocol() {
+        return "polly";
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Operations.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Operations.java
new file mode 100644
index 000000000000..54a27e6cd844
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Operations.java
@@ -0,0 +1,30 @@
+/*
+ * 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.component.aws2.polly;
+
+public enum Polly2Operations {
+
+    synthesizeSpeech,
+    describeVoices,
+    listLexicons,
+    getLexicon,
+    putLexicon,
+    deleteLexicon,
+    startSpeechSynthesisTask,
+    getSpeechSynthesisTask,
+    listSpeechSynthesisTasks
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Producer.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Producer.java
new file mode 100644
index 000000000000..bdbd4a80e96b
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2Producer.java
@@ -0,0 +1,624 @@
+/*
+ * 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.component.aws2.polly;
+
+import java.util.Arrays;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.WritableHealthCheckRepository;
+import org.apache.camel.support.DefaultProducer;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.awscore.exception.AwsServiceException;
+import software.amazon.awssdk.core.ResponseInputStream;
+import software.amazon.awssdk.services.polly.PollyClient;
+import software.amazon.awssdk.services.polly.model.DeleteLexiconRequest;
+import software.amazon.awssdk.services.polly.model.DeleteLexiconResponse;
+import software.amazon.awssdk.services.polly.model.DescribeVoicesRequest;
+import software.amazon.awssdk.services.polly.model.DescribeVoicesResponse;
+import software.amazon.awssdk.services.polly.model.Engine;
+import software.amazon.awssdk.services.polly.model.GetLexiconRequest;
+import software.amazon.awssdk.services.polly.model.GetLexiconResponse;
+import software.amazon.awssdk.services.polly.model.GetSpeechSynthesisTaskRequest;
+import software.amazon.awssdk.services.polly.model.GetSpeechSynthesisTaskResponse;
+import software.amazon.awssdk.services.polly.model.ListLexiconsRequest;
+import software.amazon.awssdk.services.polly.model.ListLexiconsResponse;
+import software.amazon.awssdk.services.polly.model.ListSpeechSynthesisTasksRequest;
+import software.amazon.awssdk.services.polly.model.ListSpeechSynthesisTasksResponse;
+import software.amazon.awssdk.services.polly.model.OutputFormat;
+import software.amazon.awssdk.services.polly.model.PutLexiconRequest;
+import software.amazon.awssdk.services.polly.model.PutLexiconResponse;
+import software.amazon.awssdk.services.polly.model.StartSpeechSynthesisTaskRequest;
+import software.amazon.awssdk.services.polly.model.StartSpeechSynthesisTaskResponse;
+import software.amazon.awssdk.services.polly.model.SynthesizeSpeechRequest;
+import software.amazon.awssdk.services.polly.model.SynthesizeSpeechResponse;
+import software.amazon.awssdk.services.polly.model.TextType;
+import software.amazon.awssdk.services.polly.model.VoiceId;
+
+/**
+ * A Producer which sends messages to the Amazon Polly Service SDK v2 <a href="http://aws.amazon.com/polly/">AWS
+ * Polly</a>
+ */
+public class Polly2Producer extends DefaultProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Polly2Producer.class);
+    private transient String pollyProducerToString;
+    private HealthCheck producerHealthCheck;
+    private WritableHealthCheckRepository healthCheckRepository;
+
+    public Polly2Producer(Endpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        switch (determineOperation(exchange)) {
+            case synthesizeSpeech:
+                synthesizeSpeech(getEndpoint().getPollyClient(), exchange);
+                break;
+            case describeVoices:
+                describeVoices(getEndpoint().getPollyClient(), exchange);
+                break;
+            case listLexicons:
+                listLexicons(getEndpoint().getPollyClient(), exchange);
+                break;
+            case getLexicon:
+                getLexicon(getEndpoint().getPollyClient(), exchange);
+                break;
+            case putLexicon:
+                putLexicon(getEndpoint().getPollyClient(), exchange);
+                break;
+            case deleteLexicon:
+                deleteLexicon(getEndpoint().getPollyClient(), exchange);
+                break;
+            case startSpeechSynthesisTask:
+                startSpeechSynthesisTask(getEndpoint().getPollyClient(), exchange);
+                break;
+            case getSpeechSynthesisTask:
+                getSpeechSynthesisTask(getEndpoint().getPollyClient(), exchange);
+                break;
+            case listSpeechSynthesisTasks:
+                listSpeechSynthesisTasks(getEndpoint().getPollyClient(), exchange);
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported operation");
+        }
+    }
+
+    private Polly2Operations determineOperation(Exchange exchange) {
+        Polly2Operations operation = exchange.getIn().getHeader(Polly2Constants.OPERATION, Polly2Operations.class);
+        if (operation == null) {
+            operation = getConfiguration().getOperation();
+        }
+        return operation;
+    }
+
+    protected Polly2Configuration getConfiguration() {
+        return getEndpoint().getConfiguration();
+    }
+
+    @Override
+    public String toString() {
+        if (pollyProducerToString == null) {
+            pollyProducerToString = "PollyProducer[" + URISupport.sanitizeUri(getEndpoint().getEndpointUri()) + "]";
+        }
+        return pollyProducerToString;
+    }
+
+    @Override
+    public Polly2Endpoint getEndpoint() {
+        return (Polly2Endpoint) super.getEndpoint();
+    }
+
+    private void synthesizeSpeech(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof SynthesizeSpeechRequest) {
+                ResponseInputStream<SynthesizeSpeechResponse> result;
+                try {
+                    result = pollyClient.synthesizeSpeech((SynthesizeSpeechRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Synthesize Speech command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result);
+                if (result.response().contentType() != null) {
+                    message.setHeader(Polly2Constants.CONTENT_TYPE, result.response().contentType());
+                }
+                message.setHeader(Polly2Constants.REQUEST_CHARACTERS, result.response().requestCharacters());
+            }
+        } else {
+            SynthesizeSpeechRequest.Builder request = SynthesizeSpeechRequest.builder();
+
+            // Set voice ID
+            VoiceId voiceId = exchange.getIn().getHeader(Polly2Constants.VOICE_ID, VoiceId.class);
+            if (voiceId == null) {
+                voiceId = getConfiguration().getVoiceId();
+            }
+            if (voiceId == null) {
+                throw new IllegalArgumentException("Voice ID must be specified as header or endpoint option");
+            }
+            request.voiceId(voiceId);
+
+            // Set output format
+            OutputFormat outputFormat = exchange.getIn().getHeader(Polly2Constants.OUTPUT_FORMAT, OutputFormat.class);
+            if (outputFormat == null) {
+                outputFormat = getConfiguration().getOutputFormat();
+            }
+            request.outputFormat(outputFormat);
+
+            // Set text type
+            TextType textType = exchange.getIn().getHeader(Polly2Constants.TEXT_TYPE, TextType.class);
+            if (textType == null) {
+                textType = getConfiguration().getTextType();
+            }
+            request.textType(textType);
+
+            // Set engine
+            Engine engine = exchange.getIn().getHeader(Polly2Constants.ENGINE, Engine.class);
+            if (engine == null && getConfiguration().getEngine() != null) {
+                engine = getConfiguration().getEngine();
+            }
+            if (engine != null) {
+                request.engine(engine);
+            }
+
+            // Set sample rate
+            String sampleRate = exchange.getIn().getHeader(Polly2Constants.SAMPLE_RATE, String.class);
+            if (sampleRate == null) {
+                sampleRate = getConfiguration().getSampleRate();
+            }
+            if (sampleRate != null) {
+                request.sampleRate(sampleRate);
+            }
+
+            // Set language code
+            String languageCode = exchange.getIn().getHeader(Polly2Constants.LANGUAGE_CODE, String.class);
+            if (languageCode == null) {
+                languageCode = getConfiguration().getLanguageCode();
+            }
+            if (languageCode != null) {
+                request.languageCode(languageCode);
+            }
+
+            // Set lexicon names
+            String lexiconNames = exchange.getIn().getHeader(Polly2Constants.LEXICON_NAMES, String.class);
+            if (lexiconNames == null) {
+                lexiconNames = getConfiguration().getLexiconNames();
+            }
+            if (lexiconNames != null) {
+                request.lexiconNames(Arrays.asList(lexiconNames.split(",")));
+            }
+
+            // Set the text to synthesize
+            request.text(exchange.getMessage().getBody(String.class));
+
+            ResponseInputStream<SynthesizeSpeechResponse> result;
+            try {
+                result = pollyClient.synthesizeSpeech(request.build());
+            } catch (AwsServiceException ase) {
+                LOG.trace("Synthesize Speech command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result);
+            if (result.response().contentType() != null) {
+                message.setHeader(Polly2Constants.CONTENT_TYPE, result.response().contentType());
+            }
+            message.setHeader(Polly2Constants.REQUEST_CHARACTERS, result.response().requestCharacters());
+        }
+    }
+
+    private void describeVoices(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof DescribeVoicesRequest) {
+                DescribeVoicesResponse result;
+                try {
+                    result = pollyClient.describeVoices((DescribeVoicesRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Describe Voices command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.voices());
+            }
+        } else {
+            DescribeVoicesRequest.Builder request = DescribeVoicesRequest.builder();
+
+            // Set engine filter
+            Engine engine = exchange.getIn().getHeader(Polly2Constants.ENGINE, Engine.class);
+            if (engine == null && getConfiguration().getEngine() != null) {
+                engine = getConfiguration().getEngine();
+            }
+            if (engine != null) {
+                request.engine(engine);
+            }
+
+            // Set language code filter
+            String languageCode = exchange.getIn().getHeader(Polly2Constants.LANGUAGE_CODE, String.class);
+            if (languageCode == null) {
+                languageCode = getConfiguration().getLanguageCode();
+            }
+            if (languageCode != null) {
+                request.languageCode(languageCode);
+            }
+
+            DescribeVoicesResponse result;
+            try {
+                result = pollyClient.describeVoices(request.build());
+            } catch (AwsServiceException ase) {
+                LOG.trace("Describe Voices command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.voices());
+        }
+    }
+
+    private void listLexicons(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof ListLexiconsRequest) {
+                ListLexiconsResponse result;
+                try {
+                    result = pollyClient.listLexicons((ListLexiconsRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("List Lexicons command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.lexicons());
+            }
+        } else {
+            ListLexiconsRequest request = ListLexiconsRequest.builder().build();
+            ListLexiconsResponse result;
+            try {
+                result = pollyClient.listLexicons(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("List Lexicons command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.lexicons());
+        }
+    }
+
+    private void getLexicon(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof GetLexiconRequest) {
+                GetLexiconResponse result;
+                try {
+                    result = pollyClient.getLexicon((GetLexiconRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Get Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.lexicon());
+            }
+        } else {
+            String lexiconName = exchange.getIn().getHeader(Polly2Constants.LEXICON_NAME, String.class);
+            if (ObjectHelper.isEmpty(lexiconName)) {
+                throw new IllegalArgumentException("Lexicon name must be specified");
+            }
+            GetLexiconRequest request = GetLexiconRequest.builder().name(lexiconName).build();
+            GetLexiconResponse result;
+            try {
+                result = pollyClient.getLexicon(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("Get Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.lexicon());
+        }
+    }
+
+    private void putLexicon(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof PutLexiconRequest) {
+                PutLexiconResponse result;
+                try {
+                    result = pollyClient.putLexicon((PutLexiconRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Put Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result);
+            }
+        } else {
+            String lexiconName = exchange.getIn().getHeader(Polly2Constants.LEXICON_NAME, String.class);
+            String lexiconContent = exchange.getIn().getHeader(Polly2Constants.LEXICON_CONTENT, String.class);
+            if (ObjectHelper.isEmpty(lexiconContent)) {
+                lexiconContent = exchange.getMessage().getBody(String.class);
+            }
+            if (ObjectHelper.isEmpty(lexiconName)) {
+                throw new IllegalArgumentException("Lexicon name must be specified");
+            }
+            if (ObjectHelper.isEmpty(lexiconContent)) {
+                throw new IllegalArgumentException("Lexicon content must be specified");
+            }
+            PutLexiconRequest request = PutLexiconRequest.builder()
+                    .name(lexiconName)
+                    .content(lexiconContent)
+                    .build();
+            PutLexiconResponse result;
+            try {
+                result = pollyClient.putLexicon(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("Put Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result);
+        }
+    }
+
+    private void deleteLexicon(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof DeleteLexiconRequest) {
+                DeleteLexiconResponse result;
+                try {
+                    result = pollyClient.deleteLexicon((DeleteLexiconRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Delete Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result);
+            }
+        } else {
+            String lexiconName = exchange.getIn().getHeader(Polly2Constants.LEXICON_NAME, String.class);
+            if (ObjectHelper.isEmpty(lexiconName)) {
+                throw new IllegalArgumentException("Lexicon name must be specified");
+            }
+            DeleteLexiconRequest request = DeleteLexiconRequest.builder().name(lexiconName).build();
+            DeleteLexiconResponse result;
+            try {
+                result = pollyClient.deleteLexicon(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("Delete Lexicon command returned the error code {}", ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result);
+        }
+    }
+
+    private void startSpeechSynthesisTask(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof StartSpeechSynthesisTaskRequest) {
+                StartSpeechSynthesisTaskResponse result;
+                try {
+                    result = pollyClient.startSpeechSynthesisTask((StartSpeechSynthesisTaskRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Start Speech Synthesis Task command returned the error code {}",
+                            ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.synthesisTask());
+                message.setHeader(Polly2Constants.TASK_ID, result.synthesisTask().taskId());
+            }
+        } else {
+            StartSpeechSynthesisTaskRequest.Builder request = StartSpeechSynthesisTaskRequest.builder();
+
+            // Set voice ID
+            VoiceId voiceId = exchange.getIn().getHeader(Polly2Constants.VOICE_ID, VoiceId.class);
+            if (voiceId == null) {
+                voiceId = getConfiguration().getVoiceId();
+            }
+            if (voiceId == null) {
+                throw new IllegalArgumentException("Voice ID must be specified as header or endpoint option");
+            }
+            request.voiceId(voiceId);
+
+            // Set output format
+            OutputFormat outputFormat = exchange.getIn().getHeader(Polly2Constants.OUTPUT_FORMAT, OutputFormat.class);
+            if (outputFormat == null) {
+                outputFormat = getConfiguration().getOutputFormat();
+            }
+            request.outputFormat(outputFormat);
+
+            // Set S3 bucket
+            String s3Bucket = exchange.getIn().getHeader(Polly2Constants.S3_BUCKET, String.class);
+            if (ObjectHelper.isEmpty(s3Bucket)) {
+                throw new IllegalArgumentException("S3 bucket must be specified for async synthesis");
+            }
+            request.outputS3BucketName(s3Bucket);
+
+            // Set S3 key prefix (optional)
+            String s3KeyPrefix = exchange.getIn().getHeader(Polly2Constants.S3_KEY_PREFIX, String.class);
+            if (ObjectHelper.isNotEmpty(s3KeyPrefix)) {
+                request.outputS3KeyPrefix(s3KeyPrefix);
+            }
+
+            // Set SNS topic ARN (optional)
+            String snsTopicArn = exchange.getIn().getHeader(Polly2Constants.SNS_TOPIC_ARN, String.class);
+            if (ObjectHelper.isNotEmpty(snsTopicArn)) {
+                request.snsTopicArn(snsTopicArn);
+            }
+
+            // Set text type
+            TextType textType = exchange.getIn().getHeader(Polly2Constants.TEXT_TYPE, TextType.class);
+            if (textType == null) {
+                textType = getConfiguration().getTextType();
+            }
+            request.textType(textType);
+
+            // Set engine
+            Engine engine = exchange.getIn().getHeader(Polly2Constants.ENGINE, Engine.class);
+            if (engine == null && getConfiguration().getEngine() != null) {
+                engine = getConfiguration().getEngine();
+            }
+            if (engine != null) {
+                request.engine(engine);
+            }
+
+            // Set sample rate
+            String sampleRate = exchange.getIn().getHeader(Polly2Constants.SAMPLE_RATE, String.class);
+            if (sampleRate == null) {
+                sampleRate = getConfiguration().getSampleRate();
+            }
+            if (sampleRate != null) {
+                request.sampleRate(sampleRate);
+            }
+
+            // Set language code
+            String languageCode = exchange.getIn().getHeader(Polly2Constants.LANGUAGE_CODE, String.class);
+            if (languageCode == null) {
+                languageCode = getConfiguration().getLanguageCode();
+            }
+            if (languageCode != null) {
+                request.languageCode(languageCode);
+            }
+
+            // Set lexicon names
+            String lexiconNames = exchange.getIn().getHeader(Polly2Constants.LEXICON_NAMES, String.class);
+            if (lexiconNames == null) {
+                lexiconNames = getConfiguration().getLexiconNames();
+            }
+            if (lexiconNames != null) {
+                request.lexiconNames(Arrays.asList(lexiconNames.split(",")));
+            }
+
+            // Set the text to synthesize
+            request.text(exchange.getMessage().getBody(String.class));
+
+            StartSpeechSynthesisTaskResponse result;
+            try {
+                result = pollyClient.startSpeechSynthesisTask(request.build());
+            } catch (AwsServiceException ase) {
+                LOG.trace("Start Speech Synthesis Task command returned the error code {}",
+                        ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.synthesisTask());
+            message.setHeader(Polly2Constants.TASK_ID, result.synthesisTask().taskId());
+        }
+    }
+
+    private void getSpeechSynthesisTask(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof GetSpeechSynthesisTaskRequest) {
+                GetSpeechSynthesisTaskResponse result;
+                try {
+                    result = pollyClient.getSpeechSynthesisTask((GetSpeechSynthesisTaskRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Get Speech Synthesis Task command returned the error code {}",
+                            ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.synthesisTask());
+            }
+        } else {
+            String taskId = exchange.getIn().getHeader(Polly2Constants.TASK_ID, String.class);
+            if (ObjectHelper.isEmpty(taskId)) {
+                throw new IllegalArgumentException("Task ID must be specified");
+            }
+            GetSpeechSynthesisTaskRequest request = GetSpeechSynthesisTaskRequest.builder()
+                    .taskId(taskId)
+                    .build();
+            GetSpeechSynthesisTaskResponse result;
+            try {
+                result = pollyClient.getSpeechSynthesisTask(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("Get Speech Synthesis Task command returned the error code {}",
+                        ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.synthesisTask());
+        }
+    }
+
+    private void listSpeechSynthesisTasks(PollyClient pollyClient, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof ListSpeechSynthesisTasksRequest) {
+                ListSpeechSynthesisTasksResponse result;
+                try {
+                    result = pollyClient.listSpeechSynthesisTasks((ListSpeechSynthesisTasksRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("List Speech Synthesis Tasks command returned the error code {}",
+                            ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result.synthesisTasks());
+            }
+        } else {
+            ListSpeechSynthesisTasksRequest request = ListSpeechSynthesisTasksRequest.builder().build();
+            ListSpeechSynthesisTasksResponse result;
+            try {
+                result = pollyClient.listSpeechSynthesisTasks(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("List Speech Synthesis Tasks command returned the error code {}",
+                        ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result.synthesisTasks());
+        }
+    }
+
+    public static Message getMessageForResponse(final Exchange exchange) {
+        return exchange.getMessage();
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        // health-check is optional so discover and resolve
+        healthCheckRepository = HealthCheckHelper.getHealthCheckRepository(
+                getEndpoint().getCamelContext(),
+                "producers",
+                WritableHealthCheckRepository.class);
+
+        if (healthCheckRepository != null) {
+            String id = getEndpoint().getId();
+            producerHealthCheck = new Polly2ProducerHealthCheck(getEndpoint(), id);
+            producerHealthCheck.setEnabled(getEndpoint().getComponent().isHealthCheckProducerEnabled());
+            healthCheckRepository.addHealthCheck(producerHealthCheck);
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (healthCheckRepository != null && producerHealthCheck != null) {
+            healthCheckRepository.removeHealthCheck(producerHealthCheck);
+            producerHealthCheck = null;
+        }
+    }
+
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2ProducerHealthCheck.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2ProducerHealthCheck.java
new file mode 100644
index 000000000000..7cd6205fa8b5
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/Polly2ProducerHealthCheck.java
@@ -0,0 +1,71 @@
+/*
+ * 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.component.aws2.polly;
+
+import java.util.Map;
+
+import org.apache.camel.health.HealthCheckResultBuilder;
+import org.apache.camel.impl.health.AbstractHealthCheck;
+import org.apache.camel.util.ObjectHelper;
+import software.amazon.awssdk.awscore.exception.AwsServiceException;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.polly.PollyClient;
+import software.amazon.awssdk.services.polly.model.DescribeVoicesRequest;
+
+public class Polly2ProducerHealthCheck extends AbstractHealthCheck {
+
+    private final Polly2Endpoint polly2Endpoint;
+
+    public Polly2ProducerHealthCheck(Polly2Endpoint polly2Endpoint, String clientId) {
+        super("camel", "producer:aws2-polly-" + clientId);
+        this.polly2Endpoint = polly2Endpoint;
+    }
+
+    @Override
+    protected void doCall(HealthCheckResultBuilder builder, Map<String, Object> options) {
+        Polly2Configuration configuration = polly2Endpoint.getConfiguration();
+        if (ObjectHelper.isNotEmpty(configuration.getRegion())) {
+            if (!PollyClient.serviceMetadata().regions().contains(Region.of(configuration.getRegion()))) {
+                builder.message("The service is not supported in this region");
+                builder.down();
+                return;
+            }
+        }
+        try {
+            PollyClient pollyClient = polly2Endpoint.getPollyClient();
+            pollyClient.describeVoices(DescribeVoicesRequest.builder().build());
+        } catch (AwsServiceException e) {
+            builder.message(e.getMessage());
+            builder.error(e);
+            if (ObjectHelper.isNotEmpty(e.statusCode())) {
+                builder.detail(SERVICE_STATUS_CODE, e.statusCode());
+            }
+            if (ObjectHelper.isNotEmpty(e.awsErrorDetails().errorCode())) {
+                builder.detail(SERVICE_ERROR_CODE, e.awsErrorDetails().errorCode());
+            }
+            builder.down();
+            return;
+        } catch (Exception e) {
+            builder.error(e);
+            builder.down();
+            return;
+        }
+        builder.up();
+    }
+
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/client/Polly2ClientFactory.java b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/client/Polly2ClientFactory.java
new file mode 100644
index 000000000000..6e378e6a5212
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/main/java/org/apache/camel/component/aws2/polly/client/Polly2ClientFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.component.aws2.polly.client;
+
+import org.apache.camel.component.aws.common.AwsClientBuilderUtil;
+import org.apache.camel.component.aws2.polly.Polly2Configuration;
+import software.amazon.awssdk.services.polly.PollyClient;
+
+/**
+ * Factory class to create AWS Polly clients using common configuration.
+ */
+public final class Polly2ClientFactory {
+
+    private Polly2ClientFactory() {
+    }
+
+    /**
+     * Create a PollyClient based on configuration.
+     *
+     * @param  configuration The Polly configuration
+     * @return               Configured PollyClient
+     */
+    public static PollyClient getPollyClient(Polly2Configuration configuration) {
+        return AwsClientBuilderUtil.buildClient(
+                configuration,
+                PollyClient::builder);
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/AmazonPollyClientMock.java b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/AmazonPollyClientMock.java
new file mode 100644
index 000000000000..36967ff75da4
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/AmazonPollyClientMock.java
@@ -0,0 +1,187 @@
+/*
+ * 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.component.aws2.polly;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import software.amazon.awssdk.core.ResponseInputStream;
+import software.amazon.awssdk.http.AbortableInputStream;
+import software.amazon.awssdk.services.polly.PollyClient;
+import software.amazon.awssdk.services.polly.PollyServiceClientConfiguration;
+import software.amazon.awssdk.services.polly.model.DeleteLexiconRequest;
+import software.amazon.awssdk.services.polly.model.DeleteLexiconResponse;
+import software.amazon.awssdk.services.polly.model.DescribeVoicesRequest;
+import software.amazon.awssdk.services.polly.model.DescribeVoicesResponse;
+import software.amazon.awssdk.services.polly.model.Engine;
+import software.amazon.awssdk.services.polly.model.Gender;
+import software.amazon.awssdk.services.polly.model.GetLexiconRequest;
+import software.amazon.awssdk.services.polly.model.GetLexiconResponse;
+import software.amazon.awssdk.services.polly.model.GetSpeechSynthesisTaskRequest;
+import software.amazon.awssdk.services.polly.model.GetSpeechSynthesisTaskResponse;
+import software.amazon.awssdk.services.polly.model.LanguageCode;
+import software.amazon.awssdk.services.polly.model.Lexicon;
+import software.amazon.awssdk.services.polly.model.LexiconDescription;
+import software.amazon.awssdk.services.polly.model.ListLexiconsRequest;
+import software.amazon.awssdk.services.polly.model.ListLexiconsResponse;
+import software.amazon.awssdk.services.polly.model.ListSpeechSynthesisTasksRequest;
+import software.amazon.awssdk.services.polly.model.ListSpeechSynthesisTasksResponse;
+import software.amazon.awssdk.services.polly.model.OutputFormat;
+import software.amazon.awssdk.services.polly.model.PutLexiconRequest;
+import software.amazon.awssdk.services.polly.model.PutLexiconResponse;
+import software.amazon.awssdk.services.polly.model.StartSpeechSynthesisTaskRequest;
+import software.amazon.awssdk.services.polly.model.StartSpeechSynthesisTaskResponse;
+import software.amazon.awssdk.services.polly.model.SynthesisTask;
+import software.amazon.awssdk.services.polly.model.SynthesizeSpeechRequest;
+import software.amazon.awssdk.services.polly.model.SynthesizeSpeechResponse;
+import software.amazon.awssdk.services.polly.model.TaskStatus;
+import software.amazon.awssdk.services.polly.model.Voice;
+import software.amazon.awssdk.services.polly.model.VoiceId;
+
+public class AmazonPollyClientMock implements PollyClient {
+
+    @Override
+    public ResponseInputStream<SynthesizeSpeechResponse> synthesizeSpeech(SynthesizeSpeechRequest request) {
+        SynthesizeSpeechResponse response = SynthesizeSpeechResponse.builder()
+                .contentType("audio/mpeg")
+                .requestCharacters(request.text().length())
+                .build();
+
+        byte[] audioData = "mock-audio-data".getBytes(StandardCharsets.UTF_8);
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(audioData);
+        AbortableInputStream abortableInputStream = AbortableInputStream.create(inputStream);
+
+        return new ResponseInputStream<>(response, abortableInputStream);
+    }
+
+    @Override
+    public DescribeVoicesResponse describeVoices(DescribeVoicesRequest request) {
+        Voice voice1 = Voice.builder()
+                .id(VoiceId.JOANNA)
+                .name("Joanna")
+                .languageCode(LanguageCode.EN_US)
+                .languageName("US English")
+                .gender(Gender.FEMALE)
+                .supportedEngines(Engine.NEURAL, Engine.STANDARD)
+                .build();
+
+        Voice voice2 = Voice.builder()
+                .id(VoiceId.MATTHEW)
+                .name("Matthew")
+                .languageCode(LanguageCode.EN_US)
+                .languageName("US English")
+                .gender(Gender.MALE)
+                .supportedEngines(Engine.NEURAL, Engine.STANDARD)
+                .build();
+
+        return DescribeVoicesResponse.builder()
+                .voices(Arrays.asList(voice1, voice2))
+                .build();
+    }
+
+    @Override
+    public ListLexiconsResponse listLexicons(ListLexiconsRequest request) {
+        LexiconDescription lexicon = LexiconDescription.builder()
+                .name("TestLexicon")
+                .build();
+
+        return ListLexiconsResponse.builder()
+                .lexicons(Arrays.asList(lexicon))
+                .build();
+    }
+
+    @Override
+    public GetLexiconResponse getLexicon(GetLexiconRequest request) {
+        Lexicon lexicon = Lexicon.builder()
+                .name(request.name())
+                .content("<?xml version=\"1.0\" encoding=\"UTF-8\"?><lexicon></lexicon>")
+                .build();
+
+        return GetLexiconResponse.builder()
+                .lexicon(lexicon)
+                .build();
+    }
+
+    @Override
+    public PutLexiconResponse putLexicon(PutLexiconRequest request) {
+        return PutLexiconResponse.builder().build();
+    }
+
+    @Override
+    public DeleteLexiconResponse deleteLexicon(DeleteLexiconRequest request) {
+        return DeleteLexiconResponse.builder().build();
+    }
+
+    @Override
+    public StartSpeechSynthesisTaskResponse startSpeechSynthesisTask(StartSpeechSynthesisTaskRequest request) {
+        SynthesisTask task = SynthesisTask.builder()
+                .taskId("test-task-id-123")
+                .taskStatus(TaskStatus.IN_PROGRESS)
+                .outputFormat(request.outputFormat())
+                .voiceId(request.voiceId())
+                .outputUri("s3://" + request.outputS3BucketName() + "/output.mp3")
+                .build();
+
+        return StartSpeechSynthesisTaskResponse.builder()
+                .synthesisTask(task)
+                .build();
+    }
+
+    @Override
+    public GetSpeechSynthesisTaskResponse getSpeechSynthesisTask(GetSpeechSynthesisTaskRequest request) {
+        SynthesisTask task = SynthesisTask.builder()
+                .taskId(request.taskId())
+                .taskStatus(TaskStatus.COMPLETED)
+                .outputFormat(OutputFormat.MP3)
+                .voiceId(VoiceId.JOANNA)
+                .outputUri("s3://test-bucket/output.mp3")
+                .build();
+
+        return GetSpeechSynthesisTaskResponse.builder()
+                .synthesisTask(task)
+                .build();
+    }
+
+    @Override
+    public ListSpeechSynthesisTasksResponse listSpeechSynthesisTasks(ListSpeechSynthesisTasksRequest request) {
+        SynthesisTask task = SynthesisTask.builder()
+                .taskId("test-task-id-123")
+                .taskStatus(TaskStatus.COMPLETED)
+                .outputFormat(OutputFormat.MP3)
+                .voiceId(VoiceId.JOANNA)
+                .build();
+
+        return ListSpeechSynthesisTasksResponse.builder()
+                .synthesisTasks(Arrays.asList(task))
+                .build();
+    }
+
+    @Override
+    public PollyServiceClientConfiguration serviceClientConfiguration() {
+        return null;
+    }
+
+    @Override
+    public String serviceName() {
+        return "polly";
+    }
+
+    @Override
+    public void close() {
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ClientFactoryTest.java b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ClientFactoryTest.java
new file mode 100644
index 000000000000..fb9325232b60
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ClientFactoryTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.component.aws2.polly;
+
+import org.apache.camel.component.aws2.polly.client.Polly2ClientFactory;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.services.polly.PollyClient;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class Polly2ClientFactoryTest {
+
+    @Test
+    public void getClientWithAccessKeyAndSecretKey() {
+        Polly2Configuration configuration = new Polly2Configuration();
+        configuration.setAccessKey("accessKey");
+        configuration.setSecretKey("secretKey");
+        configuration.setRegion("us-east-1");
+
+        PollyClient client = Polly2ClientFactory.getPollyClient(configuration);
+        assertNotNull(client);
+        client.close();
+    }
+
+    @Test
+    public void getClientWithDefaultCredentialsProvider() {
+        Polly2Configuration configuration = new Polly2Configuration();
+        configuration.setUseDefaultCredentialsProvider(true);
+        configuration.setRegion("us-east-1");
+
+        // Just verify the client is created - actual credential resolution happens on first API call
+        PollyClient client = Polly2ClientFactory.getPollyClient(configuration);
+        assertNotNull(client);
+        client.close();
+    }
+}
diff --git a/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ProducerTest.java b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ProducerTest.java
new file mode 100644
index 000000000000..006b2283bbe9
--- /dev/null
+++ b/components/camel-aws/camel-aws2-polly/src/test/java/org/apache/camel/component/aws2/polly/Polly2ProducerTest.java
@@ -0,0 +1,282 @@
+/*
+ * 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.component.aws2.polly;
+
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.services.polly.model.Lexicon;
+import software.amazon.awssdk.services.polly.model.LexiconDescription;
+import software.amazon.awssdk.services.polly.model.OutputFormat;
+import software.amazon.awssdk.services.polly.model.SynthesisTask;
+import software.amazon.awssdk.services.polly.model.SynthesizeSpeechRequest;
+import software.amazon.awssdk.services.polly.model.Voice;
+import software.amazon.awssdk.services.polly.model.VoiceId;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class Polly2ProducerTest extends CamelTestSupport {
+
+    @BindToRegistry("amazonPollyClient")
+    AmazonPollyClientMock clientMock = new AmazonPollyClientMock();
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    @Test
+    public void synthesizeSpeechTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:synthesizeSpeech", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.VOICE_ID, VoiceId.JOANNA);
+                exchange.getIn().setBody("Hello, this is a test.");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        assertNotNull(exchange.getIn().getBody(InputStream.class));
+        assertEquals("audio/mpeg", exchange.getIn().getHeader(Polly2Constants.CONTENT_TYPE));
+    }
+
+    @Test
+    public void synthesizeSpeechWithOptionsTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:synthesizeSpeechWithOptions", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setBody("Hello, this is a test with neural engine.");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        assertNotNull(exchange.getIn().getBody(InputStream.class));
+    }
+
+    @Test
+    public void synthesizeSpeechPojoTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:synthesizeSpeechPojo", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setBody(SynthesizeSpeechRequest.builder()
+                        .voiceId(VoiceId.JOANNA)
+                        .outputFormat(OutputFormat.MP3)
+                        .text("Hello from POJO request")
+                        .build());
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        assertNotNull(exchange.getIn().getBody(InputStream.class));
+    }
+
+    @Test
+    public void describeVoicesTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:describeVoices", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        List<Voice> voices = exchange.getIn().getBody(List.class);
+        assertNotNull(voices);
+        assertEquals(2, voices.size());
+    }
+
+    @Test
+    public void listLexiconsTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:listLexicons", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        List<LexiconDescription> lexicons = exchange.getIn().getBody(List.class);
+        assertNotNull(lexicons);
+        assertEquals(1, lexicons.size());
+    }
+
+    @Test
+    public void getLexiconTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:getLexicon", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.LEXICON_NAME, "TestLexicon");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        Lexicon lexicon = exchange.getIn().getBody(Lexicon.class);
+        assertNotNull(lexicon);
+        assertEquals("TestLexicon", lexicon.name());
+    }
+
+    @Test
+    public void putLexiconTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:putLexicon", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.LEXICON_NAME, "NewLexicon");
+                exchange.getIn().setBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?><lexicon></lexicon>");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+        assertNotNull(exchange.getIn().getBody());
+    }
+
+    @Test
+    public void deleteLexiconTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:deleteLexicon", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.LEXICON_NAME, "TestLexicon");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+        assertNotNull(exchange.getIn().getBody());
+    }
+
+    @Test
+    public void startSpeechSynthesisTaskTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:startSpeechSynthesisTask", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.VOICE_ID, VoiceId.JOANNA);
+                exchange.getIn().setHeader(Polly2Constants.S3_BUCKET, "my-bucket");
+                exchange.getIn().setBody("This is a long text for async synthesis.");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        SynthesisTask task = exchange.getIn().getBody(SynthesisTask.class);
+        assertNotNull(task);
+        assertEquals("test-task-id-123", task.taskId());
+        assertEquals("test-task-id-123", exchange.getIn().getHeader(Polly2Constants.TASK_ID));
+    }
+
+    @Test
+    public void getSpeechSynthesisTaskTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:getSpeechSynthesisTask", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(Polly2Constants.TASK_ID, "test-task-id-123");
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        SynthesisTask task = exchange.getIn().getBody(SynthesisTask.class);
+        assertNotNull(task);
+        assertEquals("test-task-id-123", task.taskId());
+    }
+
+    @Test
+    public void listSpeechSynthesisTasksTest() throws Exception {
+        mock.expectedMessageCount(1);
+        Exchange exchange = template.request("direct:listSpeechSynthesisTasks", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+            }
+        });
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        List<SynthesisTask> tasks = exchange.getIn().getBody(List.class);
+        assertNotNull(tasks);
+        assertEquals(1, tasks.size());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:synthesizeSpeech")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=synthesizeSpeech")
+                        .to("mock:result");
+
+                from("direct:synthesizeSpeechWithOptions")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=synthesizeSpeech&voiceId=JOANNA&engine=NEURAL&outputFormat=MP3")
+                        .to("mock:result");
+
+                from("direct:synthesizeSpeechPojo")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=synthesizeSpeech&pojoRequest=true")
+                        .to("mock:result");
+
+                from("direct:describeVoices")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=describeVoices")
+                        .to("mock:result");
+
+                from("direct:listLexicons")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=listLexicons")
+                        .to("mock:result");
+
+                from("direct:getLexicon")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=getLexicon")
+                        .to("mock:result");
+
+                from("direct:putLexicon")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=putLexicon")
+                        .to("mock:result");
+
+                from("direct:deleteLexicon")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=deleteLexicon")
+                        .to("mock:result");
+
+                from("direct:startSpeechSynthesisTask")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=startSpeechSynthesisTask")
+                        .to("mock:result");
+
+                from("direct:getSpeechSynthesisTask")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=getSpeechSynthesisTask")
+                        .to("mock:result");
+
+                from("direct:listSpeechSynthesisTasks")
+                        .to("aws2-polly://test?pollyClient=#amazonPollyClient&operation=listSpeechSynthesisTasks")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-aws/pom.xml b/components/camel-aws/pom.xml
index d10ded276cc5..4538a09e66bf 100644
--- a/components/camel-aws/pom.xml
+++ b/components/camel-aws/pom.xml
@@ -56,6 +56,7 @@
         <module>camel-aws2-lambda</module>
         <module>camel-aws2-msk</module>
         <module>camel-aws2-mq</module>
+        <module>camel-aws2-polly</module>
         <module>camel-aws-parameter-store</module>
         <module>camel-aws2-redshift</module>
         <module>camel-aws2-s3</module>
diff --git a/parent/pom.xml b/parent/pom.xml
index ce0cfd3bc2c9..06f984cd970e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -904,6 +904,11 @@
                 <artifactId>camel-aws2-msk</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-aws2-polly</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-aws2-redshift</artifactId>
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
index 8f76e6a6d654..fe1ed8dfef99 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
@@ -116,7 +116,7 @@ public final class MojoHelper {
                         dir.resolve("camel-aws2-iam"),
                         dir.resolve("camel-aws2-kinesis"), dir.resolve("camel-aws2-kms"), dir.resolve("camel-aws2-lambda"),
                         dir.resolve("camel-aws2-mq"),
-                        dir.resolve("camel-aws2-msk"), dir.resolve("camel-aws2-redshift"),
+                        dir.resolve("camel-aws2-msk"), dir.resolve("camel-aws2-polly"), dir.resolve("camel-aws2-redshift"),
                         dir.resolve("camel-aws2-rekognition"),
                         dir.resolve("camel-aws2-s3"), dir.resolve("camel-aws2-ses"),
                         dir.resolve("camel-aws2-sns"),