Use Amazon Bedrock to Generate Content for Amazon Connect Outbound Campaigns
Use AWS Lambda and Amazon Bedrock to dynamically transform Message Template content during Amazon Connect outbound campaign execution - enabling multilingual translation, personalization, and AI-powered content generation at scale.
Overview
This solution integrates Amazon Bedrock with Amazon Connect outbound campaigns through a Journey Flow, AWS Lambda, and the GetMessageTemplate API. A campaign operator writes content in a source Message Template, and at execution time a Lambda function reads that template, processes it through a large language model based on each customer's attributes, and delivers personalized results.
This pattern supports multiple use cases:
- Multilingual campaigns — translate a single template into each customer's preferred language
- Tone adaptation — adjust formality based on customer segment or region
- Content personalization — tailor messaging based on profile attributes or purchase history
- Summarization — condense detailed content into shorter formats for specific channels
- Appointment reminders — generate context-aware messages with customer-specific details
Architecture
The solution follows this flow:
- Campaign operator creates a source Message Template with content in the default language.
- Journey starts and invokes the Lambda via the Custom action block with a batch of customer profiles.
- Lambda reads the source template content via the GetMessageTemplate API (cached for 5 minutes).
- For each customer profile, Lambda extracts attributes (locale, name, segment) and invokes Bedrock to transform the content.
- Lambda writes the transformed subject and body to the Customer Profile.
- The Send communication block delivers the email using a delivery Message Template that resolves the transformed content from the profile.
Prerequisites
- An Amazon Connect instance (see setup details in the Prerequisites section below)
- Amazon Bedrock model access enabled
- Customer profiles with
FirstName,LastName,emailAddress, and aLocalecustom attribute
Time to implement: approximately 30-45 minutes.
Costs: This solution incurs Amazon Bedrock charges for each content transformation. See Amazon Bedrock pricing. Amazon Connect outbound campaign and email delivery charges also apply.
Prerequisites: Configure your Amazon Connect instance
Before building the solution, ensure your Connect instance has the required features enabled.
A. Enable outbound campaigns
- Open the Amazon Connect console → select your instance.
- In the navigation pane, choose Channels and communications → Outbound campaigns.
- If not already enabled, follow the prompts to enable outbound campaigns.
- This enables the Journey builder, Custom actions, and Send communication blocks.
B. Enable the email channel
- In the Connect console, go to your instance → Channels and messaging → Email.
- If email is not enabled, choose Enable email.
- Configure an S3 bucket for email attachments storage (the console guides you through this).
- Verify your email sending domain or email address:
- Go to Email addresses → Add email address
- Enter your outbound email address (e.g.,
campaigns@yourdomain.com) - Complete domain verification (DKIM/SPF) — Connect will provide DNS records to add to your domain
- Wait for verification status to show Verified
- Note your verified outbound email address — you'll use it in the Send communication block.
C. Enable Customer Profiles
- In the Connect console, go to your instance → Customer Profiles.
- If not enabled, choose Enable Customer Profiles.
- Note your Customer Profiles domain name (format:
amazon-connect-<instance-alias>). - Import or create customer profiles with the required fields:
FirstName,LastName,emailAddress, andLocale(in the attributes map).
D. Enable AI Agents (Amazon Q in Connect)
The Lambda uses the GetMessageTemplate API to read source template content. This API is part of the Amazon Q in Connect service (labeled AI Agents in the Connect console). Message Templates are stored in a knowledge base that is automatically created when you enable outbound campaigns on your instance.
Note on naming: The boto3 client uses
qconnectas the service name, but the IAM action uses the legacywisdom:prefix (e.g.,wisdom:GetMessageTemplate). Both refer to the same service — Amazon Q in Connect.
How to verify it's enabled:
If you can already create Message Templates in your Connect admin site (under Message Templates), then AI Agents is already active and a knowledge base exists.
How to find your knowledge base ID:
Run this CLI command:
aws qconnect list-knowledge-bases --region <your-region>
Look for the entry with your instance name (e.g., amazon-connect-<your-instance-alias>) and knowledgeBaseType: MESSAGE_TEMPLATES. Note the knowledgeBaseId value.
How to find a message template ID:
After creating your source template (Step 5), run:
aws qconnect list-message-templates \ --knowledge-base-id <your-knowledge-base-id> \ --region <your-region>
Find your template by name and note the messageTemplateId value.
How to verify the template content is readable:
aws qconnect get-message-template \ --knowledge-base-id <your-knowledge-base-id> \ --message-template-id <your-template-id> \ --region <your-region> \ --query "messageTemplate.content"
This returns the template's subject and body content — which is exactly what the Lambda reads at runtime.
E. Register a Lambda function for outbound campaigns
This step connects your Lambda to the Connect instance so Journey Flows can invoke it.
- In the Connect console, go to your instance → Channels and communications → Outbound campaigns.
- Under Set up custom actions → Lambda Functions, you will add your function here after creating it in Step 4.
F. Understand how email delivery works in Journey Flows
The Journey Flow email delivery process works as follows:
- Journey starts — selects customers from a segment based on configured audience criteria.
- Custom action block — invokes your Lambda function with batches of customer profiles (up to 10 per invocation). The Lambda must respond within 30 seconds.
- Send communication block — delivers the email using:
- A Message Template for content (resolves placeholders from Customer Profile attributes)
- The From address you configured (must be verified)
- The recipient's email from their Customer Profile's
emailAddressfield
- Email delivery — Connect routes the email through Amazon SES for actual delivery.
Key constraints:
- The Lambda response must complete within 30 seconds or the Journey treats it as a failure
- Message Template placeholders that cannot be resolved cause the email to be silently dropped
- Custom attributes in Customer Profiles are limited to 255 characters per value
- The
AdditionalInformationstandard profile field supports up to 1000 characters - All profiles in the segment must have a valid
emailAddressor they will be skipped
G. Understand Journey Flow blocks
The Journey Flow builder provides these blocks for our solution:
| Block | Purpose | Configuration |
|---|---|---|
| Custom action | Invokes the Lambda function | Select your registered Lambda ARN |
| Send communication | Sends the email via template | Configure From address, template, version |
| End flow | Terminates the journey for a recipient | No configuration needed |
The flow connects as: Custom action → Send communication → End flow. Both success and error paths from Send communication lead to End flow.
Step 1: Enable Bedrock model access
- Open the Amazon Bedrock console.
- Go to Model access → Manage model access.
- Request access to Anthropic Claude Sonnet if not already enabled.
- Wait for access to be granted.
Step 2: Create the source Message Template
This template contains your email content in the default language (e.g., English). The Lambda reads this template and translates it.
- Open Amazon Connect console → Message Templates → Create template.
- Configure:
| Setting | Value |
|---|---|
| Name | Source-Campaign-Email |
| Channel | |
| Subject | Your appointment is tomorrow, {{CustomerName}} |
- In the Body, write your email content in your default language:
Dear {{CustomerName}},
This is a friendly reminder that your appointment is scheduled for tomorrow. Please arrive 15 minutes early and bring a valid ID. If you need to reschedule, please contact us at least 24 hours in advance.
Regards,
Customer Support Team
- Save and publish the template.
- Note the template ID and knowledge base ID from the URL (format:
https://<instance>.my.connect.aws/message-templates/<knowledge-base-id>/<template-id>).
Step 3: Create SSM parameters
The Lambda reads configuration from SSM Parameter Store. Create these parameters using the template ID and knowledge base ID from Step 2.
- Open AWS Systems Manager console → Parameter Store → Create parameter
- Create each parameter:
| Name | Type | Value |
|---|---|---|
/connect-campaigns/outbound-email/default-locale | String | en |
/connect-campaigns/outbound-email/max-retry-attempts | String | 3 |
/connect-campaigns/outbound-email/llm-model-id | String | (see note below) |
/connect-campaigns/outbound-email/source-template-id | String | (template ID from Step 2) |
/connect-campaigns/outbound-email/knowledge-base-id | String | (knowledge base ID from Step 2) |
/connect-campaigns/outbound-email/connect-instance-id | String | (your Connect instance UUID) |
Note: For
llm-model-id, use the current inference profile ID available in your region (e.g.,us.anthropic.claude-sonnet-4-20250514-v1:0). Check Amazon Bedrock model IDs for the latest.
Step 4: Create the Lambda function
- Open AWS Lambda console → Create function → Author from scratch
- Configure:
| Setting | Value |
|---|---|
| Function name | connect-outbound-email-generator |
| Runtime | Python 3.12 |
| Architecture | arm64 |
| Timeout | 120 seconds |
| Memory | 512 MB |
- Attach the following inline IAM policy to the Lambda execution role:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "BedrockInvoke", "Effect": "Allow", "Action": "bedrock:InvokeModel", "Resource": [ "arn:aws:bedrock:*::foundation-model/anthropic.*", "arn:aws:bedrock:*:ACCOUNT_ID:inference-profile/us.anthropic.*" ] }, { "Sid": "SSMRead", "Effect": "Allow", "Action": ["ssm:GetParameter", "ssm:GetParametersByPath"], "Resource": "arn:aws:ssm:*:ACCOUNT_ID:parameter/connect-campaigns/outbound-email/*" }, { "Sid": "CustomerProfiles", "Effect": "Allow", "Action": "profile:UpdateProfile", "Resource": "arn:aws:profile:*:ACCOUNT_ID:domains/*" }, { "Sid": "QConnectReadTemplate", "Effect": "Allow", "Action": "wisdom:GetMessageTemplate", "Resource": "arn:aws:wisdom:*:ACCOUNT_ID:message-template/*/*" }, { "Sid": "CloudWatch", "Effect": "Allow", "Action": "cloudwatch:PutMetricData", "Resource": "*" } ] }
Note: The CloudWatch
PutMetricDataaction requiresResource: "*"because CloudWatch does not support resource-level permissions for this action.
⚠️ Important: Replace all instances of
ACCOUNT_IDin the policy above with your actual 12-digit AWS account ID. You can find it by runningaws sts get-caller-identity.
- Set environment variables:
| Key | Value |
|---|---|
SSM_PARAMETER_PATH | /connect-campaigns/outbound-email/ |
CUSTOMER_PROFILES_DOMAIN | amazon-connect-<your-instance-alias> |
AWS_REGION_NAME | Your region (e.g., us-east-1) |
- Paste the following function code:
import json import logging import os import random import re import time from concurrent.futures import ThreadPoolExecutor, as_completed import boto3 from botocore.exceptions import ClientError logger = logging.getLogger() logger.setLevel(logging.INFO) # --- Configuration --- SSM_PATH = os.environ.get("SSM_PARAMETER_PATH", "/connect-campaigns/outbound-email/") CP_DOMAIN = os.environ.get("CUSTOMER_PROFILES_DOMAIN", "") REGION = os.environ.get("AWS_REGION_NAME", "us-east-1") # BCP-47 locale validation BCP47_PATTERN = re.compile(r"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$") # Locale to language name mapping LOCALE_TO_LANGUAGE = { "en": "English", "fr": "French", "es": "Spanish", "de": "German", "it": "Italian", "pt": "Portuguese", "ja": "Japanese", "ko": "Korean", "zh": "Chinese", "ar": "Arabic", "hi": "Hindi", "nl": "Dutch", "ru": "Russian", "sv": "Swedish", "tr": "Turkish", "th": "Thai", } # --- Config loader with caching --- _config_cache = None _config_loaded_at = 0 CONFIG_TTL = 45 # --- Source template cache --- _template_cache = None _template_loaded_at = 0 TEMPLATE_TTL = 300 # Cache template for 5 minutes def load_config(): """Load config from SSM with caching.""" global _config_cache, _config_loaded_at if _config_cache and (time.time() - _config_loaded_at) < CONFIG_TTL: return _config_cache defaults = { "default-locale": "en", "max-retry-attempts": "3", "llm-model-id": "us.anthropic.claude-sonnet-4-20250514-v1:0", "source-template-id": "", "knowledge-base-id": "", "connect-instance-id": "", } try: ssm = boto3.client("ssm", region_name=REGION) response = ssm.get_parameters_by_path(Path=SSM_PATH, Recursive=False) for param in response.get("Parameters", []): name = param["Name"].rsplit("/", 1)[-1] defaults[name] = param["Value"] except Exception as e: logger.error(f"SSM load failed, using defaults: {e}") _config_cache = defaults _config_loaded_at = time.time() return defaults def load_source_template(config): """Read the source Message Template content via GetMessageTemplate API.""" global _template_cache, _template_loaded_at if _template_cache and (time.time() - _template_loaded_at) < TEMPLATE_TTL: return _template_cache template_id = config.get("source-template-id", "") knowledge_base_id = config.get("knowledge-base-id", "") if not template_id or not knowledge_base_id: logger.error("source-template-id or knowledge-base-id not configured") return None try: qconnect = boto3.client("qconnect", region_name=REGION) response = qconnect.get_message_template( knowledgeBaseId=knowledge_base_id, messageTemplateId=template_id, ) template_data = response.get("messageTemplate", {}) content = template_data.get("content", {}) email_content = content.get("email", {}) subject = email_content.get("subject", "") body_html = email_content.get("body", {}).get("html", {}).get("content", "") body_plain = email_content.get("body", {}).get("plainText", {}).get("content", "") _template_cache = { "subject": subject, "body": body_plain or body_html, # Prefer plain text; fall back to HTML } _template_loaded_at = time.time() logger.info(f"Loaded source template: subject='{subject[:50]}...'") return _template_cache except Exception as e: logger.error(f"Failed to load source template: {e}") return None # --- Locale helpers --- def validate_bcp47(locale): if not locale: return False return BCP47_PATTERN.match(locale) is not None def resolve_locale(profile_locale, default_locale): if not profile_locale: return default_locale if not validate_bcp47(profile_locale): return default_locale return profile_locale def get_language(locale): prefix = locale.split("-")[0].lower() return LOCALE_TO_LANGUAGE.get(prefix, locale) # --- Bedrock invocation --- def invoke_bedrock(prompt, model_id, max_retries=3, bedrock_client=None): """Invoke Bedrock with retry and exponential backoff.""" bedrock = bedrock_client or boto3.client("bedrock-runtime", region_name=REGION) for attempt in range(1, max_retries + 1): try: body = json.dumps({ "anthropic_version": "bedrock-2023-05-31", "max_tokens": 2048, "temperature": 0.3, # Lower temperature for translation accuracy "top_p": 0.9, "messages": [{"role": "user", "content": prompt}], }) response = bedrock.invoke_model( modelId=model_id, contentType="application/json", accept="application/json", body=body, ) result = json.loads(response["body"].read()) content = result.get("content", []) text = "".join(b.get("text", "") for b in content if b.get("type") == "text") return text, None except ClientError as e: code = e.response.get("Error", {}).get("Code", "") if code == "ThrottlingException" and attempt < max_retries: delay = min(1 * (2 ** (attempt - 1)), 60) jitter = delay * 0.1 * (2 * random.random() - 1) time.sleep(delay + jitter) continue if attempt == max_retries: return None, f"Bedrock failed after {max_retries} attempts: {e}" time.sleep(1) except Exception as e: if attempt == max_retries: return None, f"Bedrock error: {e}" time.sleep(1) return None, "Bedrock invocation failed" # --- Response parsing --- def parse_response(raw): """Parse JSON response from LLM.""" stripped = raw.strip() match = re.match(r"^```(?:json)?\s*\n?(.*?)\n?\s*```$", stripped, re.DOTALL) if match: stripped = match.group(1).strip() try: parsed = json.loads(stripped) except (json.JSONDecodeError, TypeError) as e: return None, f"JSON parse error: {e}" if "subject" not in parsed: return None, "Missing field: subject" if "body" not in parsed: return None, "Missing field: body" return {"subject": parsed["subject"], "body": parsed["body"]}, None # --- Main handler --- def lambda_handler(event, context): """Handle Journey Flow batch invocations.""" config = load_config() campaign_context = event.get("InvocationMetadata", {}).get("CampaignContext", {}) # Used for campaign name in prompt profiles = event["Items"]["CustomerProfiles"] model_id = config["llm-model-id"] max_retries = int(config["max-retry-attempts"]) default_locale = config["default-locale"] results = [] # Load the source template content source_template = load_source_template(config) if not source_template: logger.error("Cannot proceed without source template") # Return error for all profiles for profile in profiles: results.append({ "Id": profile.get("ProfileId", "unknown"), "ResultData": {"errorCode": "TEMPLATE_NOT_FOUND"} }) return {"Items": {"CustomerProfiles": results}} source_subject = source_template["subject"] source_body = source_template["body"] # Create boto3 clients once (reused across all profiles in the batch) cp_client = boto3.client("customer-profiles", region_name=REGION) bedrock_client = boto3.client("bedrock-runtime", region_name=REGION) def process_profile(profile): profile_id = profile.get("ProfileId", "unknown") try: customer_data = json.loads(profile.get("CustomerData", "{}")) except (json.JSONDecodeError, TypeError): customer_data = {} # Extract customer info first_name = customer_data.get("firstName", customer_data.get("FirstName", "")) last_name = customer_data.get("lastName", customer_data.get("LastName", "")) customer_name = f"{first_name} {last_name}".strip() or "Customer" # Resolve locale profile_locale = ( customer_data.get("attributes", {}).get("Locale") or customer_data.get("attributes", {}).get("locale") or customer_data.get("Locale") or customer_data.get("locale") or "" ) locale = resolve_locale(profile_locale or None, default_locale) language = get_language(locale) # If customer's locale matches the source template language, skip translation source_language = get_language(default_locale) if language == source_language: # No translation needed — use source content directly subject = source_subject.replace("{{CustomerName}}", customer_name)[:255] body = source_body.replace("{{CustomerName}}", customer_name)[:1000] else: # Build translation prompt prompt = ( f"Translate the following email into {language}. " f"Maintain the same tone, meaning, and formatting. " f"Replace any placeholder like '{{{{CustomerName}}}}' with '{customer_name}'. " f"Keep the email concise — body must not exceed 900 characters.\n\n" f"SOURCE EMAIL:\n" f"Subject: {source_subject}\n" f"Body: {source_body}\n\n" f"Respond in JSON format ONLY:\n" f'{{\n "subject": "<translated subject>",\n "body": "<translated body>"\n}}' ) # Invoke Bedrock for translation raw_response, error = invoke_bedrock(prompt, model_id, max_retries, bedrock_client) if error: logger.error(f"Translation failed for {profile_id}: {error}") return {"Id": profile_id, "ResultData": {"errorCode": "TRANSLATION_FAILED", "errorMessage": error}} # Parse response parsed, parse_error = parse_response(raw_response) if parse_error: logger.error(f"Parse failed for {profile_id}: {parse_error}") return {"Id": profile_id, "ResultData": {"errorCode": "PARSE_FAILED", "errorMessage": parse_error}} subject = parsed["subject"][:255] body = parsed["body"][:1000] # Write translated content to Customer Profile try: cp_client.update_profile( DomainName=CP_DOMAIN, ProfileId=profile_id, AdditionalInformation=body, Attributes={"emailSubject": subject}, ) logger.info(f"Updated profile {profile_id} with {language} content") except Exception as e: logger.error(f"Profile update failed for {profile_id}: {e}") return {"Id": profile_id, "ResultData": {"subject": subject, "body": body, "locale": locale}} # Process profiles concurrently (must complete within 30s) with ThreadPoolExecutor(max_workers=min(len(profiles), 10)) as executor: futures = {executor.submit(process_profile, p): p for p in profiles} for future in as_completed(futures): results.append(future.result()) return {"Items": {"CustomerProfiles": results}}
- Click Deploy.
Step 5: Register the Lambda with your Connect instance
- Open Amazon Connect console → select your instance.
- Navigate to Channels and communications → Outbound campaigns.
- Under Set up custom actions → Lambda Functions, select
connect-outbound-email-generator. - Choose Add Lambda Function.
Step 6: Create the delivery Message Template
This template is used by the Send communication block. It resolves the translated content from the Customer Profile.
- Open Amazon Connect console → Message Templates → Create template.
- Configure:
| Setting | Value |
|---|---|
| Name | Delivery-Localized-Email |
| Channel | |
| Subject | {{Attributes.Customer.Attributes.emailSubject}} |
- Body (HTML):
<html> <body> {{Attributes.Customer.AdditionalInformation}} </body> </html>
- Save and publish.
Tip: You can add CSS styling, branding elements, headers, and footers to the delivery template HTML. The
{{Attributes.Customer.AdditionalInformation}}placeholder will be replaced with the translated body content within your branded layout.
Step 7: Create the Journey Flow
- Open Amazon Connect console → Flows → Create flow → select Journey flow.
- Name:
AI-Translated-Outbound-Email - Add blocks:
[Custom action] → [Send communication] → [End flow]
↓ (error)
[End flow]
- Configure Custom action block:
| Property | Value |
|---|---|
| Action | Invoke Lambda action |
| Function ARN | Select connect-outbound-email-generator |
- Configure Send communication block:
| Property | Value |
|---|---|
| Channel | |
| From | Your verified outbound email address |
| Display name | Your brand name |
| Message template | Delivery-Localized-Email |
| Template alias or version | Select your published version |
- Connect both Success and Error from Send communication to End flow.
- Save and publish.
Step 8: Set up Customer Profiles
Ensure your customer profiles have:
| Field | Location | Required | Example |
|---|---|---|---|
FirstName | Standard field | Yes | Marie |
LastName | Standard field | No | Dupont |
emailAddress | Standard field | Yes | marie@example.com |
Locale | Custom attributes | No | fr (defaults to en) |
Step 9: Create a segment and run the Journey
- Create a Customer Segment targeting your audience.
- Go to Outbound Campaigns → Create Journey.
- Select your segment and the
AI-Translated-Outbound-Emailflow. - Configure communication time and guardrails.
- Schedule and publish.
Step 10: Verify
- Check CloudWatch Logs for the Lambda:
- Look for "Updated profile" messages (success)
- Look for "Loaded source template" (template read successful)
- Confirm emails arrive in the customer's language.
- Test by changing a profile's
Localeattribute and re-running.
How it works
- Operator writes content once — in the source template (English or any default language)
- Journey invokes Lambda — sends a batch of customer profiles
- Lambda reads the source template — via
GetMessageTemplateAPI (cached for 5 minutes) - For each customer:
- If customer's locale matches the source language → use content as-is (skip Bedrock call)
- If different locale → send content to Bedrock for translation
- Lambda writes translated content — subject to
Attributes.emailSubject, body toAdditionalInformation - Journey sends email — delivery template resolves the translated content from the profile
Benefits of this approach:
- Campaign operators write content once in one language
- No need to maintain separate templates per locale
- Content changes only require updating the source template — translations happen automatically
- Customers always receive content in their preferred language
Important notes
- 30-second Journey timeout: The Lambda processes profiles concurrently to respond within 30 seconds.
- Template caching: Source template is cached for 5 minutes. Update SSM's
source-template-idto point to a different template for immediate change. - Skip optimization: Profiles matching the source locale don't invoke Bedrock — reducing cost and latency.
- Silent delivery failures: If the delivery template can't resolve a placeholder, Connect drops the email silently.
- Character limits: Body is capped at 1000 characters. The prompt instructs Bedrock to stay under 900 as a safety margin.
- AdditionalInformation field usage: This solution uses the Customer Profile's
AdditionalInformationfield as temporary storage for the generated email body. If your profiles use this field for other purposes, consider clearing it after campaign completion or using a dedicated custom attribute (255-char limit) instead.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Lambda logs show "Cannot proceed without source template" | source-template-id or knowledge-base-id SSM parameter is missing or empty | Verify both parameters exist and have correct values (see Step 3) |
| Lambda times out | Timeout set too low (default is 3s) | Set Lambda timeout to 120 seconds in Configuration → General configuration |
| Lambda logs show "get_message_template FAILED: AccessDeniedException" | Lambda role missing wisdom:GetMessageTemplate permission | Add the permission to the Lambda's IAM role (see Step 4) |
| Lambda logs show "NameError: name 'qconnect' is not defined" | Missing boto3.client("qconnect") initialization in the code | Ensure qconnect = boto3.client("qconnect", region_name=REGION) exists in load_source_template() |
| Campaign shows send attempts but no emails received | Message Template placeholder cannot be resolved — Connect drops email silently | Verify delivery template uses {{Attributes.Customer.Attributes.emailSubject}} and {{Attributes.Customer.AdditionalInformation}} exactly |
| Email body is truncated | Content exceeds AdditionalInformation 1000-character limit | Shorten source template content or adjust the Bedrock prompt to produce shorter output |
| Lambda logs show "Profile update failed" with ResourceNotFoundException | Wrong CUSTOMER_PROFILES_DOMAIN environment variable | Set it to amazon-connect-<your-instance-alias> (check aws customer-profiles list-domains) |
| Emails arrive but not translated (same language as source) | Customer profile's Locale attribute matches default-locale — Lambda skips translation | Verify the profile's Locale value differs from the SSM default-locale parameter |
| Duplicate emails received | Journey retried or ran multiple times | Set communication limits in Journey guardrails (e.g., max 1 per recipient per day) |
Cleaning up
- Delete the Lambda function.
- Remove it from your Connect instance (Outbound campaigns → Lambda Functions).
- Delete SSM parameters.
- Delete both Message Templates (source and delivery) from Connect.
- Delete the Journey Flow and Journey.
Related information
Relevant content
- Accepted Answer
asked 7 months ago
AWS OFFICIALUpdated 4 years ago