Tag Archives: messaging

Implement Tenants in your Amazon SES environment, Part 3: Implementation guide

Post Syndicated from Rommel Sunga original https://aws.amazon.com/blogs/messaging-and-targeting/implement-tenants-in-your-amazon-ses-environment-part-3-implementation-guide/

This is part 3 in a series covering the new tenants feature in Amazon Simple Email Service (SES). The first post in this series discussed how users can improve email deliverability with tenant management in Amazon SES. Part 2 covered key aspects involved in planning the migration of existing Amazon SES infrastructure to use tenant-based reputation isolation.

With Amazon SES tenants, users can:

  • Manage individual tenant onboardings and their reputations in isolation
  • Provision isolated tenants within a single SES account
  • Apply automated reputation policies to manage email sending
  • Detect and isolate deliverability issues within isolated email streams
  • Preserve sender reputation and improve inbox placement with mailbox providers

This post provides a step-by-step migration guide to Tenants for key AWS components like AWS Identity and Access Management (IAM) permissions, Amazon CloudWatch logging and Amazon EventBridge monitoring. Additionally, we provide several code examples that show how to programmatically provision tenants in real time as customers are onboarded. The goal is to demonstrate how to use the Tenants feature to achieve reputation isolation between customers or business units (BUs), get more control over sending policies, and enable the automatic pause mechanism to limit the damage from problematic senders.

Step-by-step migration guide

Having completed the inventory and configuration planning prescribed in part 2 of this series, we are ready to start the 4-step migration (or implementation) of the tenants feature in the AWS SES account.

The Amazon SES Tenants Migration process is as follows:

  1. Preparation
    1. Verify SES V2 API usage
    2. Update SDK versions
  2. Create Your First Tenant
    1. Create Tenant API calls
    2. Implement in onboarding workflow
    3. Verify tenant creation
  3. Associating Resources
    1. Link verified domains to tenants
    2. Associate configuration sets
    3. Connect IP pools
  4. Updating Your Sending Code
    1. Add Tenant/Name parameter to API calls
    2. Add X-SES-TENANT header for SMTP
    3. Update application sending code
    4. Test email sending functionality

Preparation

When sending email through a tenant, be sure to specify the tenant in the API calls or SMTP headers and ensure that all resources used are associated with that tenant. Before getting started, keep in mind that there’s an additional charge per tenant per month based on the number of emails. For more detailed information, see the SES Pricing page.

For applications that use SMTP, see the SMTP Implementation section later in this document.

For applications that use the SES API, confirm that the latest Amazon SES V2 API is being used, as tenant management capabilities are only available in this version (see SES V2 API migration guide). We also recommend verifying that the AWS SDK version being used supports these operations, otherwise you may need to update to a version that supports them.

The SES V2 API includes the seven essential operations for managing the tenant architecture that the application will need to leverage throughout the migration (or implementation) and tenant lifecycle:

  1. CreateTenant for establishing new tenant containers
  2. CreateTenantResourceAssociation for linking resources like domains and configuration sets to tenants
  3. DeleteTenant for removing tenants when workloads offboard
  4. DeleteTenantResourceAssociation to unlink resources from tenants
  5. GetTenant retrieves specific tenant details
  6. ListTenants provides an overview of all tenants in an account
  7. ListTenantResources shows which resources are associated with each tenant

Implementation Steps

Creating the tenant(s)

The following Python code example uses the AWS SDK for Python (Boto3) and CreateTenant to demonstrate tenant creation. We’ve added optional tags to better organize the tenant resource for billing or logging purposes.

import boto3
from botocore.exceptions import ClientError

def setup_ses_tenant():
    ses_client = boto3.client('sesv2')
    
    # Create a new tenant with descriptive tags
    tenant_response = ses_client.create_tenant(
        TenantName='MyTenant',
        Tags=[
            {
                'Key': 'Environment',
                'Value': 'Production'
            },
            {
                'Key': 'CustomerID',
                'Value': '[customer_id]'
            }
        ]
    )
    
    # Verify tenant creation
    tenants = ses_client.list_tenants()
    print(f"Total tenants in account: {len(tenants['Tenants'])}")
    
    return tenant_response['TenantName']


if __name__ == "__main__":
    try:
        tenant_name = setup_ses_tenant()
        print(f"Successfully created tenant: {tenant_name}")
    except ClientError as e:
        print(f"AWS error: {e}")
    except Exception as e:
        print(f"Unexpected error: {e}")

This example code can be used when a customer first onboards onto the platform to send email. By creating a tenant for this customer, resources under that tenant will be associated together whenever the tenant is used as explained in the next steps.

Associating resources with the tenant

Each tenant needs appropriate resources—configuration sets, sending identities, and potentially dedicated IP pools—to begin sending email. The association process should align with the resource sharing strategy as established during the migration planning phase.

The following Python code example uses the AWS SDK for Python (Boto3) and CreateTenantResourceAssociation to associate resources to the tenant that was created in the previous step.

import boto3
from botocore.exceptions import ClientError

def associate_resources_with_tenant():
    ses_client = boto3.client('sesv2')
    
    try:
        # Associate verified domain identity
        ses_client.create_tenant_resource_association(
            TenantName='MyTenant',
            ResourceArn='arn:aws:ses:[aws_region]:[account_id]:identity/[domain_name]'
        )
        print("Successfully associated email identity with tenant")

        # Associate configuration set for tracking
        ses_client.create_tenant_resource_association(
            TenantName='MyTenant',
            ResourceArn='arn:aws:ses:[aws_region]:[account_id]:configuration-set/MyTenantConfigurationSet'
        )
        print("Successfully associated configuration set with tenant")

    except ClientError as e:
        print(f"Error: {e.response['Error']['Message']}")
        raise

if __name__ == "__main__":
    associate_resources_with_tenant()

Consider implementing batch association for email streams with multiple domains or configuration sets. This approach reduces API calls and improves provisioning efficiency. Remember that resources can be shared across multiple tenants if the architecture requires it, allowing flexible resource allocation strategies.

Update the applications

The transition to tenant-based sending requires minimal code changes in the apps, namely adding the TenantName and ConfigurationSetName to the sending process.

API Implementations

For applications that use the SES V2 API, add the tenant and configuration set parameters to the send calls as demonstrated below using the AWS SDK for Python (Boto3) :

import boto3

def send_email_from_tenant():
    ses_client = boto3.client('sesv2')
    
    response = ses_client.send_email(
        FromEmailAddress='sender@[domain_name]',
        Destination={
            'ToAddresses': ['[recipient_email]']
        },
        Content={
            'Simple': {
                'Subject': {
                    'Data': 'Test email from SES tenant'
                },
                'Body': {
                    'Text': {
                        'Data': 'This is a test email sent from an SES tenant'
                    }
                }
            }
        },
        ConfigurationSetName='MyTenantConfigurationSet',
        TenantName='MyTenant'  # Critical addition for tenant routing
    )
    
    print(f"Message sent! Message ID: {response['MessageId']}")
    return response

if __name__ == "__main__":
    send_email_from_tenant()

SMTP Implementations

For sending applications that use SMTP, add the X-SES-TENANT and the ConfigurationSetName header parameters to every message. In the code block that follows, we demonstrate the proper header configuration for SMTP sending using Python:

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib

def send_smtp_email_with_tenant():
    sender = 'smtp-sender@[domain_name]'
    sender_name = 'Sender Name'
    recipient = '[recipient_email]'
    username_smtp = '[smtp_username]'
    configuration_set = 'MyTenantConfigurationSet'
    host = 'email-smtp.[aws_region].amazonaws.com'
    port = 587
    
    subject = 'Amazon SES test (SMTP interface accessed using Python)'
    body_text = """Email Test
    This email was sent through the Amazon SES SMTP interface using Python."""
    body_html = """<h1>Email Test</h1>
        <p>This email was sent through the 
        <a href="https://aws.amazon.com/ses">Amazon SES</a> SMTP
        interface using Python."</p>"""
    
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = f"{sender_name} <{sender}>"
    msg['To'] = recipient
    msg['X-SES-CONFIGURATION-SET'] = configuration_set
    
    # Critical: Specify tenant for SMTP sending
    msg['X-SES-TENANT'] = 'MyTenant'
    
    part1 = MIMEText(body_text, 'plain')
    part2 = MIMEText(body_html, 'html')
    msg.attach(part1)
    msg.attach(part2)
    
    try:
        server = smtplib.SMTP(host, port)
        server.ehlo()
        server.starttls()
        server.ehlo()
        server.login(username_smtp, fetch_smtp_password_from_secure_storage())
        server.sendmail(sender, recipient, msg.as_string())
        print("Email sent successfully!")
        
    except Exception as e:
        print(f"Error: {str(e)}")
    
    finally:
        server.quit()

def fetch_smtp_password_from_secure_storage():
    # Implement secure password retrieval from AWS Secrets Manager
    # or your preferred secret storage solution
    return '[smtp_password]'


if __name__ == "__main__":
    send_smtp_email_with_tenant()

Configuring IAM policies and permissions for tenants

This section explains how to configure IAM permissions for SES tenants, including how to set up different permission levels for tenant management, email sending, and monitoring while following security best practices to control access based on organizational roles. Remember that IAM policies for tenants follow the principle of least privilege. Start with minimal permissions and expand as needed, regularly reviewing and removing unused permissions to maintain security.

Tenant management permissions

SES Tenants can be controlled through specific IAM permissions that determine who can create, modify, and use specific tenant(s) in the organization. The tenant management system’s core API actions discussed previously can be granted with granular access through IAM policies for administrative operations. The Service Authorization Reference for Amazon Simple Email Service v2 page contains the latest documentation for the service-specific actions used below for Amazon Simple Email Service.

We recommend limiting each IAM role’s permission based on the minimum capabilities required by that role. This helps mitigate the potential for negative effects if an SMTP credential is misused. What follows is a basic IAM policy that demonstrates full tenant management capabilities; this is NOT demonstrating the principle of least privilege (yet):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:CreateTenant",
                "ses:DeleteTenant",
                "ses:GetTenant",
                "ses:ListTenants",
                "ses:CreateTenantResourceAssociation",
                "ses:DeleteTenantResourceAssociation",
                "ses:ListTenantResources",
                "ses:ListResourceTenants"
            ],
            "Resource": "*"
        }
    ]
}

Configuring sending permissions with tenants

Applications that send emails through tenants need different permissions than those managing tenants. The key distinction is using the ses:TenantName condition to restrict which tenants an application can use for sending.

The IAM policy below allows sending emails only through the specified CustomerA-Tenant tenant, ensuring applications can’t accidentally or maliciously send through other customers’ tenants.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendBulkEmail"
            ],
            "Resource": [
                "arn:aws:ses:[aws_region]:[account_id]:identity/*",
                "arn:aws:ses:[aws_region]:[account_id]:configuration-set/*"
            ],
            "Condition": {
                "StringEquals": {
                    "ses:TenantName": "CustomerA-Tenant"
                }
            }
        }
    ]
}

Separating administrative and operational access

Production environments implement role separation between tenant management and email sending operations. Administrative roles handle tenant creation and resource association during customer onboarding, while application roles can only send emails through assigned tenants. The IAM policy below is an example of an administrative role; it allows creating and configuring tenants for use during customer onboarding but does not allow the tenant deletion action to prevent accidental deletions.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:CreateTenant",
                "ses:ListTenants"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ses:CreateTenantResourceAssociation",
                "ses:GetTenant"
            ],
            "Resource": "arn:aws:ses:[aws_region]:[account_id]:tenant/*/tn-*"
        },
        {
            "Effect": "Deny",
            "Action": "ses:DeleteTenant",
            "Resource": "*"
        }
    ]
}

Resource-level permissions

Tenants support resource-level permissions using Amazon Resource Names (ARNs), enabling fine-grained access control. Grant access to specific tenants by specifying the tenant name and tenant id (ex. CustomerA-Tenant/tn-1a2b3c4d5e6f7890abcdef1234567890) rather than granting blanket permissions using the “*/tn-*” wildcard as above. To obtain the tenant id you can use the list-tenants command of the AWS SESv2 CLI.

The IAM policy below grants access only to tenants CustomerA-Tenant and CustomerB-Tenant where the following tenant id is a placeholder that should be replaced by the correct tenant id that you obtained from list-tenants.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ses:GetTenant",
            "Resource": [
                "arn:aws:ses:[aws_region]:[account_id]:tenant/CustomerA-Tenant/tn-1a2b3c4d5e6f7890abcdef1234567890",
                "arn:aws:ses:[aws_region]:[account_id]:tenant/CustomerB-Tenant/tn-9876543210fedcba0987654321abcdef"
            ]
        }
    ]
}

Monitoring and compliance access

Security and compliance teams often need read-only access to monitor tenant usage. The following IAM policy grants read-only access to all tenants, but does not permit modifications or deletions of any tenants:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:GetTenant",
                "ses:ListTenants",
                "ses:ListTenantResources"
            ],
            "Resource": "*"
        }
    ]
}

Monitoring Tenants with EventBridge and CloudWatch

Amazon SES integrates with Amazon EventBridge to deliver comprehensive monitoring capabilities for tenant management, providing real-time visibility into reputation changes and enabling automated response workflows. EventBridge is a serverless service that uses JSON-formatted events to connect application components, making it straightforward to build scalable event-driven applications. Amazon SES’s tenant feature’s integration with EventBridge enables organizations to track tenant-specific metrics and other metrics, such as reputation findings and reputation status changes, and tenant status changes.

Understanding EventBridge Integration with SES

EventBridge operates as a router that receives events from SES and delivers them to one or many destinations (aka targets). When SES features experience state changes or status updates, they automatically send events to the EventBridge default event bus. Rules associated with the event bus evaluate events as they arrive, checking whether each event matches the rule’s pattern before routing to specified targets. For SES tenant management, organizations can receive real-time alerts through Amazon EventBridge when tenant reputation findings are detected or when tenant status changes occur. These events are delivered on a best-effort basis; they might be delivered out of order, requiring users to deploy processing logic to handle such scenarios gracefully.

The code block that follows can guide users through the basic EventBridge integration with the SES tenant feature. For more extensive documentation on integrating with EventBridge please consult AWS documentation.

Setting up EventBridge integration

Create an EventBridge rule using the AWS SDK for Python (Boto3) to capture tenant status changes and reputation findings:

# Create rule for monitoring tenant status changes
aws events put-rule \
    --name "SESTenantStatusMonitor" \
    --description "Monitor SES tenant status changes" \
    --event-pattern '{
        "source": ["aws.ses"],
        "detail-type": [
            "Sending Status Enabled",
            "Sending Status Disabled",
            "Advisor Recommendation Status Open",
            "Advisor Recommendation Status Closed"
        ]
    }'

Routing events from EventBridge to CloudWatch Logs

CloudWatch provides the capability to collect raw data and process it into readable, near real-time metrics. Follow these steps to set up a CloudWatch log group for SES tenant events and configure the appropriate IAM permissions:

  1. Create a CloudWatch log group for tenant events:

aws logs create-log-group --log-group-name "/aws/ses/tenants"

  1. Add resource-based policy to CloudWatch Logs:
aws logs put-resource-policy \
    --policy-name EventBridgeToCloudWatchLogsPolicy \
    --policy-document '{
        "Version": "2012-10-17",
        "Statement": [{
            "Sid": "TrustEventsToStoreLogEvent",
            "Effect": "Allow",
            "Principal": {
                "Service": ["events.amazonaws.com", "delivery.logs.amazonaws.com"]
            },
            "Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
            "Resource": "arn:aws:logs:[aws_region]: [account_id]:log-group:/aws/ses/tenants:*"
        }]
    }'
  1. Add the EventBridge target:

aws events put-targets \
    --rule "SESTenantStatusMonitor" \
    --targets '[{
        "Id": "SendToCloudWatchLogs",
        "Arn": "arn:aws:logs:[aws_region]:[account_id]:log-group:/aws/ses/tenants"
    }]'

An example event of a paused (“disabled”) tenant is shown below for reference:

{
    "version": "0",
    "id": "3cc76530-9842-03a9-fdef-e4e4f667cf4e",
    "detail-type": "Sending Status Disabled",
    "source": "aws.ses",
    "account": "[account_id]",
    "time": "2025-10-01T03:37:17Z",
    "region": "[aws_region]",
    "resources": [
        "arn:aws:ses:[aws_region]::tenant/CustomerA-Tenant/tn-2a8c678ec0000fdaf76cc1f127b40"
    ],
    "detail": {
        "version": "1.0.0",
        "data": {
            "origin": "CUSTOMER_MANAGED",
            "record": {
                "status": "DISABLED",
                "cause": "Status manually updated.",
                "lastUpdatedTimestamp": [
                    2025,
                    10,
                    1,
                    3,
                    37,
                    17,
                    671000000
                ]
            }
        }
    }
}

Managing tenant reputation with key Tenants features

Reputation management for individual tenants is one of the core benefits of using Amazon SES’s tenant feature, providing automated protection against deliverability issues that could damage overall account reputation. This section demonstrates how to configure reputation policies that can automatically pause tenants when they experience high bounce rates or reputation issues, as well as how to manually control tenant sending status for custom workflows.

Setting reputation policies

Amazon SES provides three reputation policy enforcement levels that determine how the system responds to reputation findings.

  • The Standard policy (recommended) pauses sending only for high-impact findings, providing a balance between protection and operational flexibility.
  • The Strict policy pauses sending for any reputation finding, offering maximum protection for sensitive environments.
  • The None option disables automated pausing while continuing to track findings, useful for manual monitoring scenarios.

Reputation findings are generated in two severity levels—low and high—based on metrics like bounce rates and complaint rates. When these metrics indicate a potential deliverability issue, SES creates findings that can trigger automatic pausing based on a chosen policy.

In the following code block, we demonstrate how to set a reputation policy on the CustomerA-Tenant

import boto3
from botocore.exceptions import ClientError

def update_tenant_reputation_policy(tenant_arn, policy_arn):
    ses_client = boto3.client('sesv2')
    
    ses_client.update_reputation_entity_policy(
        ReputationEntityType='RESOURCE',
        ReputationEntityReference=tenant_arn,
        ReputationEntityPolicy=policy_arn
    )
    print(f"Tenant policy_arn updated to: {policy_arn}")

# Example usage
if __name__ == "__main__":
    tenant_arn = "arn:aws:ses:[aws_region]:[account_id]:tenant/CustomerA-Tenant/tn-2a8c678ec0000fdaf76cc1f127b40"
    
    # Enable normal sending
    update_tenant_reputation_policy(tenant_arn, 'arn:aws:ses:[aws_region]:aws:reputation-policy/standard')
    
    # Disable/pause sending
    update_tenant_reputation_policy(tenant_arn, 'arn:aws:ses:[aws_region]:aws:reputation-policy/strict')
    
    # Reinstate with monitoring
    update_tenant_reputation_policy(tenant_arn, 'arn:aws:ses:[aws_region]:aws:reputation-policy/none')

Our recommendation is to choose the Standard policy for most production tenants, as this policy provides automatic protection against severe reputation issues while avoiding unnecessary disruptions. Reserve the Strict policy for new or untrusted tenants where maximum caution is warranted. Use the None option during initial monitoring periods or when implementing custom reputation management logic.

Handling paused tenants

When a tenant is paused, either automatically through reputation policies or manually, the sending status prevents any emails from being sent through that tenant. The system derives this aggregate status from both customer-managed and AWS-managed statuses; if either is set to DISABLED, the tenant cannot send emails.

Amazon SES publishes notifications to EventBridge when tenant status changes occur or new reputation findings are detected, enabling real-time response to reputation events. After investigating and resolving the underlying issues, the tenant’s sending capabilities can be reinstated. During reinstatement (REINSTATED status), the tenant can continue sending while metrics are monitored to verify improvement.

def update_tenant_status(tenant_arn, status):
    ses_client = boto3.client('sesv2')
    
    ses_client.update_reputation_entity_customer_managed_status(
        ReputationEntityType='RESOURCE',
        ReputationEntityReference=tenant_arn,
        SendingStatus=status
    )
    print(f"Tenant status updated to: {status}")

# Example usage
if __name__ == "__main__":
    tenant_arn = "arn:aws:ses:[aws_region]:[account_id]:tenant/CustomerA-Tenant/tn-2a8c678ec0000fdaf76cc1f127b40"
    
    # Enable normal sending
    update_tenant_status(tenant_arn, 'ENABLED')
    
    # Disable/pause sending
    update_tenant_status(tenant_arn, 'DISABLED')
    
    # Reinstate with monitoring
    update_tenant_status(tenant_arn, 'REINSTATED')

The REINSTATED status allows the tenant to continue sending even with active reputation findings. Once metrics return to healthy levels, the tenant automatically transitions back to ENABLED status. This approach ensures minimal disruption while protecting the overall account reputation from problematic email streams.

Managing tenant lifecycle

When customers modify a service tier or leave the platform, proper cleanup ensures resource efficiency and maintains account organization.

Removing resource associations

Before deleting a tenant, remove all resource associations to prevent orphaned configurations:

import boto3
from botocore.exceptions import ClientError

def remove_resource_from_tenant():
    ses_client = boto3.client('sesv2')
    
    try:
        # Remove identity association
        ses_client.delete_tenant_resource_association(
            TenantName='MyTenant',
            ResourceArn='arn:aws:ses:[aws_region]:[account_id]:identity/[domain_name]'
        )
        print("Successfully removed identity association")
        
        # Remove configuration set association
        ses_client.delete_tenant_resource_association(
            TenantName='MyTenant',
            ResourceArn='arn:aws:ses:[aws_region]:[account_id]:configuration-set/MyTenantConfigurationSet'
        )
        print("Successfully removed configuration set association")
    
    except ClientError as e:
        print(f"Error: {e.response['Error']['Message']}")
        raise


if __name__ == "__main__":
    remove_resource_from_tenant()

Deleting tenants

Once all resources are disassociated, remove the tenant entirely:

import boto3
from botocore.exceptions import ClientError

def delete_tenant(tenant_name):
    ses_client = boto3.client('sesv2')
    
    try:
        # Delete the tenant
        ses_client.delete_tenant(TenantName=tenant_name)
        print(f"Successfully deleted tenant: {tenant_name}")
        return True
        
    except ClientError as e:
        print(f"Error deleting tenant: {e.response['Error']['Message']}")
        raise

# Example usage with error handling
if __name__ == "__main__":
    try:
        delete_tenant("MyTenant")
    except ClientError as e:
        print(f"Cleanup failed: {e}")

Tenant lifecycle management ensures clean transitions when customers change service tiers or leave the platform. Implement these operations in customer offboarding workflows to maintain optimal account organization and resource utilization.

Resource Management

Resource Sharing Capabilities

Resources can be assigned to multiple tenants simultaneously. This enables sharing common resources between tenants while maintaining separate reputation tracking. For example, the reputation for marketing and transactional email could be tracked separately across independent tenants while using the same sending domain. SES validates tenant-resource associations at send time, rejecting requests if the specified tenant lacks access to the requested resources.

Resource Migration Between Tenants

Resource migration involves two API calls. First, remove the association from the current tenant using DeleteTenantResourceAssociation, then create a new association with the target tenant using CreateTenantResourceAssociation. This process can be automated for bulk migrations during reorganizations.

Reputation Management

Tenant Isolation Protection

Each tenant maintains independent reputation metrics and sending status. When one tenant experiences deliverability issues, it can be automatically paused without affecting other tenants’ ability to send, protecting both shared resources and account-level reputation.

Tenant Pausing Triggers

Tenants can either be paused manually using the UpdateReputationEntityCustomerManagedStatus API or paused automatically based on the reputation policy assigned to the tenant. Reputation policies pause tenants based on reputation findings generated from bounce rates, complaint rates, and third-party feedback reports. The Standard policy (recommended) pauses only for high-severity findings (bounce rate > 15%, complaint rate > 1%), while Strict pauses even for low severity findings (bounce rate > 10%, complaint rate > 0.5%).

Tenant Reactivation Process

For tenants paused by automated reputation policies, use the UpdateReputationEntityCustomerManagedStatus API to reinstate sending after addressing root causes. Tenants paused by AWS Trust & Safety require case resolution through AWS Support.

Migrating Existing Customers

Creating tenants for existing email streams can be completed with no disruption to email sending. Start by creating tenants for each customer or business unit, then associate existing resources like email identities, configuration sets, and templates using the tenant association APIs. Once those steps are complete, update the application, or inform the customer or BU they now need to specify the tenant name and configuration set in their SES SendEmail API calls or SMTP headers which enables SES to route emails through the appropriate tenant.

Reputation Metrics Transition

New reputation metrics will be tracked separately for each tenant from the point of creation and use. Historical metrics from before tenant implementation are not available. Tenant metrics contribute to the overall account-level reputation. For example, if tenant-a, tenant-b, and tenant-c each send 1,000 emails and:

  • Tenant-a receives 150 bounce notifications over 1,000 emails (for a bounce rate of 15%), tenant reputation protection will pause this tenant before the issue escalates.
  • Tenant-b receives 0 bounces over 1,000 emails, for a bounce rate of 0%
  • Tenant-c receives 0 bounces over 1,000 emails, for a bounce rate of 0%

The SES Account Level Bounce Rate (all tenants) is 150 out of 3,000, or 5%

Account Activation Requirements

No account-level activation is required to configure and use the Tenant feature, it is immediately available through the SES V2 API or the AWS SES Console. Users can also start using the tenant management APIs (CreateTenant, CreateTenantResourceAssociation, DeleteTenant, etc.) without any account modifications or support requests.

Conclusion

This post covered detailed migration steps, monitoring setup, practical implementation examples and troubleshooting steps. From running a SaaS platform, to managing multiple brands, to operating separate business units, tenant-based reputation isolation ensures Amazon SES email infrastructure scales reliably as an organization grows.

Additional resources


About the authors

Implement Tenants in your Amazon SES environment, Part 2: Assessment and planning

Post Syndicated from Rommel Sunga original https://aws.amazon.com/blogs/messaging-and-targeting/implement-tenants-in-your-amazon-ses-environment-part-2-assessment-and-planning/

Running multiple users or business units (BUs) on a shared email infrastructure often creates deliverability and compliance risks. The tenant-based reputation isolation feature in Amazon Simple Email Service (Amazon SES) solves these challenges by separating email reputation by customer, BU, or workload. This is part 2 in a series covering the new tenants feature in Amazon Simple Email Service (SES). The first post in this series discussed how users can improve email deliverability with tenant management in Amazon SES (for more details, see the blog post).

In this post, we provide an overview of the tenants feature and guidance for planning the implementation to or migration of your existing Amazon SES infrastructure to use tenant-based reputation isolation.

Part 3 covers practical implementation steps for the tenants feature, including configuration steps for key components like Identity and Access Management (IAM) permissions, Amazon CloudWatch logging, and Amazon EventBridge monitoring. We also provide code examples using the Amazon SES v2 APIs that show how to provision tenants in real time as you onboard downstream customers or business divisions onto your Amazon SES account. Key outcomes include complete reputation isolation between customers, control over sending policies, and automated pause mechanisms for problematic senders.

Solution overview

Amazon SES now offers tenant management capabilities that enable isolated email sending environments within a single AWS account. This provides granular reputation management across different email streams. You can assign dedicated configuration sets, sending identities, and templates to each tenant. Each tenant functions as a logical container that maintains its own sending reputation independently. This tenant-based reputation isolation makes sure deliverability issues with one tenant won’t affect your other tenants. You also get real-time visibility into tenant-level metrics, including messages sent, bounce rates, and complaint rates.

The following diagram illustrates the solution architecture.

Tenants are a best practice for those who want visibility, isolation, and control over their email reputation, from large-scale platforms to smaller teams:

  • Independent software vendors (ISVs) with multiple customers, and marketing and software as a service (SaaS) solutions using a central AWS SES account – You can provision a tenant for each customer to segregate email sending and prevent one client’s sending from negatively affecting deliverability for other clients.
  • Enterprises and other large organizations with multiple BUs – You can maintain separate reputation profiles for different BUs, departments, or brands within the same AWS account.
  • Organizations with distinct mail streams – You can separate transactional and marketing mail, or keep product notifications distinct from internal communications, to make sure issues with one tenant’s email stream don’t affect the other tenants.
  • Single-stream senders – Even if you currently only operate one email stream, you can future-proof your SES account by assigning a tenant from day one. This provides visibility into reputation findings and helps you apply proactive policies to stay ahead of deliverability issues before they impact sending.

In the following sections, we outline how to plan and execute your migration to Amazon SES tenants. We show how to assess your current setup, choose the right tenant structure for your organization, and implement a gradual rollout that minimizes disruption to your existing email operations.

Pre-migration assessment

If you are already using Amazon SES, the transition to tenant-based architecture begins with understanding your current email infrastructure. Start by creating an inventory of your existing sending identities (domains) and identify what, if any, Amazon SES configuration set is assigned. This will help you understand how each customer or BU is currently distributed across your Amazon SES infrastructure. Review each configuration set to identify and track the various configuration options, such as the sending IP pool and archive option. The information you uncover in this phase will serve as the blueprint for your tenant associations and help you make sure each tenant has access to the appropriate resources, while maintaining proper isolation boundaries.

Recommended tenant structure: Individual tenants per customer

For most implementations, we recommend creating one or more tenants per customer or BU so you can achieve complete tenant-level isolation of email workloads. With this approach, you can supply dedicated SMTP or API credentials per tenant to provide secure access to allocated resources. You can apply different reputation policies per tenant as needed and automatically pause any tenant that conflicts with the reputation policy. Additionally, the shared tenant monitoring tools in Amazon SES help you automatically monitor and enforce reputation-based policies at the tenant level, so that problematic email sending behavior from one tenant doesn’t impact the deliverability of others.

The following diagram shows an example of an ISV that operates a SaaS platform on AWS that sends emails on behalf of its many customers from a single Amazon SES account. They have followed the recommended approach by implementing a 1:1 mapping between tenants and customers. This strategy provides complete reputation isolation for each customer and makes sure the ISV operating the Amazon SES account can automatically prevent deliverability issues from one customer from impacting others. This architecture minimizes the reputation damage a single tenant can cause to the ISV’s Amazon SES account’s shared resources like IP pools and domains, making it the optimal choice for maintaining high deliverability standards.

Resource sharing strategies

Your resource allocation strategy depends on your business model and customer segmentation. Consider the following recommended approaches:

  • Complete resource isolation – Each customer, brand, BU, or workload is assigned to individual, dedicated resources using the tenant configuration. This approach offers the simplest migration path: associate each customer’s dedicated resources (identities, IP addresses) with their corresponding tenant and continue operations with enhanced isolation. This model works well for enterprise customers and ISVs who deploy dedicated IPs for customers and require complete separation.
  • Tiered resource sharing – Organizations and ISVs with service tiers (such as free, pro, and VIP) can align tenants and resource sharing with these tiers. Free-tier customers might use the free-tier tenant and share basic resources, pro customers access the pro-tier tenant that maps to enhanced shared resources, and VIP customers receive dedicated resources, often using VIP customer-specific tenants. This balances cost-efficiency with appropriate isolation levels for each customer segment.
  • Extensive resource sharing – Even when email streams share most resources in the Amazon SES account, such as sending identities and IP pools, tenant isolation tenant isolation allows you to protect the sender reputation for independent email streams you send through the shared resources. Consider grouping similar types of customers or email streams into a single tenant or assigning a certain number of customers to each tenant. Although the grouping might be varied, the Amazon SES tenant feature can still minimize the effect of problematic email streams in any one tenant from affecting other tenants by pausing the offending tenant. This helps avoid Amazon SES account-level reputation damage to shared resources, protecting customers and stakeholders using those resources.

Tenant limits and quotas

Amazon SES provides tenant limits to accommodate various organizational scales. The default limit supports 10,000 tenants per account, which is sufficient for most organizations. Qualifying accounts can request increases for more tenants as needed through the Service Quotas console.

Importantly, implementing tenants doesn’t impact your account-level sending quotas or transactions per second (TPS) limits; these remain unchanged and continue to apply across the tenants within your account.

Low-friction adoption

Amazon SES tenants are designed for low-friction adoption, providing isolated containers for your existing Amazon SES email infrastructure. With tenants, you can continue sending emails using your current domains, configuration sets, and IP pools while progressively associating them with appropriate tenants. If you use them, your senders can continue targeting their assigned configuration set. After you’ve configured your Amazon SES account with tenants, instruct your customers or event buses to add a new Amazon SES API call or SMTP header specifying their unique tenant ID. If you aren’t yet using configuration sets, we’ve found that the introduction of the Amazon SES tenants feature often serves as a compelling reason for ISVs and large organizations to adopt configuration sets. If your organization has been looking for ways to offer enhanced email services to existing customers, you might want to use this opportunity to review customer accounts and offer dedicated IPs or email archiving to important email workloads. The ability to gradually roll out the Amazon SES tenants feature facilitates selective adoption, starting with a subset of customers, brands, event buses, or workloads before expanding to your entire customer base. This phased approach enables testing and refinement of your tenant strategy without disrupting existing email operations. Organizations can validate their tenant configuration with low-risk customers before rolling out to critical segments, providing a smooth transition to enhanced reputation management.

Conclusion

In this post, we discussed key aspects of the migration process to Amazon SES tenants, from initial assessment to tenant structure planning. Part 3 of this series will cover details of IAM configuration, monitoring setup, and practical implementation examples. Whether you’re running a SaaS platform, managing multiple brands, operating separate BUs, or just starting to use Amazon SES for your organization, the tenant feature provides simple reputation isolation, boosts efficiency, and helps create better experiences for users.

To learn more, refer to the following resources:


About the authors

Learning email deliverability with Amazon SES

Post Syndicated from Alaa Hammad original https://aws.amazon.com/blogs/messaging-and-targeting/learning-email-deliverability-with-amazon-ses/

Emails landing in spam folders? Facing account suspension warnings? This blog post walks you through seven targeted video tutorials that address the most common Amazon Simple Email Service (Amazon SES) deliverability challenges our customers encounter. Each video in this series provides actionable insights which will allow you to gain knowledge on every aspect of email deliverability, improve your email performance and increase your inbox placement rates.

Why email deliverability matters

Poor deliverability can lead to emails landing in spam folders, increase bounce rates, and can trigger account suspension. Email deliverability directly impacts:

  • Your sender reputation
  • Inbox placement rates
  • Customer engagement
  • Business revenue
  • Compliance with email service provider policies.

Our video series will help you avoid these pitfalls and build a robust email delivery strategy, including onboarding to Amazon SES, choosing your IP, monitoring feedback, reputation, and how to handle unsubscribes, bounces, and complaints.

Onboarding your email solution to Amazon SES

Watch: SES Deliverability learning series: Onboarding your email solution to Amazon SES

What you’ll learn: This video provides a complete migration roadmap for moving your email system to Amazon SES, including domain verification and authentication setup through DKIM, SPF, and DMARC protocols. You’ll learn how to move the account to the production access, acquire and configure dedicated IPs, create and manage configuration sets, and set up Virtual Deliverability Manager for email monitoring. The video also covers the difference between SMTP and API sending methods to explain bulk sender requirements and how to comply with them for successful email delivery.

How this helps with email deliverability: Following SES best practices when onboarding your email system to Amazon SES will help protect your emails from being spoofed, with proactive monitoring using Virtual Deliverability Manager, you can identify issues before they impact delivery, maintaining strong sender reputation and sustained email delivery success.

Choosing the right Amazon SES IP

Watch: SES Deliverability learning series: Choosing the Right Amazon SES IP for Your Email Needs

What you’ll learn: Key differences between shared IPs, dedicated IPs (Managed and Standard), How to choose the right IP environment based on your sending volume and use case, best practices for managing IP reputation, the IP warm-up process and its importance, and shared responsibilities between you and Amazon SES when using dedicated IPs. This video shows you how to rebuild trust with mailbox providers through proper IP management.

How this helps with email deliverability: If your account’s reputation was impacted due to poor sending practices, switching to dedicated IPs can help isolate your reputation and provide better control over your sending environment.

Monitoring email feedback

Watch: Mastering email deliverability: Monitoring email feedback

What you’ll learn: Discover how Amazon SES feedback loops can prevent account pause by alerting you to rising complaint, understanding and analyzing complaint data, utilizing mailbox provider postmaster tools, setting up comprehensive monitoring dashboards, tracking deliverability and engagement metrics, and strategies for emails to reach intended recipients. This video teaches you how to set up systems that alert you to rising complaint rates, bounce rates, and other warning signs before they started to impact your account’s ability to send emails.

How this helps with email deliverability: Proper monitoring is essential for preventing further complaints or bounces that could put your AWS account at risk of termination.

Email reputation with Amazon SES

Watch: Mastering email deliverability: Email Reputation with Amazon SES

What you’ll learn: What email reputation is and why it matters, how email providers evaluate sender reputation, best practices for isolating and managing your reputation, authentication methods to protect your reputation, and effective monitoring techniques for reputation management.

How this helps with email deliverability: Understanding email reputation is important for maintaining a good reputation with mailbox providers.

Handling email unsubscribes

Watch: Mastering email deliverability: Handling email unsubscribes

What you’ll learn: The importance of proper unsubscribe handling, how to remove unsubscribes from your SES mailing lists, the connection between unsubscribes and deliverability rates, strategies to maintain clean email lists, how to identify and prevent mass unsubscribe events, what to do when you see high unsubscribe rates. This video shows you how to properly handle unsubscribes and reduce rates that might trigger spam complaints by mailbox providers or impact your account’s ability to send emails.

How this helps with email deliverability: High unsubscribe rates often indicate content quality issues, sending emails to users who don’t want or expect, list hygiene issue, not having a proper confirmed opt-in, and sending too frequently.

How to handle bounces and boost inbox success

Watch: Mastering Email Deliverability: How to Handle Bounces and Boost Inbox Success

What you’ll learn: Different types of email bounces (soft and hard bounces), What each bounce type indicates about your campaign health, practical strategies to manage and reduce bounce rates, best practices for cleaning your email lists, how to implement effective bounce monitoring systems, steps to identify and address unusual bounce trends, and actionable solutions for common bounce-related challenges. This video provides specific strategies to clean your lists and reduce bounce rates that could impact your account’s ability to send emails, helping you demonstrate improved sending practices with SES.

How this helps with email deliverability: High bounce rates often indicate that a sender is sending unsolicited email to their recipients.

Understanding and handling email complaints

Watch: Mastering Email Deliverability: Understanding and Handling Email Complaints

What you’ll learn: What email complaints are and why they matter, different types of complaints (spam reports, unsubscribe requests), how complaints directly impact your deliverability rates, the correlation between complaint rates and spam folder placement , strategies to keep complaint rates within ideal ranges, practical tips to proactively reduce email complaints, and best practices for content creation and opt-out options. This video helps you understand how to maintain a healthy sender reputation by implementing best practices that align with email service provider guidelines and minimize potential risks to the email system.

How this helps with email deliverability: Mailbox providers may reject emails received from senders based on the complaints they received from their recipients.

Take action today

Don’t let deliverability issues impact your business success. Each video in this series provides practical, actionable guidance that you can implement immediately. Whether you’re dealing with account suspensions issue or simply want to optimize your email performance, these videos will help you establish reliable email delivery that meets mailbox provider requirements.

Ready to get started? Begin with the video that addresses your most pressing challenge, then work through the complete series to learn more about all aspects of email deliverability with Amazon SES.

Have questions about implementing these strategies? The AWS Support team is here to help you optimize your email deliverability and resolve any challenges you may be facing.


About the author

How to register for a US toll-free number with AWS End User Messaging

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/how-to-register-for-a-us-toll-free-number-with-aws-end-user-messaging/

As businesses increasingly use SMS messaging to engage with customers at scale, having the right origination identity is crucial. Toll-free numbers (TFNs) are the quickest way to begin sending to the United States and offer a trusted, high-visibility option that can drive greater response and brand recognition. This post is for every company that wants to send to the US or internationally.

Obtaining and properly registering a US toll-free number requires a registration process and adhering to requirements set forth by mobile carriers. This comprehensive guide walks you through the step-by-step procedure for registering a US toll-free number through AWS End User Messaging, which provides robust SMS capabilities to AWS customers.

The benefits of using a US toll-free number

TFNs offer several key advantages over other SMS origination types in the US market:

Toll-free facts

  • The opt-out flow for US TFNs is managed at a network level and enforced by US Carriers. If a user sends the word stopor any of the other supported keywords—to the TFN, the carrier sends the following outbound message to the user: NETWORK MSG: You replied with the word "stop" which blocks all texts sent from this number.
    Text back unstop or start to receive messages again. This behavior cannot be changed.
  • Toll-free numbers have a throughput of three Message Parts per Second (MPS).
  • International toll-free numbers are two-way capable in the US and Canada but are one-way only in all other supported countries. Depending on the country being sent to, if not the US or Canada, your end-user can receive your message from an originator other than your TFN. This feature can be turned on before or after registration.

The TFN registration process

To get started, you need to create a US toll-free number registration in the AWS Management Console for AWS End User Messaging or use the API.

  1. Company information: Provide details about your business, including the company name, website, and headquarters address.
  2. Contact information: Enter the name, email, and phone number of the individual who will serve as the main point of contact for your TFN program. This email address should match the domain of the company being registered and cannot be a distribution list, contact group, or mailing list. This information will be used for verification or in the event of something needing to be communicated to you about your TFN. It will not be public knowledge.
  3. Messaging use case: Describe how you intend to use the TFN, including your estimated monthly SMS volume, and select the Use Case Category (such as two-factor authentication, notifications, or marketing).
  4. Use case details: It’s critical that the Use Case Details field and all message templates are consistent with the Use Case Category you selected in the previous step.

For example, if you select two-factor authentication or one-time passwords, your Use Case Details should explain how you plan to use your TFN for that use case, who you will interact with, and why. Answers must be written in English, and it is very important to be clear and concise in this section. Humans are reviewing these, so make sure that everything you write can be understood without prior knowledge of your company or your use case.

  1. Opt-in Workflow Description: This has several boiler-plate components that must be present at the point of opt-in and are discussed in depth in this blog post. If you have a verbal opt-in, you can include the script in this field. If you have a publicly available form, you can supply the URL in the description. Regardless of the format, you must include the following elements at the point of opt in:
    1. Program (brand) name.
    2. Explicitly state the purpose of the SMS program that your end-users are opting into.
    3. Have no prefilled checkboxes, radio buttons, or other fields.
    4. Message frequency disclosure. For example: Message frequency varies or One message per login.
    5. Customer care contact information. For example, Text HELP or call 1-800-111-2222 for support.
    6. Opt-out information. For example: Text STOP to opt-out of future messages.
    7. Include Message and data rates may apply disclosure.
    8. Link to a publicly accessible terms and conditions page.
        • Note: See this post on opt-in processes for terms that must be included.
        • If you are unable to include a public link to your terms, you can include them in the Opt-in workflow image field or alternatively attach them to the registration form or another method like an Amazon S3 presigned URL. Make sure to keep it separate from the actual opt-in screenshots.
    9. Link to a publicly accessible privacy policy page.
        • Note: Carriers are primarily concerned with data sharing of opt-in information to third parties. It’s recommended to have a specific SMS section that addresses that no data gathered during opt-in is shared. See this post on opt-in processes for more details on creating a compliant privacy policy.
        • If you’re unable to include a public link, you can include the full terms in the Opt-in workflow image field or alternatively attach them to the registration form or another method like an Amazon S3 presigned URL. Make sure to keep it separate from the actual opt-in screenshots.
  2. Opt-in workflow image: Upload an image showing how users consent to receiving messages.
    • The maximum file size is 500 KB, and valid file extensions are PDF, JPEG, and PNG.
    • This could be a screenshot of a non-public form, a written consent form, or other evidence of a compliant explicit opt-in that includes all the elements detailed previously.
    • Make sure that the screenshot is clear and readable; degraded image quality will likely be rejected regardless of compliance.
  3. Message samples: Each sample message should reflect actual messages to be sent, should match the Use Case Category you indicated previously, and should follow these best practices:

    • Indicate any variable fields with brackets and make sure to be clear what information can be replaced.
    • Example: Hi, [FirstName] this is AnyCompany letting you know that your delivery is ready.
    • Each sample message must be at least 20 characters. If you plan to use multiple message templates, include them too.
    • Ensure that all messages include your brand name and that it’s consistent with the previously entered information.
    • Make sure your messaging doesn’t involve prohibited content such as cannabis, hate speech, and so on; and that your use case is compliant with AWS Messaging Policy.
  4. Review and submit: Verify that all information is accurate before submitting your registration for approval. There are no exceptions to an explicit opt-in—this includes one-time password use cases, so make sure that your registration includes all the required elements.

The TFN provisioning process

After your TFN registration is submitted it will be reviewed by the same third-party as all other SMS vendors across the globe, not by AWS. You can find current registration time estimates in the number registration process. While waiting, you can monitor your registration status for rejection or acceptance. This AWS blog post has an example of using AWS Lambda to monitor status changes.

If your registration is rejected, the status will change to REQUIRES_UPDATES and should have at least one rejection reason that needs to be reviewed and updated before resubmitting. Follow these instructions to update a rejected registration.

Sending SMS messages and monitoring delivery receipts

After your TFN is activated, you can begin sending SMS messages through AWS End User Messaging. It’s important to monitor your program closely and maintain compliance, because carriers might filter or block your messages if there are issues with your program. This blog post reviews best practices for how to monitor deliverability of SMS messages.

Conclusion

Make sure to follow each step carefully and answer each question completely. There are humans reviewing these so it’s important that your answers are succinct and clear.

As an AWS customer, you have access to powerful messaging capabilities through AWS End User Messaging. By following the steps outlined in this guide, you can quickly register for a US toll-free number to start your SMS outreach. Maintaining compliance is key, and with a TFN in place, you’ll be well on your way to delivering highly effective, compliant SMS messaging that drives real business impact. If you have other questions about AWS End User Messaging, see the comprehensive API specs, the User Guide, or reach out to AWS Support.


About the authors

Track OTP success with AWS End User Messaging SMS feedback

Post Syndicated from Rommel Sunga original https://aws.amazon.com/blogs/messaging-and-targeting/track-otp-success-with-aws-end-user-messaging-sms-feedback/

In this post, we show how to implement message feedback for SMS one-time passwords (OTPs) using AWS End User Messaging. OTP verification through SMS is a fundamental component of modern authentication systems. Although sending OTPs follows an established pattern, tracking their delivery and usage presents several challenges. This post shows how to implement the AWS End User Messaging Message Feedback API to monitor OTP delivery and conversion rates effectively. This post highlights the Message Feedback API in an OTP use case; for practical examples and detailed guidance on building a secure OTP architecture, see Build a Secure One-Time Password Architecture with AWS.

Challenges with OTP tracking

Organizations commonly face these key challenges with OTP tracking:

  • Relying solely on Delivery Receipt (DLR) data for confirming message delivery, which is third-party carrier data that can be subject to interpretation by carriers or message providers, whereas conversion tracking through message feedback provides first-party data that can more accurately reflect actual message delivery and usage
  • Measuring accurate user authentication success rates
  • Identifying OTP verification issues across different geographic regions, carriers and delivery paths

To address these challenges, you can use the AWS End User Messaging Message Feedback API to track delivery and conversion rates, providing first-party data for more accurate insights into message delivery and usage patterns. Although OTP use cases are the most common and serve as our example implementation of message feedback, the same tracking logic can also be applied to other types of SMS conversions, such as promotional link clicks, shopping cart additions, account activations, appointment confirmations, and delivery notifications.

Solution overview

The OTP message flow consists of two main phases. Let’s first examine how the system handles the initial OTP request.

Phase 1: OTP request flow

When a customer initiates an OTP request, your system begins a carefully orchestrated process. First, your application receives this request and generates a unique OTP. With the OTP generated, your system prepares to send it through the AWS End User Messaging API, specifically enabling message feedback tracking by setting the MessageFeedbackEnabled parameter to true when calling SendTextMessage.

Upon successful sending, it returns a unique message ID, which your system must store alongside the generated OTP. This message ID serves as a crucial tracking identifier for the entire verification process. The message is then dispatched to the customer’s device, and your system enters a waiting state, ready to process the verification attempt.

The following diagram illustrates the OTP request flow.

OTP Request Flow Diagram

Phase 2: OTP verification flow

The verification process begins when the customer receives the OTP through SMS and submits it back to your system. Upon receiving the submission, your system first validates the OTP against the stored value. This verification step is critical, because its outcome determines how you will update the message feedback status.

If the customer successfully verifies the OTP, your system calls the PutMessageFeedback API with the stored message ID and sets the status to "RECEIVED", indicating successful delivery and usage of the OTP. However, if the verification fails or the customer doesn’t respond within the timeout period, your system sets the status to "FAILED".

If your system doesn’t explicitly update the feedback status within 1 hour, AWS automatically sets it to "FAILED".

The following diagram illustrates the OTP verification flow.

Prerequisites

Before you begin implementing OTP message feedback, make sure you have the following components and permissions in place:

Send SMS with message feedback enabled

You can enable message feedback in two ways. The first method is to use the MessageFeedbackEnabled parameter when sending an SMS, the second is to send a message with a configuration set with message feedback already enabled. Using a configuration set is often more convenient for bulk implementations because you don’t need to specify message feedback settings in each API call.

To send an SMS with message feedback enabled directly, you can use the following function:

import boto3

# Initialize the End User Messaging client
client = boto3.client('pinpoint-sms-voice-v2')

def send_otp_with_feedback():
    # Generate a unique OTP
    otp = generate_otp()  
    
    # Send SMS with feedback enabled
    response = client.send_text_message(
        DestinationPhoneNumber='+15555550123',  # Replace with your destination phone number
        OriginationIdentity='+14255550120',  # Replace with your origination identity
        MessageBody=f'Your verification code is: {otp}',
        MessageFeedbackEnabled=True
    )
    
    # Store OTP details for verification
    store_otp_details(response['MessageId'], otp)
    return response['MessageId']

The function uses the following details:

  • store_otp_details() is a placeholder function where you store the OTP details in a database for later retrieval
  • generate_otp() is a placeholder function where you generate your OTPs to send using SMS

If you prefer to use a configuration set with message feedback enabled, you can use the following alternative function:

def send_otp_with_feedback_using_configuration_set():
    # Initialize the End User Messaging client
    client = boto3.client('pinpoint-sms-voice-v2')
    
    # Generate OTP
    otp = generate_otp()
    
    # Send SMS using configuration set
    response = client.send_text_message(
        DestinationPhoneNumber='+15555550123',  # Replace with your destination phone number
        OriginationIdentity='pool-201d59fffd554bdfbaf9ee8aEXAMPLE',  # Replace with your origination identity
        MessageBody=f'Your verification code is: {otp}',
        ConfigurationSetName='example-us-east-configuration-set'  # Replace with your configuration set name
    )
    
    # Store OTP details for later verification
    store_otp_details(response['MessageId'], otp)
    
    return response['MessageId']

Your configuration set must have message feedback enabled to use this option. You can enable it using the AWS Command Line Interface (AWS CLI) with the following command:

aws pinpoint-sms-voice-v2 set-default-message-feedback-enabled \
--configuration-set-name "YourConfigSetName" \
--message-feedback-enabled

Another option is to use the AWS End User Messaging console, where you can enable message feedback under Set Settings for the desired configuration set.

Update feedback

After you send a message, you can update the message status to indicate whether a user has successfully completed an action, such as entering the OTP on your application or webpage:

def update_message_feedback(message_id: str, status: str) -> dict:
    try:
        # Initialize the End User Messaging client
        client = boto3.client('pinpoint-sms-voice-v2')
        
        # Update the message feedback status
        response = client.put_message_feedback(
            MessageId=message_id,
            MessageFeedbackStatus=status
        )
        
        return response
        
    except Exception as e:
        print(f"Error updating message feedback: {str(e)}")
        raise

# Example usage
message_id = "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"  # Replace with your message ID
status = "RECEIVED"  # Use "FAILED" for unsuccessful verifications

result = update_message_feedback(message_id, status)
print(f"Feedback status updated: {result}")

Verify feedback metrics

The AWS End User Messaging dashboard provides comprehensive metrics to help you monitor your OTP performance. The following metrics are available for customizable time periods:

  • Number of messages with feedback completion
  • Percentage of messages with feedback completion
  • Number of SMS with feedback completion by country

To review your application’s overall message feedback metrics, choose Dashboard in the AWS End User Messaging console navigation pane, then choose Message Feedback Metrics.

The dashboard presents three key metrics:

  • Number of messages with feedback completion – The count of SMS and MMS messages where the message feedback record is set to RECEIVED
  • Percentage of messages with feedback completion – The percentage of SMS and MMS messages where the message feedback record is set to RECEIVED
  • Number of SMS with feedback completion by country – The count of message feedback received by country

The progression to 100% completion indicates optimal system performance, where all sent OTPs were successfully received and verified by users, and the message feedback record is set to RECEIVED within the expected timeframe. This high completion rate suggests effective message delivery and a smooth user verification experience. Variations in completion rates across countries can help identify potential regional delivery challenges or user behavior patterns.

The 30% conversion starting point shown in this example is used for illustration purposes only, demonstrating messages that were intentionally left unconverted during testing.

Best practices for OTP implementation

For a secure and reliable OTP implementation, follow these best practices to balance security with user experience:

  • Include rate limiting to prevent abuse
  • Implement proper timeout mechanisms for OTPs
  • Make sure error handling provides clear feedback to users
  • Maintain comprehensive logging for security audits

Conclusion

By implementing the Message Feedback API for OTP tracking, you can gain valuable insights into your authentication system’s effectiveness in real time. This approach helps you monitor successful OTP usage and identify potential delivery issues that might affect user authentication, with granular metrics broken down by geographic regions. The data collected through message feedback offers a more accurate picture of actual user interactions compared to carrier-provided delivery receipts, helping you make data-driven decisions about your authentication system.

To build upon this foundation, consider implementing Amazon CloudWatch alerts for your conversion metrics, and optimizing your message templates based on performance data. The combination of real-time feedback, detailed analytics, and proactive monitoring can help make sure your OTP system remains both secure and efficient.

For additional implementation guidance and best practices, refer to the following resources:


About the authors

A Complete Guide to Resource Sharing for AWS End User Messaging

Post Syndicated from Brett Ezell original https://aws.amazon.com/blogs/messaging-and-targeting/a-complete-guide-to-resource-sharing-for-aws-end-user-messaging/

Introduction

Do you need to send SMS across multiple AWS accounts? Or have you ever wanted to use the same specific 10DLC phone number or branded Sender ID across those accounts? Perhaps your development team needs to test an application in a sandbox account using a production-ready number, or you’re migrating a workload to a new account and need to ensure your customer communications aren’t disrupted. Centralizing your messaging resources across accounts improves efficiency and branding, while lowering the risk in compliance gaps..

In this step-by-step guide, we will show how to solve this challenge by sharing your AWS End User Messaging resources across multiple AWS accounts using AWS Resource Access Manager (AWS RAM). By creating a single sharing account for your messaging resources—like phone numbers, Sender IDs, and opt-out lists—and securely sharing them with your other “consuming” accounts, you can build a more efficient, secure, and scalable communication platform.

Common Use Cases for Resource Sharing

Important: resource sharing with AWS RAM is a regional feature. You can only share resources with accounts within the same AWS Region where those resources are located.

Centralizing and sharing resources is a powerful pattern that addresses several common customer needs:

  • Testing in a Sandbox Environment: Allows development teams to test applications using production-ready phone numbers or Sender IDs in an isolated sandbox account, without giving them access to production configurations.
  • Simplified Registration and Onboarding: Share an existing pre-registered 10DLC number or Sender ID with a new account that has not yet completed its own registration process, enabling it to start sending messages more quickly.
  • Seamless Account Transitions: When migrating an application or workload to a new AWS account, you can share the existing origination identities. This makes certain that your phone numbers and Sender IDs remain consistent during the transition, preventing any disruption to your customer-facing communications.

This guide will walk you through the step-by-step process of sharing your AWS End User Messaging resources.

Shareable AWS End User Messaging Resources

You can share the following AWS End User Messaging resources using AWS RAM:

  • Phone Numbers: Share your dedicated short codes, 10DLCs, long codes, and toll-free numbers. This allows different accounts to send messages using a centralized pool of numbers.
  • Sender IDs: Share alphanumeric sender IDs to maintain consistent branding in one-way SMS messages across your accounts.
  • Opt-out Lists: Centralize your opt-out management to ensure regulatory compliance. When a user opts out of messaging from one account, they are opted out across all accounts using that shared list. This is especially powerful when used with pools, as you can associate a pool with a specific opt-out list, ensuring all numbers in that pool adhere to the same primary list. As a best practice, you should create and share a dedicated opt-out list rather than relying on the default list for each account.
  • Pools: Share your pools of phone numbers and sender IDs to manage origination identities at scale. Pools provide benefits like automatic failover and apply settings like opt-out lists or two-way SMS configurations to the entire pool.
    • Important: for a shared Opt-out list or pool to be functional, all of its member resources (the phone numbers and/or Sender IDs within it) must also be included in the same AWS RAM resource share.

Understanding AWS RAM Fundamentals

Before sharing your End User Messaging resources, it’s essential to understand the core concepts of AWS RAM.

  • Resource Share: This is the central component in AWS RAM. A resource share consists of three elements:
    • The resources to be shared (such as phone numbers, or opt-out lists).
    • The principals (AWS accounts, OUs, or an entire organization) with whom you are sharing.
    • The managed permissions that define what actions the principals can perform on the shared resources.

Important: The supported resources of AWS End User Messaging are shareable with AWS accounts, Organizations, and OUs, but not with individual AWS Identity and Access Management (IAM) roles or users. This restriction ensures that resource sharing remains at the account level, maintaining clear boundaries and simplifying access management for your End User Messaging infrastructure.

  • Sharing Account vs. Consuming Account:
    • The sharing account (or owner account) is the AWS account that owns the resources and creates the resource share.
    • When a principal (such as an AWS account) is granted access to a resource share, it becomes a consuming account. It can use the shared resources according to the permissions granted and pays for its own usage of those resources, not for the resources themselves. For example: The consuming account pays for the volume of SMS sent by a shared number but the sharing account pays for any fees associated with owning that actual number.
  • AWS Organizations Integration: While you can share resources with individual AWS accounts, the most powerful way to use AWS RAM is in conjunction with AWS Organizations. This service allows you to centrally manage and govern multiple AWS accounts under a single umbrella. When you enable sharing within your organization, you can share resources with all accounts in the organization, or with specific Organizational Units (OUs), seamlessly and without needing to send and accept individual invitations. This sharing is only possible between accounts that reside in the same AWS Region.
  • Managed Permissions: AWS RAM uses managed permissions to control access.
    • AWS managed permissions are predefined permission sets created and maintained by AWS for common use cases. For AWS End User Messaging, the key permission is AWSRAMDefaultPermissionSmsVoice, which allows consumers to use the resources for sending messages but not for deleting or modifying them.
    • Customer managed permissions can be created for more granular control over shared resources.
  • Resource-Based Policies: Behind the scenes, AWS RAM works by creating and managing resource-based policies for you. These policies are what actually grant the consuming accounts access to the shared resources.

To better illustrate these sharing models, the following diagrams show how a Sharing Account can share its AWS End User Messaging resources using different strategies:

Diagram 1: Direct Account-to-Account Sharing:

Diagram 2: Sharing with an Entire AWS Organization:

Diagram 3: Sharing with a Specific Organizational Unit (OU):

Prerequisites and Setup

For the following walkthrough, we will demonstrate how to configure the setup for Diagram 1: Direct Account-to-Account Sharing. However, the steps for managing and using the resource share are similar for all three scenarios. Before you begin, ensure your environment is set up correctly.

Note for AWS Organizations Users: When your account is managed by AWS Organizations, you can take advantage of that to share resources more easily. With or without Organizations, a user can share with individual accounts. However, if your account is in an organization, then you can share with individual accounts, or with all accounts in the organization or in an OU without having to enumerate each account.

If you plan to share resources using AWS Organizations (as shown in Diagram 2 or Diagram 3), you must complete the following prerequisite steps from your organization’s management account before creating a resource share:

1. Enable all features in your organization:

aws organizations enable-all-features

2. Enable resource sharing with AWS RAM: This creates the necessary service-linked role.

aws ram enable-sharing-with-aws-organization

1. Required IAM Permissions

The IAM user or role performing these actions needs permissions for both AWS RAM and AWS End User Messaging. The following policy grants the necessary permissions to manage resource shares.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "RAMResourceShareManagement",
            "Effect": "Allow",
            "Action": [
                "ram:UpdateResourceShare",
                "ram:DeleteResourceShare",
                "ram:AssociateResourceShare",
                "ram:DisassociateResourceShare"
            ],
            "Resource": "arn:aws:ram:*:*:resource-share/*"
        },
        {
            "Sid": "DiscoveryAndCreationPermissions",
            "Effect": "Allow",
            "Action": [
                "ram:CreateResourceShare",
                "ram:GetResourceShares",
                "ram:ListResources",
                "organizations:ListAccounts",
                "organizations:DescribeOrganization",
                "pinpoint-sms-voice-v2:DescribePhoneNumbers",
                "pinpoint-sms-voice-v2:DescribeSenderIds",
                "pinpoint-sms-voice-v2:DescribeOptOutLists",
                "pinpoint-sms-voice-v2:DescribePools"
            ],
            "Resource": "*"
        }
    ]
}

Note on Least Privilege: This policy follows the security best practice of granting least privilege. The first statement scopes modification permissions to only AWS RAM resource shares. The second statement grants permissions for discovery actions (like Describe* and List*) and the ram:CreateResourceShare action, which require "Resource": "*" as they do not operate on a specific, pre-existing resource.

2. Regionality Requirement

Important Reminder: resource sharing with AWS RAM is a regional feature. You can only share resources with accounts within the same AWS Region where those resources are located.

For example, a resource in us-east-1 can only be shared with other accounts in us-east-1, regardless of where those accounts operate other resources. Ensure that the resources you intend to share and the accounts that you anticipate sharing with are each considering the same Region for this process.

Creating and Managing Resource Shares (Sharing Account Actions)

This section provides a step-by-step guide to sharing your resources using the AWS CLI. We will walk through creating a resource share, associating and disassociating resources, and checking the status of your shares.

Step 1: Create an Empty Resource Share

First, create the resource share. Think of this as an empty container. You will associate principals (the consuming accounts) and resources (the phone numbers, etc.) with this share.

In the command below, we will create a share named EUM-Shared-Resources for an external account.

# Create a resource share and grant default End User Messaging permissions # Replace 123456789012 with the consuming account's ID
aws ram create-resource-share \
    --name "EUM-Shared-Resources" \
    --principals "123456789012" \
    --permission-arns "arn:aws:ram::aws:permission/AWSRAMDefaultPermissionSmsVoice" \
    --allow-external-principals \
    --region us-east-1
  • --principals: Specify one or more AWS account IDs.
  • --allow-external-principals: This flag is required when sharing with accounts that are not part of your AWS Organization.

Expected Response: A successful command returns a JSON object describing the new resource share. Note that allowExternalPrincipals is now true.

{
    "resourceShare": {
        "resourceShareArn": "arn:aws:ram:us-east-1:111122223333:resource-share/a1b2c3d4-5678-90ab-cdef-example11111",
        "name": "EUM-Shared-Resources",
        "owningAccountId": "111122223333",
        "allowExternalPrincipals": false,
        "status": "ACTIVE",
        "tags": [],
        "featureSet": "STANDARD"
    }
}

For the following sections and when specifying resource ARNs, ensure you’re using the correct format for AWS End User Messaging resources:

  • Phone numbers: arn:aws:sms-voice:region:account-id:phone-number/phonenumber-id
  • Sender IDs: arn:aws:sms-voice:region:account-id:sender-id/senderid
  • Opt-out lists: arn:aws:sms-voice:region:account-id:opt-out-list/optoutlist-id
  • Pools: arn:aws:sms-voice:region:account-id:pool/pool-id

Replace ‘region‘, ‘account-id‘, and the specific resource IDs with your actual values.

Step 2: Associate Resources with the Share

Now that you have your “container,” you can add resources to it. The associate-resource-share command links one or more of your End User Messaging resources to the share you just created, making them available to the principals.

# Define the ARN of the resource share from the previous step
RESOURCE_SHARE_ARN="arn:aws:ram:us-east-1:111122223333:resource-share/a1b2c3d4-5678-90ab-cdef-111111111111"

# Associate a phone number and a pool with the share # Replace the resource-arns with your actual resource ARNs
aws ram associate-resource-share \
    --resource-share-arn "$RESOURCE_SHARE_ARN" \
    --resource-arns \
        "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4" \
        "arn:aws:sms-voice:us-east-1:111122223333:pool/pool-b2c3d4e5" \
    --region us-east-1

Expected Response: A successful association returns a JSON object confirming the association and showing its status. The status will initially be ASSOCIATING and will transition to ASSOCIATED once complete.

Note: The association process is asynchronous. We’ll show you how to verify the completion status in the next step using the get-resource-shares and list-resources commands. It’s important to confirm the status has changed to ASSOCIATED before attempting to use the shared resources.

Step 3: Verify the Status and contents of the Share

Before making changes, it’s good practice to verify what’s in the share. Use get-resource-shares to check the status and list-resources to see the contents. This process helps ensure that all intended resources are properly associated and accessible to the principals you’ve designated.

# Verify the association status is ASSOCIATED
aws ram get-resource-shares \
    --resource-owner SELF \
    --name "EUM-Shared-Resources" \
    --association-status ASSOCIATED \
    --region us-east-1

Expected Response: If the command returns no results, wait a few moments and try again. The association process is typically quick but can sometimes take up to a few minutes.

{
    "resourceShares": [
        {
            "resourceShareArn": "arn:aws:ram:us-east-1:111122223333:resource-share/12345678-abcd-1234-efgh-111122223333",
            "name": "EUM-Shared-Resources",
            "owningAccountId": "111122223333",
            "allowExternalPrincipals": true,
            "status": "ACTIVE",
            "creationTime": "2023-07-01T12:00:00.000Z",
            "lastUpdatedTime": "2023-07-01T12:00:00.000Z",
            "featureSet": "STANDARD"
        }
    ]
}

Review the output carefully to ensure all intended resources are listed. If any resources are missing, you may need to reassociate them using the associate-resource-share command.

Expected Response (list-resources): This command will return a list of JSON objects, each representing a resource in the share.

# List the ARNs of all resources currently in the share
aws ram list-resources \
    --resource-owner SELF \
    --resource-share-arns "$RESOURCE_SHARE_ARN" \
    --region us-east-1

Review the output carefully to ensure all intended resources are listed. If any resources are missing, you may need to reassociate them using the associate-resource-share command.

# List the ARNs of all resources currently in the share
aws ram list-resources \
    --resource-owner SELF \
    --resource-share-arns "$RESOURCE_SHARE_ARN" \
    --region us-east-1

Expected Response (list-resources): This command will return a list of JSON objects, each representing a resource in the share.

{
    "resources": [
        {
            "arn": "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4",
            "type": "sms-voice:PhoneNumber",
            "resourceShareArn": "arn:aws:ram:us-east-1:111122223333:resource-share/a1b2c3d4-5678-90ab-cdef-example11111",
            "status": "AVAILABLE"
        },
        {
            "arn": "arn:aws:sms-voice:us-east-1:111122223333:pool/pool-b2c3d4e5",
            "type": "sms-voice:Pool",
            "resourceShareArn": "arn:aws:ram:us-east-1:111122223333:resource-share/a1b2c3d4-5678-90ab-cdef-example11111",
            "status": "AVAILABLE"
        }
    ]
}

Step 4: Disassociate Specific Resources from the Share

To stop sharing a specific resource, you use the disassociate-resource-share command. You must provide the ARN of the resource you wish to remove. This gives you granular control, allowing you to remove one resource while continuing to share others.

# Disassociate only the phone number from the share
aws ram disassociate-resource-share \
    --resource-share-arn "$RESOURCE_SHARE_ARN" \
    --resource-arns "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4" \
    --region us-east-1

Expected Response: The response will be nearly identical to the associate response, confirming the disassociation request. The status will be DISASSOCIATING.

{
    "resourceShareAssociations": [
        {
            "resourceShareArn": "arn:aws:ram:us-east-1:111122223333:resource-share/a1b2c3d4-5678-90ab-cdef-example11111",
            "associatedEntity": "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4",
            "associationType": "RESOURCE",
            "status": "DISASSOCIATING",
            "external": false
        }
    ]
}

How to Use Shared Resources

Once resources are shared, users in the consuming accounts can discover and use them for sending messages.

Step 1: Discovering Shared Resources

From a consuming account, you can list resources that have been shared with you by using the --filters parameter in the describe-* commands.

Note: Shared resources are discoverable via the AWS CLI and SDKs but will not appear in the AWS Management Console of the consuming account. This is expected behavior, as the resources are owned by the sharing account.

# List phone numbers shared with your account
aws pinpoint-sms-voice-v2 describe-phone-numbers \
    --filters Name=shared-with-me,Values=true \
    --region us-east-1
# List sender IDs shared with your account
aws pinpoint-sms-voice-v2 describe-sender-ids \
--filters Name=shared-with-me,Values=true \
--region us-east-1

# List pools shared with your account
aws pinpoint-sms-voice-v2 describe-pools \
--filters Name=shared-with-me,Values=true \
--region us-east-1

# List shared opt-out lists with region specification
aws pinpoint-sms-voice-v2 describe-opt-out-lists \
--filters Name=shared-with-me,Values=true \
--region us-east-1

Expected Response: The command returns a JSON object listing the shared resources, including their ARNs, which you will need for sending messages.

{
    "PhoneNumbers": [
        {
            "PhoneNumberArn": "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4",
            "PhoneNumberId": "phonenumber-a1b2c3d4",
            "PhoneNumber": "+12065550100",
            "Status": "ACTIVE",
            "MessageType": "TRANSACTIONAL",
            "TwoWayEnabled": true,
            "CreatedTimestamp": "2023-10-26T14:34:56.123Z"
        }
    ]
}

Step 2: Sending Messages with Shared Resources

Important: When using shared resources, consuming accounts must specify the full ARN of the shared resource in API calls. This differs from resource owners, who can use either the resource ID, ARN, or the number directly. You can specify the ARN of an individual phone number or a pool as the origination-identity.

# Send an SMS using a shared Phone Number ARN (consuming account MUST use ARN)
aws pinpoint-sms-voice-v2 send-text-message \
    --destination-phone-number "+12065550199" \
    --origination-identity "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4" \
    --message-body "Hello from a shared number!" \
    --region us-east-1

# Send an SMS using a shared Pool ARN (consuming account MUST use ARN)
aws pinpoint-sms-voice-v2 send-text-message \
    --destination-phone-number "+12065550199" \
    --origination-identity "arn:aws:sms-voice:us-east-1:111122223333:pool/pool-b2c3d4e5" \
    --message-body "Hello from a shared pool!" \
    --region us-east-1

Expected Response: A successful send-text-message call will return a MessageId, which confirms that the service has accepted the message for delivery.

{
    "MessageId": "a1b2c3d4-5678-90ab-cdef-example22222"
}

Message Delivery Reporting:

Once a message is sent, understanding its delivery status is crucial for ensuring your communications are effective. AWS End User Messaging provides several mechanisms for tracking message delivery, giving you a multi-layered approach to reporting.

Delivery Receipts (DLRs):

For traditional, carrier-provided Delivery Receipts (DLRs), which can sometimes take up to 72 hours to be returned, you must configure an event destination. This is the most common method for confirming that a message has reached the recipient’s handset, and is achieved through a Configuration Set.

For shared resources:

  • The configuration set must be created and managed in the sharing account.
  • The consuming account must then reference the ARN of the configuration set when sending messages.
# Example for consuming account
aws pinpoint-sms-voice-v2 send-text-message 
    --destination-phone-number "+12065550199" 
    --origination-identity "arn:aws:sms-voice:us-east-1:111122223333:phone-number/phonenumber-a1b2c3d4" 
    --message-body "Hello from a shared number!" 
    --configuration-set-name "arn:aws:sms-voice:us-east-1:111122223333:configuration-set/MyConfigSet" 
    --region us-east-1

For a detailed walkthrough, see our companion blog post, How to Send SMS Using Configuration Sets with AWS End User Messaging.

Message Feedback:

For more immediate, application-driven insights, you can use the Message Feedback feature. This allows you to programmatically mark messages as “delivered” based on a user’s action, such as using a one-time password (OTP) or clicking a link in the message. This provides a real-time confirmation loop that is independent of carrier DLRs.

Amazon CloudWatch:

To monitor these events at scale, you can stream them to Amazon CloudWatch Logs to track key performance indicators like the number of messages sent and delivered, and to set up alerts based on your specific business needs.

To set up comprehensive reporting:

  1. Configure an event destination for DLRs and detailed status events.
  2. Set up CloudWatch dashboards and alerts for ongoing monitoring.

This multi-layered approach provides both immediate feedback and long-term delivery insights, allowing you to optimize your messaging strategy and quickly identify potential delivery issues.

Troubleshooting Common Issues

  • Permission Denied Errors: If a consuming account cannot access a shared resource, verify that the consuming account’s IAM policies include the necessary permissions. Here’s an example policy:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "pinpoint-sms-voice-v2:SendTextMessage",
                "pinpoint-sms-voice-v2:SendVoiceMessage",
                "pinpoint-sms-voice-v2:DescribePhoneNumbers",
                "pinpoint-sms-voice-v2:DescribeSenderIds",
                "pinpoint-sms-voice-v2:DescribeOptOutLists",
                "pinpoint-sms-voice-v2:DescribePools"
            ],
            "Resource": "*"
        }
    ]
}
  • Resource Not Visible: Remember that shared resources do not appear in the consuming account’s AWS Management Console. If the describe-* commands with the shared-with-me filter return no results, ensure the resource share status is ACTIVE in the sharing account.
    • If sharing via AWS Organizations, confirm the consuming account is correctly placed in the specified OU. You can find more information on managing OUs in the AWS Organizations User Guide.
  • CLI Command Fails: If a command fails with a “not found” or “invalid parameter” error, it is often due to an incorrect ARN. Double-check that the ARNs for resources, principals, and the resource share itself are correct. A Permission Denied error, on the other hand, points to an IAM policy issue..

Best Practices and Considerations

  • Security: Always follow the principle of least privilege. Use AWS managed permissions like AWSRAMDefaultPermissionSmsVoice where possible and create customer-managed permissions only for specific, granular requirements.
  • Cost: The sharing account is billed for provisioning the resources (e.g., the monthly cost of a phone number). Consuming accounts are billed for their usage of those shared resources (e.g., the cost per message sent). There are no additional costs for using AWS RAM.
  • Throughput and Quotas: Resource throughput quotas (e.g., messages per second) are shared along with the resource. High volume sending from multiple consuming accounts using the same shared number or pool, could collectively hit the service quota, which may result in throttling. Plan your usage accordingly or request quota increases if necessary.

Conclusion

This guide has equipped you to centralize your AWS End User Messaging resources using AWS Resource Access Manager. By implementing this strategy, you can directly address the common challenges of a multi-account environment: maintaining consistent branding with shared Sender IDs, ensuring comprehensive compliance with centralized opt-out lists, and reducing operational overhead by managing resources in one place.

We have walked through the entire lifecycle, from the initial prerequisites in AWS Organizations and IAM, to the step-by-step CLI commands for creating shares, associating resources, and enabling consuming accounts to use them. By applying these techniques and keeping the best practices for security and throughput in mind, you are now able to build a more efficient, secure, and scalable communication platform across your entire AWS ecosystem.

Improve email deliverability with tenant management in Amazon SES

Post Syndicated from Satya S Tripathy original https://aws.amazon.com/blogs/messaging-and-targeting/improve-email-deliverability-with-tenant-management-in-amazon-ses/

Amazon Simple Email Service (Amazon SES) serves diverse industries—from ecommerce services to financial institutions to marketing technology product providers—helping organizations manage their email communication needs. Many businesses face the challenge of sending emails not just for themselves, but on behalf of their downstream customers or across various business divisions. These scenarios, commonly known as multi-tenant email sending practices, require careful architectural consideration. For example, a marketing service might need to send promotional emails for hundreds of retail clients, or an enterprise IT team might manage email communications across multiple business units (BUs). These clients and BUs are also identified as tenants. To successfully implement multi-tenancy in Amazon SES, customers usually develop an architecture pattern within Amazon SES that accomplishes critical objectives to efficiently handle the email sending needs of thousands of downstream tenants while maintaining isolated email sending reputations for each tenant. This isolation is crucial for protecting each customer’s deliverability metrics and to prevent issues with one tenant from impacting others.

Amazon SES customers can achieve multi-tenancy through isolated configuration sets for sending emails, but traditionally, reputation management and enforcement occur at the account level. To address this, Amazon SES now offers tenant management capabilities that enable tenant isolation and reputation management at the individual tenant level. This new feature provides greater control and flexibility for organizations managing multiple tenants within a single Amazon SES account, allowing each tenant to maintain its own sending reputation independently.

In this post, you will learn about the newly released tenant management feature that helps customers manage individual tenant onboardings and manage their reputations in isolation. This feature helps organizations create and manage up to 10,000 isolated tenants within a single AWS account (which can be increased 300,000 on explicit request), each with independent configurations and reputation metrics. You will discover how these capabilities maintain email deliverability through automated tenant-level controls, real-time monitoring, and customizable sending policies.

Whether you’re a service provider sending emails on behalf of multiple customers or an enterprise coordinating various BUs or lines of business (LOBs), this new feature offers sophisticated workflows to identify reputation-based findings and pause individual tenant sending to protect other tenants’ reputations. These enhancements are available globally across AWS Regions where Amazon SES is offered, representing a significant advancement in email deliverability management at scale.

Use cases

Following use cases can easily achieved though Amazon SES tenant management feature.

  • Onboard multiple brands from different BUs with different domains
  • Separate marketing and transaction tenants
  • Support independent software vendor (ISV) customers’ requirement to segregate email sending reputation of their customers
  • Domain management using configuration sets.
  • Track individual customers’ email sending reputations and control their email sending processes

Multi-tenant email operation challenges

Businesses rely on email as a critical communication channel. However, managing email operations for multiple tenants (customers or business units) has historically presented significant challenges such as:

  • Lack of isolation: Without proper tenant isolation, poor sending practices by one tenant could negatively impact the email deliverability of others, potentially jeopardizing your entire email sending operation.
  • Limited visibility: Understanding per-tenant email performance metrics and managing reputation independently has been difficult, if not impossible.
  • Scalability constraints: Many organizations struggle to scale their email operations because of account-level limitations on resources such as identities and configuration sets.
  • Inadequate control: The inability to set tenant-specific limits and configurations has made it challenging to prevent individual tenants from impacting others or exceeding allocated resources.
  • Complex monitoring: Building custom solutions for monitoring tenant activity often leads to inconsistent and inefficient workflows.

Benefits of tenant management capability

The Amazon SES tenant management feature provides a comprehensive solution for organizations managing email sending at scale on behalf of their customers or LOBs (called tenants). This capability is particularly valuable for software as a service (SaaS) providers, email service providers, and enterprises managing email operations across multiple clients or departments while separating tenants from each other.

Through tenant management, organizations can effectively manage email streams and reputation independently and maintain oversight of their various email operations. This new functionality transforms how organizations use Amazon SES, enabling them to handle complex, multi-faceted email operations with greater control and visibility at the tenant level with the following key capabilities.

  • Isolate tenant resources and reputation: Tenant management provides dedicated resource isolation that protects your email reputation across different customers and lines of business. Each tenant (customers or LOBs) will have their own dedicated set of resources such as email sending IPs, domain, and identifiers in DomainKeys Identified Mail (DKIM) signed headers, which are observed by mailbox providers within your Amazon SES account. Tenant management delivers granular control over resource allocation. You can assign tenant-specific or shared sending identities based on your organizational requirements. Each tenant can receive dedicated SMTP or API credentials that provide secure access to their allocated resources. You can configure tenant-level IP pools that separate sending traffic and maintain distinct reputation profiles for each tenant. You can use tenant management to manage tenant-specific configuration sets that define how emails are processed and tracked for each tenant. You can associate email templates with specific tenants, confirms that branded communications remain properly segmented and controlled. This isolation helps ensure that one tenant’s actions cannot affect the reputation or performance of other tenants. When a tenant experiences delivery issues or reputation problems, these challenges remain contained within their dedicated resources. This approach maintains fairness across all tenants and establishes clear individual accountability for email practices.
  • Monitor tenant-specific metrics in real time: You can access specific reputation metrics for each tenant, including raw bounce rates and complaint rates that directly impact sender reputation. You can use this system to set up tenant-level event destinations though the respective configuration set mapped to the tenant for detailed tracking and analysis. With this, you gain access to detailed tenant-level events that track performance, engagement, and compliance metrics for each tenant individually. You can also establish automated enforcement policies based on configurable thresholds that align with your business requirements. When tenant reputation findings are detected or when tenant status changes occur, you can receive real-time alerts through Amazon EventBridge.
  • Scale to hundreds of thousands of tenants: The system is designed to handle massive scale (starting at 10 thousand tenants per account and can increase to as many as 300 thousand tenants), allowing you to grow your business or expand your email operations without worrying about infrastructure limitations. Whether you’re managing dozens or hundreds of thousands of tenants, the system will adapt to your needs.
  • Automate tenant management workflows: You can set up automated processes for onboarding new tenants, applying policies, and managing tenant lifecycles. With this system, you can use API and console interfaces to create, modify, and delete tenants and have the flexibility to pause or resume sending capabilities as required. This automation reduces manual overhead for consistent application of your email sending standards across all tenants.
  • Take targeted enforcement actions to maintain high deliverability: If issues arise with a specific tenant, you can take precise actions—such as suspending sending privileges or applying stricter reputation policies—without affecting other tenants. This capability helps maintain overall high deliverability rates for your entire operation.

These features collectively represent an advancement in email management capabilities, so organizations can offer more sophisticated, scalable, and reliable email services to their clients or internal departments while maintaining strict control over reputation and compliance.

How tenant management works

You can use the tenant management feature from Amazon SES to segment your email sending operations effectively. You can use the system to create multiple tenants within a single Amazon SES account, with each tenant having its own dedicated resources. These resources include essential components such as sending identities, SMTP credentials, configuration sets, and dedicated IP pools. What makes this architecture particularly flexible is the ability to share common resources across tenants, such as IP pools and configuration sets, enabling optimal resource utilization while maintaining operational separation. The following diagram illustrates the preceding information in detail.

Prerequisites

To get started with tenant management, you need:

  • An AWS account
  • Verified sending identities within Amazon SES (domains or email addresses)
  • Configuration sets for email settings
  • A clear understanding of your tenant structure based on your business requirements

How to set up tenant management and its key considerations

Setting up a multi-tenant system in Amazon SES requires careful configuration of three key components: IP pools, domain verification, and configuration sets. By following the set-up procedure, each tenant will have isolated resources, proper tracking, and monitoring capabilities. Using the AWS Management Console for Amazon SES or the Amazon SES APIs, you can create a robust email sending infrastructure that maintains high deliverability while keeping each tenant’s reputation separate.

IP pool configuration

IP pool configuration is a fundamental step to send email communications using Amazon SES. Begin your multi-tenant setup by establishing dedicated IP pools or managed IP pools for each customer though a configuration set. First, access the Amazon SES console and navigate to the Dedicated IP pools section. Create a new Standard dedicated IP pool, giving it a name that clearly identifies the customer. Through AWS Support, request the specific number of IP addresses needed based on your customer’s sending volume—typically one IP per 50,000 daily emails. After the IPs are provisioned, assign them to the appropriate pool. Then, map the IP pool with the configuration set mapped to the tenant. For IP warm-up, you have two options: enable the automatic warm-up schedule, which gradually increases sending volume over 45 days, or disable it to implement your own custom warm-up plan. Monitor the warm-up progress closely to help ensure optimal delivery rates.

Domain verification process

After setting up the IP pool, proceed with domain verification to establish your customer’s sending identity. Navigate to the “verified Identities” (verified identities are the domains or email ids those you have already whitelisted with Amazon SES) section in the Amazon SES console and create a new domain identity using your customer’s domain name. Amazon SES will provide DKIM records that need to be added to the domain’s DNS settings. Work with your customer to implement these records correctly in their DNS configuration. The verification process typically takes 24–72 hours to complete. During this time, regularly check the verification status in the Amazon SES console to make sure the process completes successfully.

Authentication and authorization for tenants

In addition to restricting email sending to specific identities and configurations, you can restrict email sending permissions by tenant using AWS Identity and Access Management (IAM) user or role policies. The following policy demonstrates these restrictions by allowing emails only when the tenant Amazon Resource Name (ARN) is arn:aws:ses:us-east-1:111122223333:tenant/testTenant1/tn-e08a68010000a3e4c67bcd990910, the identity is arn:aws:ses:us-east-1:111122223333:identity/example.com and the configuration-set is arn:aws:ses:us-east-1:111122223333:configuration-set/testTenant1.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": "ses:SendRawEmail",
      "Resource": [
        "arn:aws:ses:us-east-1:111122223333:identity/example.com",
        "arn:aws:ses:us-east-1:111122223333:configuration-set/TestTenant1"
      ],
  "Condition": 
{ "StringEquals": 
{ "ses:TenantName": "testTenant1" }
}
    }
  ]
}

Set up a configuration set

The final step involves creating and configuring the configuration set, which manages tracking and monitoring. Start by creating a new configuration set under configuration set section in the Amazon SES console, naming it to match your customer’s identification. Configure the custom tracking domain and enable appropriate tracking settings for opens and clicks. Link this configuration to the previously created IP pool. Next, set up event destinations to monitor email performance—this can include Amazon CloudWatch metrics, Amazon Data Firehose, or Amazon Simple Notification Service (Amazon SNS) topics. In CloudWatch, create alarms for critical metrics such as bounce rates (recommended threshold: 5%) and complaint rates (recommended threshold: 0.1%). Set up notification systems to alert your team when these thresholds are breached, so you can quickly respond to any delivery issues.

Sample CLI commands

To start using tenant management, you can use the console, AWS Command Line Interface (AWS CLI), or AWS SDKs. The following are basic examples of creating and configuring a tenant using the AWS CLI:

Following states a life cycle of the tenant management procedure starting from creating a tenant to deleting it in case you want to remove the tenant. Make sure that you are using AWS CLI version to 2.28.0 or later. See AWS CLI install and update instructions if necessary.

Create a new tenant

aws sesv2 create-tenant --tenant-name testTenant1 --region us-east-1
Note that “-–region” value is optional

Assign a sending identity to the tenant (domain or email ID)

aws sesv2 create-tenant-resource-association --tenant-name testTenant1 --resource-arn arn:aws:ses:us-east-1:111122223333:identity/example.com

Add a configuration set to the tenant

aws sesv2 create-tenant-resource-association --tenant-name testTenant1 --resource-arn arn:aws:ses:us-east-1:111122223333:configuration-set/test1

The assumption here is that the selected configuration set already has an IP-Pool associated.

Get tenant information through get-tenants or list-tenants

aws sesv2 get-tenant --tenant-name testTenant1 --region us-east-1 

aws sesv2 list-tenants --region us-east-1 <List all the tenants with their ARN>

You can use get-tenant or List-tenants to get information about a specific tenant, including the tenant’s name, ID, ARN, creation timestamp, tags, and sending status or list-tenants to list all tenants associated with your account

List resources of a tenant

aws sesv2 list-tenant-resources --tenant-name testTenant1

Send email using tenant

aws sesv2 send-email --from-email-address "[email protected]" --destination "[email protected] " --configuration-set-name test1   --content '{"Simple":{"Subject":{"Data":"Your email subject","Charset":"UTF-8"},"Body":{"Text":{"Data":"This is the plain text version.","Charset":"UTF-8"},"Html":{"Data":"<html><body><h1>This is the HTML version</h1><p>With formatted content.</p></body></html>","Charset":"UTF-8"}}}}' --tenant-name testTenant1 

To change the reputation policy from standard to strict (Standard policy is applied by default)

aws sesv2 update-reputation-entity-policy --reputation-entity-type RESOURCE --reputation-entity-reference arn:aws:ses:us-east-1: 111122223333:tenant/ testTenant1/tn-145f7885b000074362bfa074ec4e1 --reputation-entity-policy arn:aws:ses:us-east-1:aws:reputation-policy/strict  

Disable sending for a tenant (to temporarily disable or pause a tenant)

aws sesv2 update-reputation-entity-customer-managed-status  —reputation-entity-type RESOURCE —reputation-entity-reference arn:aws:ses:us-east-1:111122223333:tenant/testTenant1/tn-145f7885b000074362bfa074ec4e1 —sending-status DISABLED

Delete the tenant (remove the tenant completely from the Amazon SES account)

aws sesv2 delete-tenant --tenant-name testTenant1

Send emails using SMTP

The X-SES-TENANT header is utilized by AWS to manage emails across multiple tenants. You can specify the tenant name by including it in the X-SES-TENANT field. This approach allows for better organization and routing of emails based on tenant information. To implement this, you can add the X-SES-TENANT header when sending emails using SMTP. The following Python code demonstrates how to include this header in your email sending process::

<Pseudo code>
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def send_email(smtp_server, port, username, password, from_email, to_email, subject, body, config_set=None):
    msg = MIMEMultipart()
    msg['From'] = from_email
    msg['To'] = to_email
    msg['Subject'] = subject
    msg['X-SES-TENANT'] = 'test1'
    if config_set:
        msg['X-SES-CONFIGURATION-SET'] = config_set
    msg.attach(MIMEText(body, 'plain'))

    with smtplib.SMTP(smtp_server, port) as server:
        server.starttls()
        server.login(username, password)
        server.send_message(msg)

# Example usage:
send_email('email-smtp.us-east-1.amazonaws.com', 587, 'YOUR_SMTP_USERNAME', 'YOUR_SMTP_PASSWORD','[email protected]', '[email protected]', 'Test Subject', 'Hello World', 'test1')

Email event feedback loop management for tenants

Receiving email events or using a feedback loop is important to monitor the email sending practices followed by the tenants. Tenant management provides reputation management capabilities for multi-tenant environments, so organizations can maintain granular control over email sending practices across their tenant base. You can automatically monitor and enforce reputation-based policies at the tenant level, so that problematic email sending behavior from one tenant doesn’t impact the deliverability of others. When reputation issues are detected, Amazon SES can automatically pause sending for the affected tenant while allowing other tenants to continue their email operations unimpeded.Organizations can now implement precise enforcement mechanisms through automated reputation findings that provide early detection of potential deliverability issues. Tenant isolation uses machine learning models and signal-based detection to identify problematic patterns in email sending behaviour. When issues are detected, Amazon SES automatically notifies the parent account and can trigger predetermined actions based on customizable thresholds. This granular control helps maintain strong deliverability rates across the entire email sending infrastructure while isolating and addressing issues at the tenant level.

Enforcement data and patterns

Unlike other communication channels that are governed by a patchwork of national laws, bulk email delivery is subject to requirements dictated by a handful of large inbox providers. Google, Yahoo, Microsoft, and several others set deliverability targets, leaving compliance up to the sender or service providers such as Amazon SES. Amazon SES, in turn, expects its direct customers, including multi-tenant providers, to monitor key signals of enforcement. If any of the tenants send rogue emails, Amazon SES expects the AWS customer to monitor key enforcement signals and take appropriate actions such as pausing or stopping the rogue tenants. Signals for enforcement and trust indicators are essential components of our email reputation management system. These signals are various data points and behaviours we monitor to assess the trustworthiness of email senders. Trust indicators, derived from these signals, provide a measure of a sender’s reputation and adherence to best practices. Amazon SES uses a combination of pre-send signals (such as account vetting and configuration) and post-send signals (including delivery success rates, bounce rates, and recipient engagement) to calculate reputation findings. These findings then inform automated enforcement actions and manual reviews, helping to ensure that our service maintains high deliverability standards while protecting recipients from unwanted or malicious emails. By continuously refining our signal analysis and enforcement processes, we strive to create a reliable and secure email ecosystem for all users.

Administrating tenant isolation and reputation management

When managing multiple tenants sending email through your SES account, you’ll want to monitor sending behaviour and reputation. Amazon SES provides a comprehensive monitoring system through reputation findings, which alert you when tenants exhibit concerning sending patterns. These findings appear in your dashboard and are delivered as events through Amazon EventBridge default event bus, letting you know immediately when issues arise.

As an email deferability administrator, your daily monitoring routine needs to include reviewing the tenant management dashboard where you can see all your tenants’ status at a glance. Pay particular attention to any reputation findings, which come in two levels—low and high severity. These findings indicate when tenants exceed acceptable thresholds for metrics like bounce rates or complaint rates. You can configure reputation policies to automatically pause tenant sending when these thresholds are breached, with options for standard enforcement (pausing on high severity findings) or strict enforcement (pausing on low severity findings).

When a tenant is paused, either automatically or manually, you’ll need to investigate the cause. The reputation findings provide detailed information about what triggered the pause, such as elevated bounce rates or complaint rates. After addressing the underlying issues with the tenant, you can reinstate their sending capabilities. During reinstatement, the tenant can continue sending while you monitor their metrics to verify that they return to healthy levels. After their metrics improve, the tenant will automatically transition back to a normal enabled status.

Available metrics and data points

These core reputation metrics are released by Amazon SES and can be routed to EventBridge. The event feedback loop will contain the tenant name and ID to enable tracking of tenant-specific bounce rates

  • Complaint rates per tenant
  • Third-party specific complaint rates
  • Spamhaus IP listing status
  • Email volume pattern

For ongoing management, you have full control over tenant resources and configurations. You can assign or remove sending identities and configuration sets as needed, adjust reputation policies, and manually pause sending if you observe concerning patterns. By using this combination of automated monitoring, clear reputation signals, and flexible management tools, you can maintain control over your tenants while preventing individual tenant issues from affecting your overall account reputation. The key is to stay proactive in monitoring the dashboard and reputation findings, and to act quickly when issues arise.

Conclusion

We’re excited to see how our customers will use the tenant management feature to transform their email operations, boost efficiency, and create better experiences for their users. To get started with tenant isolation simply visit the Amazon SES console or see Tenants in the Amazon SES Developer Guide. You can find details about pricing on the Amazon SES pricing page. We’re committed to improving tenant isolation and management based on your feedback and needs, and we look forward to bringing you even more powerful and flexible email management capabilities in the future. Start exploring multi-tenant management today with Amazon SES.


About the authors

Streamlining outbound emails with Amazon SES Mail Manager

Post Syndicated from Manoj Gaddam original https://aws.amazon.com/blogs/messaging-and-targeting/streamlining-outbound-emails-with-amazon-ses-mail-manager/

In today’s digital landscape, efficient email management is crucial for businesses of all sizes. Amazon Simple Email Service (Amazon SES) has long been a go-to solution for handling transactional and marketing emails. Through Mail Manager, Amazon SES offers powerful tools to enhance your email infrastructure, particularly for outbound email handling and archiving.

In this post, we explore how Mail Manager can modernize your approach to outbound email management. We’ll dive into the various options available for controlling email flows and archiving all outgoing emails. By the end of this article, you’ll have a clear understanding of how you can use Mail Manager to:

  • Strengthen your email infrastructure
  • Simplify outbound email workflow management
  • Help meet compliance through robust email archiving

In this post, we consider a real-world customer use case from a university where students should receive clean emails free from malware and phishing attempts. Amazon SES Mail Manager provides a comprehensive email pipeline that handles security screening, message archival, and reliable delivery. By implementing this system, the university significantly improved its email infrastructure, helping to ensure that important communications reach students safely and efficiently.

Walkthrough

In this walkthrough, we guide you through the process of configuring Amazon SES Mail Manager with the following components:

  • Traffic policy: You’ll create a traffic policy designed to help ensure that students receive only clean, secure emails. The default action is set to Deny all, providing a strict baseline. The policy includes two key statements connected by an OR condition. Policy Statement 1 allows emails if the recipient address is in the Valid-Address list. Policy Statement 2 allows emails that meet all of the following conditions: not listed in Abusix Guardian Mail, recipient address is not in the Invalid-Email-List, and uses TLS protocol version 1.3 or higher. This configuration effectively filters potential threats while allowing legitimate communications to reach students’ inboxes, maintaining a secure email environment for the university.
  • Rule set: You’ll create a rule set containing two rules that execute in sequential order:
    • Rule 1: Scan and isolate malicious content: Scans messages and, if the scan fails, stores emails in an Amazon Simple Storage Service (Amazon S3) bucket for further validation and halts sending email.
    • Rule 2: Archive and send clean emails to recipients: Archives all outgoing emails for audit and compliance after passing the security scan and routes emails to recipients.
  • Ingress endpoint: You’ll create a Mail Manager ingress endpoint that will receive, route, and manage emails based on your configured policies and rules.

After setting up these components, you’ll use sample Python code to send an email through the ingress endpoint. To verify functionality, we’ll check the email archive to confirm that all incoming emails are archived for compliance or audit purposes and confirm email is received in the intended inbox. The workflow is shown in the following figure.

Prerequisites

Before beginning, make sure that you have completed domain verification in your desired AWS Region and moved out of the Amazon SES sandbox. Domain verification is a crucial first step that validates your authority to send emails through SES from your domain. In this tutorial, you’ll use a sample Python program to send emails programmatically through an ingress SMTP endpoint. You can run this program either on your local machine or using AWS CloudShell.

You should have:

Before creating traffic policies and rule sets, you will first set up Email Add Ons, and email archiving, and AWS Identity and Access Management (IAM) roles, which will be needed while creating traffic policies and rules.

Step 1: Enable Email Add Ons for Amazon SES Mail Manager

To implement security features such as malicious content scanning in your email workflow, first enable the necessary Email Add Ons:

  1. Open the AWS Management Console for Amazon SES.
  2. Choose Mail Manager and then Email Add Ons.
  3. Select your desired Add Ons:
    • Trend Micro Virus Scanning
    • Abusix Guardian Mail
    • Spamhaus Domain Block List (DBL)
    • Vade Advanced Email Security
  4. Choose Enable.

Important Notes:

  • Email Add Ons are third-party security products integrated with Mail Manager
  • Once subscribed, you can use them in your traffic policies or rule sets

As part of this post, you will be using the Abusix Guardian Mail and Vade Advanced Email Security Add Ons to enhance email security posture. It doesn’t mean you have to use all of them—you can subscribe to the ones that best fit your requirements based on your use case.

Step 2: Configure an email archive for compliance and retention

You will create an email archive to store outgoing messages to use as part of configuring Rule 2. This archive will serve as a repository for outgoing messages.

  1. Navigate to Mail Manager and then to Email Archiving.
  2. Choose Create archive.
  3. Complete the archive configuration:
    1. Enter a unique name in the Archive name field.
    2. (Optional) Select a retention period to override the default of 180 days.
    3. (Optional) Set up encryption by either entering your own AWS Key Management System (AWS KMS) key in the KMS key ARN field or selecting Create new key.
  4. Choose Create archive.
  5. After being created, this archive will store your emails according to the rules you’ll define in the next step.

Step 3: Create and S3 bucket and IAM role for S3 access

When emails fail the Vade security scan, they need to be stored securely for further investigation. In this step, we’ll create an S3 bucket to store these flagged emails and set up the necessary IAM permissions.

  1. Create an S3 bucket to quarantine suspicious and malicious emails identified by the Vade scanner. This bucket will store these emails for further investigation by the security team. Note the bucket name, because you’ll need it in the next step.
  2. Create an IAM role that allows Mail Manager to upload suspicious emails to an S3 bucket. This IAM role will be used in Rule 1 when configuring the Write to S3 rule action for storing emails that fail the security scan.
    1. Go to the IAM console.
    2. Choose Roles and then choose Create role.
    3. For trusted entity, select Custom trust policy and paste the following (replace "XXXXXXXXXXX" with your AWS account ID).
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Service": "ses.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
              "StringEquals": {
                "aws:SourceAccount": "XXXXXXXXXXX"
              },
              "ArnLike": {
                "aws:SourceArn": "arn:aws:ses:us-east-1:XXXXXXXXXXX:mailmanager-rule-set/*"
              }
            }
          }
        ]
      }

    4. Choose Next and create an inline policy with the following permissions (replace "MyDestinationBucketName" with your S3 bucket name).
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Sid": "AllowPutObject",
            "Effect": "Allow",
            "Action": ["s3:PutObject"],
            "Resource": ["arn:aws:s3:::MyDestinationBucketName/*"]
          },
          {
            "Sid": "AllowListBucket",
            "Effect": "Allow",
            "Action": ["s3:ListBucket"],
            "Resource": ["arn:aws:s3:::MyDestinationBucketName"]
          }
        ]
      }

    5. Enter a name your role and choose Create role.

Step 4: Create and IAM role permission policy for send to internet rule action

Configure an IAM role that permits Mail Manager to send emails to external domains. This role will be referenced in Rule 2 for delivering validated emails to recipients.

  1. You can either:
    1. Use the same IAM role created in Step 3 and add this policy, or
    2. Create a new IAM role and add the following permission policy (Replace example.com with your verified domain, "XXXXXXXXXXX" with your AWS account ID and my-configuration-set with your configuration set name if applicable).

This policy grants the necessary permissions to send emails to recipients on the internet, which will be used in rule 2 of your rule set.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ses:SendEmail", "ses:SendRawEmail"],
      "Resource": [
        "arn:aws:ses:us-east-1:XXXXXXXXXXX:identity/",
        "arn:aws:ses:us-east-1:XXXXXXXXXXX:configuration-set/"
      ]
    }
  ]
}
  1. If adding to an existing role:
    • Go to the IAM console and select your role
    • Choose Add permissions and then select Create inline policy.
    • Paste the preceding JSON and choose Review policy.
    • Enter a name for the policy and choose Create policy.
  2. If you create a new role, name it appropriately and choose Create role.

Step 5: Create a traffic policy

Traffic policies serve as security checkpoints for your email infrastructure, controlling which messages can enter your system based on defined security rules. To create a traffic policy that enforces security requirements for your emails:

  1. Open the Amazon SES console.
  2.  Go to Mail Manager and choose Traffic policies.
  3.  Choose Create traffic policy.
  4. Enter a unique name for your policy.
  5. Set Default action to Allow (this handles emails that don’t match any specific rules).
  6. Add policy statements by choosing Add new policy statement:
    1. Choose Deny for emails that don’t meet security requirements.
    2. Add condition: TLS Protocol Version select Less than and then select 1.2.
    3. Add conditions for any Email Add-Ons you’ve subscribed to, such as Spamhaus, Abusix, and so on.)
  7.  Choose Create traffic policy.

Traffic policies are evaluated in a specific sequence:

  1. First, all Deny policy statements are evaluated in order. If any match, the email is immediately blocked and no further evaluation occurs.
  2. If no Deny statements match, all Allow policy statements are evaluated in order. Multiple statements within a policy are connected by OR logic. If any statement matches, the email is allowed.
  3. Within each individual policy statement, multiple conditions are connected by AND logic. All conditions must be true for the statement to match.
  4. If no policy statements match (neither Deny nor Allow), the default action of the traffic policy (either Allow or Deny) is applied.

In this step, you’ll establish a robust policy that enforces strict TLS security protocols while harnessing the power of specialized email security add-ons such as Abusix Guardian Mail to preemptively identify and block potentially harmful messages before they can penetrate your system. In this traffic policy configuration, you’ll create two policy statements that work together to provide security and flexibility:

Default policy statement:

  • Deny-by-default where all email traffic is initially blocked unless explicitly allowed by below policy statements

Policy statement 1:

  • Allows emails if the recipient address is in a list called Valid-Address

Policy statement 2 (with three conditions connected by AND):

  • Must NOT be listed in Abusix Guardian Mail (FALSE condition)
  • The recipient address must NOT be in the Invalid-Email-List
  • The TLS protocol version must be at least TLS 1.3

In basic terms, this policy will allow emails that either:

  • Have recipients from an approved address list, or
  • Meet all three security conditions (not deny-listed, not on the invalid list, and using secure TLS 1.3)

Step 6: Create a rule set

Rule sets define how your emails are processed after they pass through your traffic policy. In this example, the rule set establishes a sequential email processing workflow. First, you will perform email scanning (marking and segregating spam emails while allowing clean ones to proceed) and archiving outgoing messages, then finally delivering clean messages to recipients. To create a rule set:

  1. Open the Amazon SES console.
  2. Go to Mail Manager and choose Rule sets.
  3. Choose Create rule set.
  4. Enter a unique name for your rule set.
  5. On the rule set’s overview page, choose Edit, then choose Create new rule

Step 7: Create rules

After creating your rule set, you’ll need to add rules that define how your emails are processed. Follow these steps to create and configure your rules:

  1. On the rule set’s overview page, choose Edit, then Create new rule.
  2. In the Rule details sidebar, enter a unique name for your rule.
  3. Add conditions or exceptions as needed:
    1. Select Add new condition to specify what messages the rule applies to.
    2. Select EXCEPT in the case of and select Add new exception for exclusions.
  4. Configure actions by choosing Add new action.
    1. For multiple actions, use the up and down arrows to set the execution order.
  5. When finished creating your rules, choose Save rule set to apply your changes.

Rule 1: Scan and isolate malicious content

This rule targets emails flagged by Vade Advanced Email Security as potentially harmful. It applies to messages identified as scams, suspect content, phishing attempts, or containing malware. When a message is flagged as malicious, the rule marks it with a custom header, stores a copy in Amazon S3 for investigation, and prevents it from reaching recipients. An exception allows emails with Action required in the subject line to bypass this security check.

Use the following settings to create and configure Rule 1:

  • Rule name: Scan and isolate
  • Conditions:
    • Property: Select Verdict (Vade Advanced Email Security).
    • Operator: Select Equals.
    • Value: Select scam, suspect, phishing, and malware.
  • Actions:
    • Add header: For Key, enter X-vedacheck and for Value, enter failed.
    • Write to S3: Enter the name of an S3 bucket to store the message for investigation.
    • Drop: Stop processing the message.

Rule 2: Archive and send clean emails to recipients

This final rule processes messages that have successfully passed through the previous security checks. With no additional conditions, it forwards clean emails to their intended recipients, completing the secure email delivery workflow for the university’s communication system. Use the following settings to create and configure Rule 2:

  • Rule name: SendEmail
  • Action:
    • Add header: For Key , enter Add X-vedacheck with a Value of Approved.
    • Archive resource name: Select your Mail Manager archive (Email_Archive)
    • Send to internet: Send email to intended recipient.

The workflow makes sure that:

  • All outbound emails are securely archived
  • Each email undergoes scanning
  • Scan results are documented in email headers
  • Clean emails are delivered to their intended recipients

Step 8 : Store password in AWS Secrets Manager for the ingress endpoint

Before creating an ingress endpoint, you need to set up a password in AWS Secrets Manager:

  1. Go to the AWS Secrets Manager console and choose Store a new secret.
  2. Select Other type of secret.
  3. Enter password as the key and your desired password as the value.
  4. For Encryption key: Use a custom KMS key (not AWS managed keys).
    1. KMS customer managed key (CMK) key policy for ingress endpoint. Replace XXXXXXXXXXX with your AWS account ID.
{
    "Effect": "Allow",
    "Principal": {
        "Service": "ses.amazonaws.com"
    },
    "Action": "kms:Decrypt",
    "Resource": "*",
    "Condition": {
        "StringEquals": {
           "kms:ViaService": "secretsmanager.us-east-1.amazonaws.com",
            "aws:SourceAccount": "XXXXXXXXXXX"
        },
        "ArnLike": {
            "aws:SourceArn": "arn:aws:ses:us-east-1:XXXXXXXXXXX:mailmanager-ingress-point/*"
        }
    }
}
  1. Choose Next to proceed
  2. Enter a secret name and choose Edit permissions and update the resource policy. Replace XXXXXXXXXXX with your AWS account ID.
{
    "Version": "2012-10-17",
    "Id": "Id",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "XXXXXXXXXXX"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:ses:us-east-1:XXXXXXXXXXX:mailmanager-ingress-point/*"
                }
            }
        }
    ]
}
  1. Choose Next and create your secret

For step-by-step guidance, see the Developer guide for Ingress endpoints.

Step 9: Create an authenticated ingress endpoint

Now that you’ve created your traffic policy, rule set, and stored your credentials, you can create the ingress endpoint:

  1. In the Amazon SES console, choose Mail Manager and then choose Ingress endpoints.
  2. Choose Create ingress endpoint.
  3. Configure your endpoint:
    1. Select the Traffic policy you created earlier.
    2. Select the Rule set you created earlier.
    3. Enter a unique name for your endpoint.
    4. For authentication, select the Secret ARN you created in Secrets Manager.
  4. Choose Create ingress endpoint.

After your ingress endpoint is created, note down the following details from the General details section:

  • Amazon Resource Name (ARN): arn:aws:ses:us-east-1:XXXXXXXXXXX:mailmanager-ingress-point/inp-XXXXXXXXXXXX
  • Username: inp-XXXXXXXXXXXX
  • Host: XXXXXXXXX.fips.wmjb.mail-manager-smtp.amazonaws.com (ARecord)

You’ll need these details when configuring your email client or application to send emails through this endpoint.

Step 10: Send email using an ingress endpoint

The following Python sample code can be executed from your local machine with the appropriate AWS credentials, but for this post you’ll run the script from the AWS CloudShell terminal from within the Amazon SES console. When running the sample Python code, the email will pass through an ingress endpoint and, if all policies are met, the email will be sent to the recipient’s email address.

Running the Python script in CloudShell

  1. Sign in to the console and open CloudShell.
  2. Create the script file and paste the following Python code into the editor.
nano send_email.py
  1. Paste the following Python code:
import smtplib, boto3, json, logging
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from botocore.exceptions import ClientError

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def get_secret(secret_name, region_name="us-east-1"):
    """Retrieve secret from AWS Secrets Manager"""
    try:
        secrets_client = boto3.session.Session().client('secretsmanager', region_name=region_name)
        logger.info(f"Connecting to AWS Secrets Manager in region {region_name}")
        response = secrets_client.get_secret_value(SecretId=secret_name)
        
        if 'SecretString' in response:
            logger.info("Successfully retrieved credentials from Secrets Manager")
            return json.loads(response['SecretString'])
        else:
            logger.error("No SecretString found in the response")
            raise ValueError("No SecretString found in the response")
    except Exception as e:
        logger.error(f"Error retrieving secret: {str(e)}")
        raise

def send_email(region_name="us-east-1"):
    try:
        # Fetch SMTP credentials from Secrets Manager
        smtp_secrets = get_secret('SES_Ingress_Endpoint_Credentials', region_name)
        
        # SMTP Configuration
        INGRESS_SERVER = 'XXXXXXXXXXX.fips.wmjb.mail-manager-smtp.amazonaws.com'
        INGRESS_PORT = 587
        INGRESS_USERNAME = 'inp-XXXXXXXXXXX'
        INGRESS_PASSWORD = smtp_secrets.get('password')
        
        # Email details
        sender = '[email protected]'
        recipient = '[email protected]'
        subject = 'Sent via SES Mail Manager'
        body = "Successfully passed through SES Mail Manager and Email Archived successfully"
        
        # Create message
        msg = MIMEMultipart()
        msg['From'], msg['To'], msg['Subject'] = sender, recipient, subject
        msg.attach(MIMEText(body, 'plain'))
        
        # Send email
        logger.info(f"Connecting to SMTP server {INGRESS_SERVER}:{INGRESS_PORT}...")
        with smtplib.SMTP(INGRESS_SERVER, INGRESS_PORT) as mail:
            mail.ehlo()
            mail.starttls()
            mail.login(INGRESS_USERNAME, INGRESS_PASSWORD)
            mail.send_message(msg)
            logger.info(f"Email successfully sent to {recipient}")
        
        return {'statusCode': 200, 'message': 'Email sent successfully'}
            
    except Exception as e:
        error_msg = f"Error: {str(e)}"
        logger.error(error_msg)
        return {'statusCode': 500, 'message': error_msg}

if __name__ == "__main__":
    result = send_email("us-east-1")
    print(json.dumps(result, indent=2))
  1. Replace all placeholders
    1. INGRESS_SERVER = XXXXXXXXXXX.fips.wmjb.mail-manager-smtp.amazonaws.com is your ingress endpoint hostname.
    2. INGRESS_PORT = Supported ports: 25, 587
    3. INGRESS_USERNAME = inp-XXXXXXXXXXXX is your ingress endpoint username.
    4. Recipient and sender= [email protected] is your verified sender and recipient email addresses.
  2. Save the file.
  3. Run the script:
python3 send_email.py
  1. Verify the results:
    1. Check the recipient’s inbox for the email.
    2. Check the Mail Manager archive to confirm the message was archived.

To search the Mail Manager archive for the specific message sent by the Python script:

  1. Navigate to the Amazon SES console and choose Mail Manager.
  2. Under Email Archiving, choose the Search archive tab.
  3. Under Archive, select the archive you created and choose Search. This should return all the emails you have sent.

Clean up

Clean up your AWS environment by removing all resources created during this walkthrough, including Mail Manager configurations, S3 buckets, secrets, and any associated Lambda functions.

Conclusion

In this post, we’ve demonstrated the implementation of sophisticated traffic policies, multi-layered rule systems, and automated archiving capabilities—all seamlessly integrated into a scalable architecture. The ability of Amazon SES Mail Manager to enforce TLS requirements, conduct email scanning, and maintain searchable archives while providing programmatic access through ingress endpoints makes it an invaluable tool for organizations seeking to modernize their email infrastructure.As businesses continue to rely heavily on email communication, Amazon SES Mail Manager emerges as a powerful ally, helping organizations navigate the complexities of modern digital correspondence while ensuring rock-solid security, seamless compliance, and optimal efficiency.

References:


About the authors

AT&T email-to-text service migration: AWS solution implementation

Post Syndicated from Vinay Ujjini original https://aws.amazon.com/blogs/messaging-and-targeting/att-email-to-text-service-migration-aws-solution-implementation/

Email-to-text services allow businesses to send short message service (SMS) messages through email, critical for automatic notifications, customer service, and operational workflows. These services process over 1.2 billion messages annually across U.S. carriers, with AT&T supporting 34% of this volume through 2024. AT&T’s deprecation of email-to-text and text-to-email services impacts businesses that rely on these communication channels. This blog post outlines an Amazon Web Services (AWS) solution to maintain service continuity for customers.

AT&T discontinued their email-to-text and text-to-email services in Q2 2025, which will impact about 23,000 business customers. Organizations rely on these communication channels for critical workflows and need a quick solution to maintain business continuity. By the numbers:

  • Average message volume: 50,000 texts per customer monthly
  • Critical use cases: Appointment reminders, security alerts, and system notifications
  • Regulatory requirements mandate message retention and delivery confirmation

Solution architecture

The following diagram shows the architecture for the solution:

Email-to-SMS architecture flow:

  1. An email is sent to [phone-number]@[your-domain.com]
  2. Amazon Simple Email Service (Amazon SES) routes emails to the Mail Manager ingress endpoint
  3. The email is written to an Amazon Simple Storage Service (Amazon S3) bucket
  4. An Amazon S3 event notification triggers an AWS Lambda function
  5. Lambda extracts the email content, formats the phone number, and sends an SMS message using AWS End User Messaging
  6. Message details are stored in DynamoDB for tracking

System components in this solution:

  • Processing: Mail Manager applies rules to incoming emails
  • Storage: Amazon S3 stores emails securely
  • Computation: Lambda processes stored emails
  • Identification: Amazon DynamoDB lookup matches the sender email to phone number
  • Delivery: AWS End User Messaging User Messaging sends an SMS message to the recipient

This architecture, which uses simple notification service (SNS), is suitable for SMS-to-email. While this post and the AWS CloudFormation template primarily focus on email-to-SMS implementation, the SMS-to-email flow works as follows:

SMS-to-email flow:

  1. A user replies to an SMS message
  2. AWS End User Messaging SMS service captures the message and publishes it to an SNS topic
  3. SNS triggers a Lambda function
  4. Lambda formats the message and sends an email through Amazon SES
  5. The email is delivered to the original sender

The solution

The solution was to build an email-to-text service using AWS core services. The architecture routes emails through an Amazon SES Mail Manager ingress endpoint. After receiving an email, Mail Manager processes it using defined business rules and stores it in Amazon S3. This triggers a Lambda function to fetch the phone number associated with the email address and send an SMS to that phone number. When successful, it stores data such as the email address, phone number, and message ID from the sent text message in DynamoDB.

Estimated setup time: 15–20 minutes

Prerequisites

To deploy the solution described in this post, you must have the following in place:

Step 1: Set up Amazon SES Verified Identity

Start by setting up an Amazon SES verified identity.

  1. Sign in to the AWS Management Console.
  2. Navigate to Amazon SES service.
  3. In the navigation pane, go to Configuration and choose Identities (skip this step if you have a verified identity).
  4. If you do not have a verified identity, choose e.
  5. Review this post to learn how to verify an identity. Best practice is to verify a domain identity. This will authenticate your domain and improve deliverability. An email address identity, while simpler, won’t be authenticated through DomainKeys Identified Mail (DKIM), which might decrease deliverability.

Reference: Creating and verifying identities in Amazon SES

  1. Confirm that the status of your domain identity is Verified before proceeding to the next step.

Step 2: Deploy the email-to-SMS CloudFormation template

Use the following steps to create a CloudFormation stack that deploys all the required components for email-to-SMS functionality:

  1. Sign in to your AWS account.
  2. Download the email-to-sms.yaml CloudFormation template file.
  3. Navigate to the CloudFormation console.
  4. Choose Create stack and select With new resources (standard).
  5. Prerequisite: Prepare template is selected as Choose an existing template.
  6. Under Specify template, choose Upload a template file and  upload the email-to-sms.yaml file you downloaded earlier. Choose Next.
  7. For Stack name, enter Email-To-SMS-Stack.
  8. Configure the following parameters:
    • e: Enter the SES verified domain name or a verified email address.
    • OriginationPhoneNumberId: Enter the AWS End User Messaging SMS phone number ID that you plan to use to send SMS messages.
      • Go to AWS End User Messaging, under Phone Numbers, select your number and find Phone number ID.
    • DestinationPhoneNumber: Enter the destination phone number to receive SMS messages.
  9. Choose Next.
  10. (Optional) Add tags to help identify and organize your AWS resources.
  11. Select Acknowledge All checkbox and choose Next.
  12. Review the configuration and choose Submit.
  13. Wait for the stack creation to complete. You can monitor the progress in the CloudFormation console

Step 3: Verify deployed stack services

After successful CloudFormation template deployment, verify the following resources and configurations:

  1. A DynamoDB table is created with the name <stackname>-email-to-sms-db
  2. A Lambda function is created with the name <stackname>-<accountnumber>-<awsregion>-process-email-to-sms
  3. The Lambda function has the following AWS Identity and Access Management (IAM)role policies attached:
    1. s3:GetObject
    2. dynamodb:PutItem
    3. sms-voice:SendTextMessage
    4. kms:Decrypt for Lambda encryption keys.
    5. IAM permissions for dead letter queue (if configured).
  4. S3 buckets are created:
    1. Main bucket: <stackname>-<accountnumber>-<awsregion>-emailtosms-storage
    2. Logging bucket: <stackname>-<accountnumber>-<awsregion>-emailtosms-logging
  5. In Amazon SES:
    1. A receipt rule set is created named <stackname>-EmailToSms-Rule-Set
    2. The receipt rule is configured to:
      1. Write messages in the S3 bucket.
      2. Invoke the Lambda function.
    3. Traffic policy is created named <stackname>-EmailToSms-Traffic-Policy
    4. The Rule set and traffic policy are configured in the ingress point <stackname>-EmailToSms-Ingress-Point
      • CAUTION: Testing this solution requires access to modify mail exchange (MX) DNS records for your domain.
      • Potential impact: Changes to MX records can interrupt email delivery to your primary domain.
      • Best practice: We strongly recommend creating a dedicated subdomain (such as testing.example.com) rather than using your primary domain (example.com) for testing purposes. This approach prevents disruption to your organization’s regular email service

Additional verifications:

  • Verify that the S3 bucket policies are correctly set
  • Verify that S3 bucket logging is on and working
  • Check the Lambda function’s environment variables
  • Monitor Amazon CloudWatch logs for any errors

Step 4: Test the email-to-SMS flow

  1. Send an email to mobile-number@verified-domain
  2. You will receive an SMS from the source number (AWS End User Messaging phone number) containing:
    • Subject: <EmailSubject>
    • Content: First 160 characters of your email body
  3. SMS character Limitations:
    1. AWS End User Messaging’s SMS messaging has character limits based on content type
    2. By default, the solution uses first 160 characters
    3. You can modify this limit by updating the Lambda function code
  4. Troubleshooting:
    1. If SMS or email responses aren’t received
    2. Check Lambda function logs in CloudWatch
    3. Review any error messages or execution issues
    4. Verify all permissions and configurations are correct

Make sure that your domain and phone numbers are properly verified before testing. If you don’t receive the email or SMS, check the Lambda CloudWatch logs for troubleshooting

Clean up

To avoid ongoing charges and remove all deployed resources, perform the following cleanup steps:

  1. Remove the CloudFormation stack:
    1. Navigate to the CloudFormation console
    2. Delete the Email-To-SMS stack
    3. Wait for complete stack deletion confirmation
  2. Amazon SES cleanup:
    1. Navigate to the Amazon SES console
    2. Remove any verified domains
    3. Delete verified email addresses
    4. Confirm all SES resources are removed
  3. AWS End User Messaging:
    1. Navigate to the AWS End User Messaging console
    2. Release all provisioned phone numbers
    3. Verify that no active phone numbers remain
  4. Additional verification:
    1. Confirm that S3 buckets are deleted
    2. Verify that Lambda functions are removed
    3. Check that DynamoDB tables are deleted
    4. Make sure that all associated IAM roles and policies are removed

Verify complete resource removal to prevent unexpected charges.

Additional recommendations

  • Security best practices:
    • Set up S3 bucket logging to track access and changes
    • Make sure that S3 buckets have:
      • No public read/write access
      • Enable Encryption at rest
      • Apply appropriate bucket policies
    • Implement least privilege access for IAM roles
    • Use KMS encryption for sensitive data
    • Add CloudWatch logging for monitoring
    • Protect against SMS pumping:
      • Enable AWS End User Messaging protect configuration: Enable filter mode to automatically block suspicious messages
      • Block countries that you don’t do business in to prevent unnecessary exposure
      • Add CAPTCHA to web forms that trigger SMS to prevent bot attacks
      • Set up SMS volume alerts to quickly detect unusual activity
      • Create separate configurations for different message types (password resets compared to marketing)
  • Cost and operational considerations:

Results

This implementation delivers three key improvements:

  1. This achieves 99.99% uptime through AWS managed services.
  2. The pay-per-use model reduces operating costs by 45% compared to maintaining dedicated infrastructure. Customers save an average of $2.30 per thousand messages.
  3. End-to-end encryption and AWS security protocols maintain GDPR and CCPA compliance while protecting customer data.

Conclusion

This AWS-based solution addresses the immediate need and provides a foundation for future enhancements in cross-platform messaging. Whether you’re migrating from AT&T’s email-to-text service or building a new notification system, this AWS-based solution provides a scalable foundation for your messaging needs.


About the author

Guide to IP and domain warming and migrating to Amazon SES

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/guide-to-ip-and-domain-warming-and-migrating-to-amazon-ses/

Transitioning your email workloads from another email service provider (ESP) to Amazon Simple Email Service (Amazon SES) can be a challenge, given that each workload can be unique. In this post, we show you how to successfully warm up IP addresses and domains when migrating to Amazon SES. This guide aims to provide a comprehensive overview of IP and domain warming best practices so you can make your transition to Amazon SES as smooth as possible. We discuss some of the challenges you might encounter and how to overcome those common pitfalls when transitioning to a new email service provider (ESP).

Understanding IP and domain email warming

IP warming and domain warming are strategic processes designed to gradually introduce a new sending identity to mailbox providers. A new sending identity can be a dedicated IP address, new domain, a subdomain of that domain, or any combination of them. The core objective of warming is to build a positive reputation with mailbox providers so your emails are delivered to the inbox rather than being filtered into spam folders or potentially blocked from being delivered to a mailbox altogether.

Mailbox providers such as Gmail, Yahoo, and Outlook are vigilant about protecting their users from spam and malicious content. When you introduce a new sending identity, mailbox providers evaluate the new sending identity with caution. They evaluate the early sending from the domain and IPs to ensure they’re sending the mailbox provider’s users messages that are wanted and aren’t engaged in abusive practices such as spam or phishing. Warming provides mailbox providers the opportunity to observe your sending patterns, content, and engagement metrics, allowing them to gradually build trust in your new sending identity.

Warming can be different for each scenario. For example, you can have completely warmed IPs, but if your sending domain is new, you’ll likely have to warm it up as well but you won’t need to worry about IP warming as much. Another common scenario is that of adding a new IP but sending with an established domain. In this case, the IP will need warming, but the domain itself is helping the warming because it already has an established reputation. When you have a net new IP and a net new domain, you’ll have to warm them together. The warm-up best practices we outline in this post, such as starting out slow and targeting your highest engaged subscribers first, apply to your situation.

Why warming is critical

Warming is essential for several reasons, each contributing to the overall success and reliability of your email marketing campaigns:

  1. Building trust with mailbox providers – A positive sender reputation is crucial for email deliverability. Mailbox providers use complex algorithms to evaluate the reputation of senders, and warming helps them build trust in your new sending identity.
  2. Avoiding initial deliverability issues – When you switch to a new ESP or introduce a new sending identity, it’s common to experience an initial dip in deliverability metrics, such as lower open rates, click-through rates, or higher bounce rates. Warming can mitigate these issues by giving mailbox providers time to adapt to your new sending patterns, whether that is a new domain, subdomain, or new IP infrastructure.
  3. Maintaining consistent sending behavior – Warming encourages you to maintain a steady and predictable sending cadence. Sudden, significant changes in sending volume, content, or frequency can trigger inbox spam filters because such changes might indicate that the sender has been compromised or is engaging in abusive practices. Even anomalies such as large changes in volume or throughput during seasonal events such as Black Friday can be interpreted as negative, and mailbox providers take a cautious approach when they detect anomalies such as sudden large spikes in volume.
  4. Long-term deliverability success – It’s a misconception that warming is done only one time. In reality you need to maintain traffic volumes and sending cadences to keep those sending identities warm. Additionally, if you plan on increasing volume considerably, for example from 1M to 5M or 5M to 25M, you need to warm up to those volumes. Those large jumps in volumes look suspicious to inbox providers even if you’ve been sending consistently.
  5. Adapting to mailbox provider changes – Mailbox providers also continuously update their algorithms to better detect spam and abusive behavior. If you view warming as a constant process and consistently monitor your deliverability and engagement signals you can make adjustments to your sending strategy as needed, ensuring that your emails continue to reach the inbox, even as inbox and audience behavior changes.

Common challenges to moving traffic and warming up on a new ESP

Transitioning your email traffic to a new ESP can present unique challenges that require careful consideration and strategic planning to overcome. These challenges include the following:

  1. Event-driven traffic – If all your email is event-driven, it’s hard to control volume and throughput.
  2. Multiple sending domains – Having many sending domains with varying traffic volumes and throughputs can complicate the transition.
  3. No shared IPs – Some organizations aren’t allowed to use shared pools of IPs.
  4. Lack of engagement data – Absence of data related to engagement can make it difficult to optimize the warming process.
  5. Outdated bounce and unsubscribe info – Not having up-to-date bounce and unsubscribe information in your current ESP can lead to deliverability issues.
  6. Single second-level domain – You’re currently sending your mail from your second-level domain, such as example.com, without separate subdomains for logical use cases such as transactional or marketing.
  7. Tight timelines – Contracts ending or other reasons might impose a tight timeline for the transition.
  8. Challenges for independent service providers (ISVs) and software-as-a-service (SaaS) providers – These organizations often don’t have complete control over the volume, content, lists, or sending consistency of their customers. They also might not have direct access to the DNS needed to update and align sending domains and authentication.

Strategies for a successful warm-up and migration

The following list isn’t suitable for every case, and many customers will use more than one strategy to address their challenges and smooth their transition to Amazon SES:

  1. Send to your best audience first – The most important thing you need to do when transitioning to a new ESP is to send to your highest and most active recipients on the new ESP and leave the less active or risky segments on the previous ESP until you’re ready to full switch. For example, if you’re a daily sender who sends to 1M addresses a day and have an open rate of about 20%, you need to start onboarding with segments that include those who are opening. A good strategy is to start with openers from the last 30 days, then move to openers from 31–90 days, and so on.
  2. Gradually shift traffic – Gradually move your less engaged subscribers to the new ESP while continuing to send in your current ESP and compare performance metrics between the two providers. After you’ve transitioned your most active segments, you can start to include the less engaged a little at a time. Make sure to continue monitoring for issues and immediately stop increasing your workloads if you encounter deliverability issues such as increased bounce or spam rates.
  3. Start with predictable workloads – Begin with workloads that aren’t time-dependent, such as newsletters, which are easier to control and monitor.
  4. Batch event-driven messages – For event-driven messages that aren’t time-sensitive, try to batch and spread them out to manage the volume.
  5. Use automated warm-up processesStandard and managed dedicated IPs can help to manage the daily volume by allowing predefined levels of traffic on your dedicated IPs and spilling over into shared IP pools when the volume of email has reached a level we deem to be sufficient for your dedicated IPs. This is dependent on your warm-up progress thus far. Dedicated standard is a static 45-day increase, but managed dedicated has a more sophisticated process. To learn more, refer to Dedicated IP addresses for Amazon SES.
  6. Strategically use shared IP pools – Use shared IP pools for workloads that don’t require dedicated IPs. Because there is consistent volume already going through these IPs, they’re a little more forgiving than dedicated IPs being warmed up.
  7. Transition gradually to dedicated IPs – Begin with shared IPs and gradually transition to dedicated IPs as they warm up.
  8. Transition gradually to logical subdomains – Split your traffic into logical workloads that can have consistent volume and throughput. Even something as simple as marketing.example.com and transactional.example.com is better than sending mail from example.com
  9. Onboard new customers on the new ESP – For ISVs and SaaS providers, consider onboarding new customers directly on the new ESP to gather initial data and test the waters. New customers already need to be warmed up, so if you warm them up on Amazon SES rather than your legacy ESP, you don’t need to go through a warming process twice.

Prepare to migrate email traffic to Amazon SES

Before you migrate your email program to Amazon SES, it’s important to thoroughly document and organize your existing setup. This preparatory work will lay the foundation for a successful warm-up and migration process. For best practices, include the following tasks:

  1. Document your use cases – Categorize your use cases as either marketing or transactional. This will help you understand the nature of the emails you send and how they should be handled.
  2. Document your sending domains – Include the “from” names associated with each domain. This will assist in mapping the appropriate domain to the corresponding email type. Ideally, you should avoid sending from your root domain. For example, use a subdomain such as email.brand.com instead of brand.com. Review and document your authentication (for example, SPF, DKIM, or DMARC). In some cases, you might not need to align all of them, but you’ll definitely need to align DMARC as part of the bulk sender requirements.
  3. Map use cases to sending domains and from names – Create a clear correspondence to ensure the right emails are sent from the appropriate domains. At a minimum, it’s a best practice to have separate subdomains for transactional and promotional email use cases, such as transactional.brand.com and promo.brand.com.
  4. Document volume and max throughput – Capture this information for each use case mapped to your sending domains. This will help you understand the scale of your email operations and plan your architecture and warming strategy accordingly.
  5. Anticipate a temporary dip in deliverability metrics – While transitioning to a new ESP, you might experience a short-term fluctuation in metrics such as open rates and click-through rates. This is a common occurrence and shouldn’t be viewed as a failure of the service. It’s an expected part of the migration process as mailbox providers adapt to your new sending identity. By closely monitoring your bounce and complaint rates, you can make proactive adjustments to your ramp-up plan to ensure a smooth transition.
  6. Document your warming plan – Have a plan to gradually increase traffic for each identity and monitor engagement metrics. Plan for how to address high bounce or complaint rates.

The following table shows a sample warm-up plan. Notice that the days are categorized by large inbox providers. This is because these providers all accept new mail at different rates. Categorizing this way is a recommended best practice, but if you can’t segment that granularly, then you can use the Daily totals column as a guide. The AWS managed dedicated IP service automatically does this segmentation and throttling at the domain level for you.

The following plan is a typical ramp. You can get more aggressive the higher your overall engagement rates are, so if you’re at 40–60% engagement, you can use this warm-up. If your rates are lower, you might want to be a little more conservative. Make sure to be adaptive as you go into your warming plan because you might need to maintain the same rate for a couple days or even roll back a step if you’re experiencing negative trends such as a drop in deliverability or engagement. Remember, as you get into the less engaged segments of your list, engagement will drop, but it shouldn’t be drastic. Constantly monitor your metrics during this critical time.

Day @gmail.com @hotmail.com @outlook.com @yahoo.com @icloud.com @aol.com Others Daily total
1 150 150 150 150 150 150 150 1,050
2 300 300 300 300 300 300 300 2,100
3 600 600 600 600 600 600 600 4,200
4 1,200 1,200 1,200 1,200 1,200 1,200 1,200 8,400
5 2,400 2,400 2,400 2,400 2,400 2,400 2,400 16,800
6 5,000 5,000 5,000 5,000 5,000 5,000 5,000 35,000
7 10,000 10,000 10,000 10,000 10,000 10,000 10,000 70,000
8 20,000 20,000 20,000 20,000 20,000 20,000 20,000 140,000
9 40,000 40,000 40,000 40,000 40,000 40,000 40,000 280,000
10 80,000 80,000 80,000 80,000 80,000 80,000 80,000 560,000
11 150,000 150,000 150,000 150,000 150,000 150,000 150,000 1,050,000
12 300,000 300,000 300,000 300,000 300,000 300,000 300,000 2,100,000
13 425,000 425,000 425,000 425,000 425,000 425,000 425,000 2,975,000
14 500,000 500,000 500,000 500,000 500,000 500,000 500,000 3,500,000
15 600,000 600,000 600,000 600,000 600,000 600,000 600,000 4,200,000
16 650,000 650,000 650,000 650,000 650,000 650,000 650,000 4,550,000
17 700,000 700,000 700,000 700,000 700,000 700,000 700,000 4,900,000
18 800,000 800,000 800,000 800,000 800,000 800,000 800,000 5,600,000
19 900,000 900,000 900,000 900,000 900,000 900,000 900,000 6,300,000
20 1,000,000 1,000,000 1,000,000 1,000,000 1,000,000 1,000,000 1,000,000 7,000,000
21 1,100,000 1,100,000 1,100,000 1,100,000 1,100,000 1,100,000 1,100,000 7,700,000
22 1,200,000 1,200,000 1,200,000 1,200,000 1,200,000 1,200,000 1,200,000 8,400,000
23 1,300,000 1,300,000 1,300,000 1,300,000 1,300,000 1,300,000 1,300,000 9,100,000
24 1,400,000 1,400,000 1,400,000 1,400,000 1,400,000 1,400,000 1,400,000 9,800,000
25 1,500,000 1,500,000 1,500,000 1,500,000 1,500,000 1,500,000 1,500,000 10,500,000
26 1,600,000 1,600,000 1,600,000 1,600,000 1,600,000 1,600,000 1,600,000 11,200,000
27 1,700,000 1,700,000 1,700,000 1,700,000 1,700,000 1,700,000 1,700,000 11,900,000
28 1,800,000 1,800,000 1,800,000 1,800,000 1,800,000 1,800,000 1,800,000 12,600,000
29 1,900,000 1,900,000 1,900,000 1,900,000 1,900,000 1,900,000 1,900,000 13,300,000
30 2,000,000 2,000,000 2,000,000 2,000,000 2,000,000 2,000,000 2,000,000 14,000,000
31 2,100,000 2,100,000 2,100,000 2,100,000 2,100,000 2,100,000 2,100,000 14,700,000
32 2,200,000 2,200,000 2,200,000 2,200,000 2,200,000 2,200,000 2,200,000 15,400,000
33 2,300,000 2,300,000 2,300,000 2,300,000 2,300,000 2,300,000 2,300,000 16,100,000
34 2,400,000 2,400,000 2,400,000 2,400,000 2,400,000 2,400,000 2,400,000 16,800,000
35 2,500,000 2,500,000 2,500,000 2,500,000 2,500,000 2,500,000 2,500,000 17,500,000
36 2,600,000 2,600,000 2,600,000 2,600,000 2,600,000 2,600,000 2,600,000 18,200,000
37 2,700,000 2,700,000 2,700,000 2,700,000 2,700,000 2,700,000 2,700,000 18,900,000
38 2,800,000 2,800,000 2,800,000 2,800,000 2,800,000 2,800,000 2,800,000 19,600,000
39 2,900,000 2,900,000 2,900,000 2,900,000 2,900,000 2,900,000 2,900,000 20,300,000
40 3,000,000 3,000,000 3,000,000 3,000,000 3,000,000 3,000,000 3,000,000 21,000,000

Best practices for a successful IP warm-up

A successful IP warm-up involves a strategic approach that combines technical preparation, engaged subscribers, compelling content, and ongoing monitoring.

  1. Ensure technical readinessConfigure DNS records and set up SPF, DKIM, DMARC, and BIMI so your email content complies with best practices. Make sure your DMARC is aligned if you’re sending across multiple ESPs or domains.
  2. Use an engaged, permission-based mailing list – Use a clean, opt-in list of subscribers who are interested in your content. For more information, refer to Optimizing Email Deliverability: A User-Centric Approach to List Management and Monitoring.
  3. Provide compelling, valuable email content – Send content that resonates with your audience and encourages engagement.
  4. Gradually ramp up sending volume and cadence – Start with a small volume of emails and gradually increase over time to allow mailbox providers to observe your sending patterns.
  5. Maintain consistency in sending behavior – Avoid sudden, significant changes in sending volume, content, or frequency.
  6. Continuously monitor and optimize key metrics – Track open rates, click-through rates, bounce rates, and complaint rates, and make adjustments as needed. For more information, refer to Amazon SES – Set up notifications for bounces and complaints.
  7. Ongoing maintenance of sender reputation – Audit data flows, ramp up changes gradually, and follow evolving email marketing best practices.

Navigating initial deliverability challenges

When transitioning to a new ESP, you might encounter some initial deliverability challenges. It’s important to monitor and exercise caution if you observe increased bounce or complaint rates. If you do have challenges, you need to address them promptly. Maintain the same volume or even reduce the volume the next day if you encounter these issues:

  1. Spike in hard bounce rates – Bring over your suppression lists from the ESP you’re offboarding from, but if your previous ESP didn’t manage these well or you load some old addresses you weren’t aware of, it’s common to experience hard bounce spikes at the beginning. If this happens, slow your volume increases or even stop increasing until things stabilize. It’s more important to warm up properly than it is to get to production levels of sending as fast as possible. This is one more reason that it’s always best to start with your most engaged segments.
  2. Increased spam complaints – Emails might reach recipients who previously filtered them, leading to more spam complaints. Changing an identity can also cause your recipients to hit the spam button because they don’t recognize it. Announce identity changes before changing your ESP to reduce the chances of an issue.
  3. Heightened mailbox provider scrutiny – Mailbox providers will closely monitor new senders to confirm they’re not engaged in malicious activities. This can divert emails to the spam filter initially or even be throttled if you reach volume or throughput limits. Gmail is known to be stringent. Amazon SES managed dedicated IPs use our data to know how much mail the big inbox providers will accept while you’re warming up and keep you from overshooting their limits.
  4. ESP throttling and sending limits – The new ESP might have stricter rules regarding the volume of emails that can be sent to individual mailbox providers. Amazon SES has account limits for daily volume and max throughput, so adjust yours to what you’ll need. To learn more, refer to Increasing your Amazon SES sending quotas in the Amazon SES Developer Guide.

Maintaining IP reputation after warming

IP warming is an ongoing process. Even after the initial warm-up phase, it’s essential to maintain your sender reputation by continuously managing your email program. Your subscriber engagement might fluctuate as your list grows and changes. Similarly, ramping up email volume for a seasonal campaign will require adjustments to your warm-up process. You need to be proactive and adapt your IP warming strategy.

Audit data flows and campaigns and monitor email list sources, data collection practices, and campaign performance. When introducing new elements, do so incrementally to avoid triggering reputation issues. To allow time for your reputation to stabilize, provide at least a month for a new baseline to be established after major program changes. Engage with customers, provide value, and implement re-engagement campaigns to nurture your customer relationships. Adhere to evolving email marketing best practices, including proper authentication protocols and emerging technologies. Be proactive and track domain and IP reputation so you can quickly address the deliverability issues that arise. To learn more about monitoring inbox tools such as Google Postmaster, refer to Understanding Google Postmaster Tools (spam complaints) for Amazon SES email senders.

Conclusion

Transitioning your email program to a new ESP such as Amazon SES can seem complex, but it can be quick and seamless if you follow the best practices explained in this post. IP warming is a critical component of this process because it helps build a positive sender reputation with mailbox providers and promotes the reliable delivery of your emails.

Throughout this guide, we’ve covered the key aspects of IP warming and email migration, from understanding the importance of this practice to identifying common challenges and outlining effective strategies for a successful transition. By following best practices such as facilitating technical readiness, using an engaged subscriber base, providing compelling content, and gradually ramping up sending volume, you can navigate the initial deliverability challenges and establish a strong foundation for long-term email program success.

However, the work doesn’t stop when the initial warm-up phase is complete. Maintaining IP reputation and adapting your strategy as your email program and subscriber engagement evolve is an ongoing process. Continuously monitoring key metrics, auditing data flows, and staying up to date with evolving email marketing best practices is crucial for sustaining deliverability. A long-lasting sender reputation and enduring relationships with your list and recipients are some of the key benefits of following these best practices.Transitioning to a new ESP is a significant undertaking, but with the right preparation, execution, and commitment to ongoing maintenance, your migration can be smooth and successful.

Resources for deliverability


About the authors

Monitoring AWS End User Messaging SMS Registrations with Lambda

Post Syndicated from Patrick Viker original https://aws.amazon.com/blogs/messaging-and-targeting/monitoring-aws-end-user-messaging-sms-registrations-with-lambda/

Managing AWS End User Messaging SMS registrations can be challenging, especially when dealing with multiple registrations in various states and countries. This post introduces an automated monitoring solution that helps you stay on top of your registration statuses. By leveraging AWS Lambda, EventBridge, and Simple Email Service (SES), you’ll create a system that provides regular updates about registrations that need attention, are under review, in draft pending submission, or have recently been completed.

Whether you’re managing Sender IDs, United States 10DLC campaigns, toll-free numbers, or short codes, this solution will help you maintain visibility across all your registrations and respond promptly to status changes. The setup takes approximately 15-20 minutes and requires no ongoing maintenance beyond occasional adjustments to meet your evolving needs.

Estimated Setup Time: 15-20 minutes

Prerequisites

  • An AWS account with access to Lambda, IAM, EventBridge, End User Messaging SMS, and SES
  • A verified email address in Amazon SES for sending reports.
Figure 1: AWS End User Messaging SMS registrations in the console. This view shows registrations in various states that our Lambda function will monitor.

Figure 1: AWS End User Messaging SMS registrations in the console. This view shows registrations in various states that our Lambda function will monitor.

Step 1: Set up Amazon SES

  1. Open the Amazon SES console
  2. Navigate to “Verified identities”
  3. If you have an identity verified you can skip this section
  4. If you do not already have an identity verified Click “Create identity”
  5. Review this post to learn how to verify an identity
    NOTE: Best practice is to verify a domain identity. This will authenticate your domain and improve deliverability. An email address identity, while more simple, will not be authenticated through DKIM which may decrease deliverability.

Reference: Creating and verifying identities in Amazon SES

Step 2: Create an IAM Role

  1. Open the IAM console
  2. Navigate to “Roles” and click “Create role”
  3. Select “AWS service” and “Lambda” as the use case
  4. Add only the following AWS managed policy: AWSLambdaBasicExecutionRole
  5. Name the role (e.g., “EndUserMessagingRegistrationsMonitorRole”) and click “Create role”
  6. After role creation, click on the newly created role
  7. Select “Add permissions” → “Create inline policy”
  8. Click on the “JSON” tab and paste the following policy:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "sms-voice:DescribeRegistrations",
                    "sms-voice:DescribeRegistrationVersions"
                ],
                "Resource": "arn:aws:sms-voice:${region}:${account-id}:registration/*"
            },
            {
                "Effect": "Allow",
                "Action": "ses:SendRawEmail",
                "Resource": [
                    "arn:aws:ses:${region}:${account-id}:identity/${domain}",
                    "arn:aws:ses:${region}:${account-id}:configuration-set/*"
                ],
                "Condition": {
                    "StringLike": {
                        "ses:FromAddress": [
                            "*@${domain}"
                        ]
                    }
                }
            }
        ]
    }
  9. Replace the placeholders in the policy:
    1. ${region}: Your AWS region (e.g., ‘us-west-2’)
    2. ${account-id}: Your AWS account ID
    3. ${domain}: Your verified SES domain
  10. Click “Next”
  11. Name the policy (e.g., “EndUserMessagingRegistrationsAccess”) and click “Create policy”

Reference: Creating a role for an AWS service (console)

Step 3: Create the Lambda Function

  1. Open the Lambda console
  2. Click “Create function”
  3. Choose “Author from scratch”
  4. Configure basic settings:
  5. Name: EndUserMessagingRegistrationsMonitor
  6. Runtime: Python 3.12
  7. Architecture: x86_64
  8. Permissions: Use the IAM role created in Step 2
  9. Click “Create function”
  10. Configure environment variables:
    1. Under “Configuration” tab → “Environment variables”
    2. Set the following key/value pairs:
      1. Key: SENDER_EMAIL, Value: [Your verified SES email]
      2. Key: RECIPIENT_EMAIL, Value: [Email to receive reports]
  11. Configure function timeout:
    1. Under “Configuration” → “General configuration”
    2. Set timeout to 1 minute
  12. In the function code area, paste the following code:
    import boto3
    import json
    from datetime import datetime, timedelta
    from collections import defaultdict
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    import os
    
    # Constants
    REGION = os.environ['AWS_REGION']
    SENDER_EMAIL = os.environ['SENDER_EMAIL']
    RECIPIENT_EMAIL = os.environ['RECIPIENT_EMAIL']
    COMPLETED_LOOKBACK_DAYS = 7
    
    # Initialize AWS clients
    sms_client = boto3.client('pinpoint-sms-voice-v2', region_name=REGION)
    ses_client = boto3.client('ses', region_name=REGION)
    
    # Global registration dictionary
    registrations = {
        'REQUIRES_UPDATES': defaultdict(list),
        'CREATED': defaultdict(list),
        'COMPLETED': defaultdict(list),
        'REVIEWING': defaultdict(list)
    }
    
    def get_console_url(registration_id):
        return f"https://{REGION}.console.aws.amazon.com/sms-voice/home?region={REGION}#/registrations?registration-id={registration_id}"
    
    def get_version_details(registration_id, latest_denied_version=None):
        try:
            if latest_denied_version:
                response = sms_client.describe_registration_versions(
                    RegistrationId=registration_id,
                    VersionNumbers=[latest_denied_version]
                )
            else:
                response = sms_client.describe_registration_versions(
                    RegistrationId=registration_id,
                    MaxResults=1
                )
            
            if response['RegistrationVersions']:
                return response['RegistrationVersions'][0]
        except Exception as e:
            print(f"Error getting version details for {registration_id}: {str(e)}")
        return None
    
    def is_recently_completed(version_info):
        if 'RegistrationVersionStatusHistory' in version_info:
            history = version_info['RegistrationVersionStatusHistory']
            if 'ApprovedTimestamp' in history:
                approved_time = history['ApprovedTimestamp']
                if isinstance(approved_time, datetime):
                    approved_time = approved_time.timestamp()
                lookback_time = (datetime.now() - timedelta(days=COMPLETED_LOOKBACK_DAYS)).timestamp()
                return approved_time > lookback_time
        return False
    
    def categorize_registration_type(registration_type):
        if 'TEN_DLC' in registration_type:
            return 'TEN_DLC'
        elif 'LONG_CODE' in registration_type:
            return 'LONG_CODE'
        elif 'SHORT_CODE' in registration_type:
            return 'SHORT_CODE'
        elif 'SENDER_ID' in registration_type:
            return 'SENDER_ID'
        elif 'TOLL_FREE' in registration_type:
            return 'TOLL_FREE'
        else:
            return 'OTHER'
    
    def categorize_registrations():
        global registrations
        registrations = {
            'REQUIRES_UPDATES': defaultdict(list),
            'CREATED': defaultdict(list),
            'COMPLETED': defaultdict(list),
            'REVIEWING': defaultdict(list)
        }
    
        try:
            response = sms_client.describe_registrations()
            
            for registration in response.get('Registrations', []):
                status = registration['RegistrationStatus']
                registration_id = registration['RegistrationId']
                registration_type = registration['RegistrationType']
                category = categorize_registration_type(registration_type)
                
                reg_info = {
                    'id': registration_id,
                    'type': registration_type,
                    'status': status,
                    'version': registration['CurrentVersionNumber'],
                    'console_url': get_console_url(registration_id)
                }
    
                if 'AdditionalAttributes' in registration:
                    reg_info['additional_attributes'] = registration['AdditionalAttributes']
    
                if status == 'REQUIRES_UPDATES':
                    latest_denied_version = registration.get('LatestDeniedVersionNumber')
                    version_info = get_version_details(registration_id, latest_denied_version)
                    if version_info and 'DeniedReasons' in version_info:
                        reg_info['denial_reasons'] = version_info['DeniedReasons']
                    registrations['REQUIRES_UPDATES'][category].append(reg_info)
                
                elif status == 'CREATED':
                    registrations['CREATED'][category].append(reg_info)
                
                elif status == 'REVIEWING':
                    registrations['REVIEWING'][category].append(reg_info)
                
                elif status == 'COMPLETE':
                    version_info = get_version_details(registration_id)
                    if version_info and is_recently_completed(version_info):
                        approved_timestamp = version_info['RegistrationVersionStatusHistory']['ApprovedTimestamp']
                        if isinstance(approved_timestamp, datetime):
                            approved_timestamp = approved_timestamp.timestamp()
                        reg_info['approved_timestamp'] = approved_timestamp
                        registrations['COMPLETED'][category].append(reg_info)
                    
        except Exception as e:
            print(f"Error listing registrations: {str(e)}")
            raise e
    
    def generate_html_output():
        html = """
        <html>
        <head>
            <style>
                body { 
                    font-family: Arial, sans-serif;
                    margin: 20px;
                    line-height: 1.6;
                }
                .registration-group { margin: 20px 0; }
                .registration-category { 
                    background-color: #f0f0f0;
                    padding: 10px;
                    margin: 10px 0;
                    border-radius: 5px;
                }
                .registration-item {
                    border-left: 4px solid #ccc;
                    margin: 10px 0;
                    padding: 10px;
                    background-color: #ffffff;
                }
                .requires-updates { border-left-color: #ff9900; }
                .created { border-left-color: #007bff; }
                .completed { border-left-color: #28a745; }
                .reviewing { border-left-color: #6c757d; }
                .denial-reasons {
                    background-color: #fff3f3;
                    padding: 10px;
                    margin: 5px 0;
                    border-radius: 3px;
                }
                .console-link {
                    color: #007bff;
                    text-decoration: none;
                    padding: 2px 5px;
                    border: 1px solid #007bff;
                    border-radius: 3px;
                }
                .console-link:hover {
                    background-color: #007bff;
                    color: #ffffff;
                }
                .summary {
                    margin: 20px 0;
                    padding: 15px;
                    background-color: #e9ecef;
                    border-radius: 5px;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                }
                .divider {
                    border-top: 2px solid #dee2e6;
                    margin: 20px 0;
                }
                .lookback-info {
                    background-color: #e2e3e5;
                    padding: 10px;
                    border-radius: 5px;
                    margin: 10px 0;
                    font-style: italic;
                }
                h2, h3, h4 {
                    color: #333;
                    margin-top: 20px;
                }
                ul {
                    margin: 5px 0;
                    padding-left: 20px;
                }
                li {
                    margin: 5px 0;
                }
            </style>
        </head>
        <body>
        """
    
        html += f"<h2>Registration Status Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</h2>"
    
        html += f"""
        <div class="lookback-info">
            Note: Completed registrations shown are those completed within the last {COMPLETED_LOOKBACK_DAYS} days.
        </div>
        """
    
        html += '<div class="summary"><h3>Summary</h3>'
        for status, categories in registrations.items():
            total = sum(len(regs) for regs in categories.values())
            html += f"<p><strong>{status}:</strong> {total}"
            if status == 'COMPLETED':
                html += f" (last {COMPLETED_LOOKBACK_DAYS} days)"
            html += "<br>"
            for category, regs in categories.items():
                if regs:
                    html += f"&nbsp;&nbsp;{category}: {len(regs)}<br>"
            html += "</p>"
        grand_total = sum(sum(len(regs) for regs in categories.values()) for categories in registrations.values())
        html += f"<p><strong>Total Registrations:</strong> {grand_total}</p>"
        html += "</div>"
    
        html += '<div class="divider"></div>'
    
        html += "<h3>Detailed Registration Status</h3>"
    
        for status, categories in registrations.items():
            total = sum(len(regs) for regs in categories.values())
            html += f"""
            <div class="registration-group">
                <h3>{status} Registrations (Total: {total})</h3>
            """
    
            for category, regs in categories.items():
                if regs:
                    html += f"""
                    <div class="registration-category">
                        <h4>{category} Registrations ({len(regs)})</h4>
                    """
    
                    for reg in regs:
                        css_class = status.lower().replace('_', '-')
                        html += f"""
                        <div class="registration-item {css_class}">
                            <strong>Registration ID:</strong> {reg['id']}<br>
                            <strong>Type:</strong> {reg['type']}<br>
                            <strong>Status:</strong> {reg['status']}<br>
                            <strong>Version:</strong> {reg['version']}<br>
                            <strong>Console:</strong> <a href="{reg['console_url']}" class="console-link" target="_blank">Open in Console</a><br>
                        """
    
                        if (reg['type'] == 'US_TEN_DLC_BRAND_VETTING' and 
                            status == 'COMPLETED' and 
                            'additional_attributes' in reg and 
                            'VETTING_SCORE' in reg['additional_attributes']):
                            html += f"<strong>Vetting Score:</strong> {reg['additional_attributes']['VETTING_SCORE']}<br>"
    
                        if status == 'REQUIRES_UPDATES' and reg.get('denial_reasons'):
                            html += '<div class="denial-reasons"><strong>Denial Reasons:</strong><ul>'
                            for reason in reg['denial_reasons']:
                                html += f"""
                                <li>
                                    <strong>{reason.get('Reason', 'N/A')}</strong><br>
                                    {reason.get('ShortDescription', 'N/A')}<br>
                                """
                                if reason.get('LongDescription'):
                                    html += f"{reason['LongDescription']}<br>"
                                if reason.get('DocumentationLink'):
                                    html += f'<a href="{reason["DocumentationLink"]}" target="_blank">Documentation</a>'
                                html += "</li>"
                            html += "</ul></div>"
    
                        if status == 'COMPLETED':
                            approved_time = datetime.fromtimestamp(reg['approved_timestamp']).strftime('%Y-%m-%d %H:%M:%S')
                            html += f"<strong>Approved:</strong> {approved_time}<br>"
    
                        html += "</div>"
                    html += "</div>"
            html += "</div>"
    
        html += "</body></html>"
        return html
    
    def send_email(html_content, subject, recipient):
        msg = MIMEMultipart('mixed')
        msg['Subject'] = subject
        msg['From'] = SENDER_EMAIL
        msg['To'] = recipient
    
        html_part = MIMEText(html_content, 'html')
        msg.attach(html_part)
    
        try:
            response = ses_client.send_raw_email(
                Source=msg['From'],
                Destinations=[recipient],
                RawMessage={'Data': msg.as_string()}
            )
            print(f"Email sent! Message ID: {response['MessageId']}")
        except Exception as e:
            print(f"Error sending email: {str(e)}")
            raise e
    
    def lambda_handler(event, context):
        try:
            print("Starting registration categorization...")
            categorize_registrations()
            
            print("Generating HTML report...")
            html_content = generate_html_output()
            
            print("Sending email...")
            subject = f"End User Messaging SMS Registration Status Report - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
            send_email(html_content, subject, RECIPIENT_EMAIL)
            
            return {'statusCode': 200, 'body': json.dumps('Registration status report generated and sent successfully')}
        except Exception as e:
            print(f"Error in lambda execution: {str(e)}")
            return {'statusCode': 500, 'body': json.dumps(f'Error generating report: {str(e)}')}

Reference: Building Lambda functions with Python

Step 4: Set Up EventBridge Rule

  1. Open the Amazon EventBridge console
  2. Click “Create rule”
  3. Name your rule (e.g., “EndUserMessagingRegistrationsMonitorSchedule”)
  4. For the event pattern, choose “Schedule” then select “Continue in EventBridge Scheduler”
  5. Configure your schedule pattern to your requirements (for example, Cron-based schedule to run at specific days and times or rate-based schedule such as every 1 day). Click “Next”.
  6. Select “Lambda” for “Target detail” and select the Lambda function created in Step 3 as the target from the dropdown. Click “Next”.
  7. For permissions:
    1. Select “Create new role for this schedule”
    2. EventBridge will automatically create a role with the necessary permissions to invoke your Lambda function
  8. Click “Next” to review your configuration
  9. Click “Create schedule”

Reference: Amazon EventBridge Scheduler

Step 5: Test the Setup

  1. Open the Lambda console and navigate to your function
  2. Click “Test” and create a test event (you can use an empty JSON object {})
  3. Run the test and check the execution results
  4. Verify that you receive an email report

Reference: Testing Lambda functions in the console

The generated email report provides a clear summary of all registrations, categorized by their status.

Figure 2: The generated email report provides a clear summary of all registrations, categorized by their status.

Understanding the Lambda Function

Let’s break down the key components of our Lambda function:

  1. Initialization: The script sets up necessary AWS clients and defines constants.
  2. categorize_registrations(): This function fetches all registrations and categorizes them based on their status and type.
  3. generate_html_output(): Creates a formatted HTML report of the registration statuses.
  4. send_email(): Uses Amazon SES to send the HTML report via email.
  5. lambda_handler(): The main entry point for the Lambda function, orchestrating the entire process.

The function categorizes registrations into four main statuses:

  • REQUIRES_UPDATES: Registrations that need attention or modifications
  • CREATED: Newly created registrations
  • REVIEWING: Registrations currently under review
  • COMPLETED: Registrations that have been approved recently (within the last 7 days by default)
Detailed view of a registration requiring updates and created registrations pending submission, including specific denial reasons if applicable and direct console links.

Figure 3: Detailed view of a registration requiring updates and created registrations pending submission, including specific denial reasons if applicable and direct console links.

Customization Options

  1. Lookback Period: Modify the COMPLETED_LOOKBACK_DAYS constant to change how far back the function checks for completed registrations.
  2. Email Formatting: Adjust the HTML and CSS in generate_html_output() to customize the email report’s appearance.
  3. Additional Data: Modify the reg_info dictionary in categorize_registrations() to include more data fields in your report.

Monitoring and Maintenance

  1. CloudWatch Logs: Regularly check the Lambda function’s CloudWatch Logs for any errors or unexpected behavior.
  2. Adjusting Schedule: If you find the current schedule doesn’t meet your needs, adjust the EventBridge rule accordingly.

Conclusion

You now have an automated system that monitors your End User Messaging SMS registrations and sends you regular, detailed status reports. This setup provides:

  • Automated visibility into registrations requiring updates or attention
  • Clear tracking of draft registrations awaiting your submission
  • Monitoring of registrations under review
  • Notifications of recently completed registrations
  • A consolidated view of all registration states through formatted email reports

This automated solution eliminates the need for manual status checking and helps ensure timely responses to registration changes. As your messaging needs grow, you can easily customize the monitoring frequency, lookback period, and report format to match your requirements.

Next Steps:

  • Consider adjusting the EventBridge schedule based on your registration volume
  • Customize the email format to highlight information most relevant to your team
  • Set up CloudWatch alarms to monitor the Lambda function’s health
  • Review and update the completed registrations lookback period as needed

For more complex scenarios, consider extending this solution with additional features like Slack notifications, registration metrics tracking, or integration with your ticketing system.

 

Use AI agents and the Model Context Protocol with Amazon SES

Post Syndicated from Zip Zieper original https://aws.amazon.com/blogs/messaging-and-targeting/use-ai-agents-and-the-model-context-protocol-with-amazon-ses/

Amazon Simple Email Service (Amazon SES) delivers a cloud-based email solution that empowers businesses to send emails more efficiently and at a larger scale. Its powerful, scalable platform enables organizations from startups to global brands to send personalized, high-volume email communications while maintaining exceptional deliverability and performance.

Amazon SES caters to a wide range of users, from developers and technical marketing professionals to business communicators. In addition to offering robust programmatic access through APIs and SMTP protocols, Amazon SES provides a comprehensive web console and intuitive dashboards that make email configuration and performance monitoring accessible to users with varying technical backgrounds. Historically, navigating email workflows and configuring advanced email capabilities in Amazon SES has required specialized knowledge, resulting in a learning curve for new users. As seen in many other areas, today’s AI tools can offer more intuitive ways to manage Amazon SES to get the most out of your email communications. We have found, however, that these AI tools occasionally produce inconsistent results, often as a result of the underlying large language model’s (LLM’s) training data.

Recognizing the need for a specialized, service-aware, AI-friendly Amazon SES solution, we are introducing the SESv2 MCP Server, a sample Model Context Protocol (MCP) for Amazon SES. We’ve integrated the SESv2 MCP Server sample with the Amazon SES v2 APIs to provide more precise and reliable AI-assisted use, management, and configuration for Amazon SES.

MCP is an open protocol that enables seamless integration between your AI-powered integrated development environment (IDE) or AI assistant, enriching the capabilities of the AI and enabling you to use Amazon SES using natural language. For more info, see the GitHub repo.

We’ve released the SESv2 MCP Server sample on GitHub and invite current and prospective customers to experiment with it in non-production environments. You can use it with your AI tools to explore ways in which AI can be used with Amazon SES to send emails, check configurations, and review deliverability. We’re interested in learning how you use your AI tools and the SESv2 MCP Server to test out email sending in different services or applications. We’re also curious if new customers find it helpful when configuring and learning about their Amazon SES service. No matter how you use it, we are eager for your feedback, comments, and contributions through the GitHub project’s issues.

Solution overview

You can use the SESv2 MCP Server sample with AI assistant applications like Anthropic’s Claude Desktop. You can also integrate it into MCP-compatible agentic AI coding assistants such as Amazon Q Developer, Amazon Q for command line, Cline, Cursor, and Windsurf. When used as an AI coding assistant, the SESv2 MCP Server sample helps developers add Amazon SES email capabilities to their applications and services using plain, natural language prompting. For recommendations from AWS on how to improve your vibe coding experience, refer to Vibe coding tips and tricks.

After you’ve configured the sample and authenticated with your AWS credentials, you can use natural language in your chosen AI tool. For example, an email marketing manager might want to ask Anthropic’s Claude Desktop “provide me with the status of the verified identities in my SES account, along with any recommendations to improve deliverability.” Someone new to Amazon SES can ask the Amazon Q CLI “create a new Amazon SES configuration set for the octank.com identity, enable it for event publishing for bounces and complaints.” Similarly, the developer of an AI-enabled restaurant booking application might ask the Amazon Q CLI “my application needs to send email confirmation of a customers online booking. Can you walk me thru adding this capability to my app using my SES account?”

As you can see from these examples, although it’s helpful to know a bit about email, and Amazon SES in general, with the help of your AI tool and the SESv2 MCP Server sample, you don’t need to be an email or Amazon SES expert. The combination of your creativity, AI tool, and the SESv2 MCP Server sample empowers even non-developers to create, test, and monitor Amazon SES workflows using natural language.

The SESv2 MCP Server sample release uses the open source Smithy Java project, which is still in development. As such, the SESv2 MCP Server is considered a sample, and we do not recommend employing it for production use. When a stable version is available, we might update this post and the GitHub repository accordingly.

Prerequisites

To follow along with the example use cases, make sure you have the following prerequisites set up:

  • AWS credentials with appropriate permissions.
  • An MCP-compatible LLM client (such as Anthropic’s Claude Desktop, Cline, Amazon Q CLI, or Cursor). For this post, we use the Amazon Q Developer CLI. For installation instructions, refer to Installing Amazon Q for command line.
  • Java 21 (or later) runtime (as required by Smithy Java).
  • Access to GitHub.
  • Git installed locally. For instructions, see Getting Started – Installing Git.

Best practices for using MCPs

To maximize the benefits of MCP-assisted development while maintaining security and code quality, we suggest you follow these essential guidelines:

  • Always review generated code for security implications before deployment
  • Use MCP servers as accelerators, not replacements for developer judgment and expertise
  • Keep MCP servers updated with the latest AWS security best practices
  • Follow the principle of least privilege when configuring AWS credentials
  • Run security scanning tools on generated infrastructure code

Configure the AWS CLI

Use the following command to configure the AWS Command Line Interface (AWS CLI) with the AWS credentials for your Amazon SES account and AWS Region:

aws configure

Clone and build the GitHub repository locally

To use macOS or Linux, use the following command to clone and build the GitHub repo:

git clone https://github.com/aws-samples/sample-for-amazon-ses-mcp.git
cd sample-for-amazon-ses-mcp
./build.sh

For Windows, use the following command:

git clone https://github.com/aws-samples/sample-for-amazon-ses-mcp.git
cd sample-for-amazon-ses-mcp
.\build.bat

Copy the absolute path to the .jar file (JAR_PATH_FROM_BUILD_OUTPUT). This will be printed at the end of the build script:

/<your path>/sample-for-amazon-ses-mcp/artifacts/sample-for-amazon-ses-mcp-all.jar

Configure your AI tool to use SESv2 MCP Server

When the build is complete, add SESv2 MCP Server to your AI tool’s MCP configuration:

{
  "mcpServers": {
    "sesv2-mcp-server": {
      "command": "java",
      "args": [
        "-jar",
        "JAR_PATH_FROM_BUILD_OUTPUT"
      ]
    }
  }
}

See MCP configuration for configuration steps. See the Claude Desktop MCP configuration guide for setup instructions.

After you build the SESv2 MCP Server and configure your AWS credentials, you’re ready to interact with Amazon SES. Keep in mind that effective, thoughtful prompting is crucial for successful AI-assisted development. For more information about vibe coding, see Vibe coding tips and tricks.

Example use cases

In this section, we provide some guided examples using the Amazon Q Developer CLI to interact with Amazon SES. Feel free to experiment on your own use cases, and share your comments and ideas through the GitHub project’s issues. Do not disclose any personal, commercially sensitive, or confidential information.

Get information, recommendations, and configurations your Amazon SES account

Open your AI tool; for these examples, we use a macOS terminal and initiate a chat session with the Amazon Q CLI:

q chat

We’ve found it useful to provide your AI tool with some guidance:

You're connected to the SESv2 MCP Server and have access to the AWS SESv2 APIs.

Ask the Amazon Q CLI about your AWS account’s SES email identities:

Tell me about the identities in my account, and also if the account is in the SES sandbox?

The Amazon Q CLI will request permission to use the SESv2 MCP Server (which provides the Amazon Q CLI with the SESv2 APIs ListEmailIdentities and GetAccount) to query your AWS SES account and reply with a detailed summary.

Ask the Amazon Q CLI if it has any recommendations related to improving deliverability for your Amazon SES account:

Do you have any recommendations to improve email deliverability for my SES account?

The Amazon Q CLI will use the SESv2 MCP Server (which provides the CLI with the SESv2 API ListRecommendations) to query your Amazon SES account and reply with a detailed summary.

Ask the Amazon Q CLI to set up Amazon SES click tracking for one of your domains. We have found it helpful to remind the CLI that it has access to additional knowledge of the AWS service APIs. It’s also a good idea to make sure the AI tool doesn’t invent nonexistent APIs.

You also have access to other AWS service APIs via the AWS CLI and your general knowledge, but you may only use known, documented APIs - do not invent or create any APIs or commands.
Set up Amazon SES click tracking with CloudWatch integration for the domain <my verified identity> to monitor email metrics. Use Amazon's default tracking domain (no SSL or https) for the click tracking to ensure immediate functionality without requiring custom domain setup. Include all necessary configuration steps and verify the setup works correctly. Create a test HTML email to <my email address> from <no-reply@verified domain> with subject "Testing SES click tracking". Create an HTML (with fallback to text) body with links and short descriptions taken from the public AWS webpages for Amazon SES, AWS End User Messaging and Amazon Connect. 

Send emails with your Amazon SES account

Using its knowledge of Amazon SES from the SESv2 MCP Server and permissions to use your Amazon SES account (aws configure), you can use your AI tool to create and send emails using Amazon SES.

If your Amazon SES account is in the Amazon SES sandbox, you are limited to sending and receiving email from verified email addresses. You are also limited to 200 messages in 24 hours. For more information about the Amazon SES sandbox, see Request production access (Moving out of the Amazon SES sandbox). If you’re in the sandbox, you can simply ask your AI tool “verify my email address <[email protected]>.”

Ask the Amazon Q CLI to send a test email with a sample HTML body:

Send a test email to <my verified email address> from <verified SES email identity>. Set the from email display name to "MCP testing". Make the email subject "Test sending an email via SES MCP". Use the information found on the Amazon SES website to create an HTML message body with a few sentences and bullet points about SES. Provide a text version of the message body in case of fallback.

Check your email, where you will receive a response.

You can get creative and ask the Amazon Q CLI to create a formatted email template with personalization using a simple table with email recipients, the product they bought, and their postal code:

Use the table below to send each person in the table an html formatted (with fallback) email message. 
-- table --
email,name,product,zipcode
<my verified email address>,Alice,an umbrella,98101
<my verified email address>,Bob,lots of sunscreen,10001
-- end table --
Use the template below. Create a 5-day weather forecast graphic similar to popular weather app graphics based on estimated weather for their ZIP code.
-- template --
"Hi {{name}}, thanks for buying {{product}}; it looks like you'll need it soon based on the 5-day weather forecast for your local area: <5-day weather forecast graphic>.

As we’ve demonstrated, you don’t need to be a seasoned developer to create and test Amazon SES workflows when you have an AI tool and the SESv2 MCP Server sample.

Conclusion

The SESv2 MCP Server sample democratizes the ability to configure, manage, and create sophisticated email automation workflows with Amazon SES.

The examples and guidance in this post demonstrate how even newcomers can use AI tools like the Amazon Q CLI to test out configuring, monitoring, and sending emails with Amazon SES using natural language. More technical users, including developers, can use the SESv2 MCP Server sample to build and test intelligent email applications that use Amazon SES, or to test out building Amazon SES sending into their own application.

We hope you will experiment with the SESv2 MCP Server sample and provide us with your thoughts and feedback, and perhaps contribute to the project through the GitHub project’s issues.

Additional resources

AWS End User Messaging SMS & Voice v2 API: A Migration Guide from v1

Post Syndicated from Brett Ezell original https://aws.amazon.com/blogs/messaging-and-targeting/aws-end-user-messaging-sms-and-voice-v2-api-a-migration-guide-from-v1/

This blog covers the steps on how to upgrade to the latest APIs offered by AWS for SMS messaging.

IMPORTANT: Understanding this Migration in Context of Amazon Pinpoint’s End of Support

Amazon Pinpoint announced its end of support (EOS) on October 2026. However, if you are an existing customer using Amazon Pinpoint for SMS, your current SMS operations are not impacted by the EOS, and you are not required to migrate to the v2 API at this time.

This blog post details an optional upgrade path from the Amazon Pinpoint v1 SendMessages API to the AWS End User Messaging SMS and Voice v2 SendTextMessage API. Transitioning allows you to leverage enhanced capabilities and new features available exclusively in the v2 API.

Regarding your existing resources: Your SMS phone numbers and sender ID resources are already stored in AWS End User Messaging. There is no need to register new numbers (originators) or configure new Sender IDs if you choose to migrate your API usage as described here.

AWS End User Messaging provides developers with a scalable and cost-effective messaging infrastructure without compromising the safety, security, or results of their communications. Developers can integrate messaging over channels such as SMS, MMS, voice text-to-speech, WhatsApp and mobile push to support use cases such as one-time passwords (OTP) at sign-ups, account updates, appointment reminders, delivery notifications, promotions and more. AWS End User Messaging was renamed in 2024 as the new name for Amazon Pinpoint’s communication capabilities. For the SMS protocol, the service includes two sets of APIs, including SMS and Voice, version 2 API (v2 API), which provides enhanced capabilities and flexibility for customer communications and the original Amazon Pinpoint v1 API.

The End User Messaging SMS service provides core building blocks and is the core service in charge of SMS delivery for other AWS services, including Amazon Simple Notification Service (SNS), Amazon Cognito, and Amazon Connect. Transitioning to the v2 API allows customers using the older Amazon Pinpoint v1 API to access enhanced capabilities available now—like improved control via Configuration Sets, Phone Pools, Protect Configurations, and Registrations—as well as ensuring access to future features developed exclusively in the V2 APIs.

In this post, we will focus on why transitioning is beneficial and how developers can transition from Amazon Pinpoint’s v1 SendMessages API to the AWS End User Messaging SMS and Voice, version 2 (SendTextMessage) API. This move offers more functionality for creating custom messaging solutions and integrating seamlessly with third-party applications. Consolidating management and messaging into AWS End User Messaging provides customers with greater control and access to the features and capabilities described below.

What Are the Changes and Benefits of Migrating?

Migrating from the Pinpoint v1 SendMessages API to the AWS End User Messaging v2 SendTextMessage API offers several key advantages in plain language:

  • Simpler Code: The new SendTextMessage API has a flatter, more straightforward structure compared to the nested configuration required by the old SendMessages API. This makes your code easier to write, read, and maintain.
  • More Control Over Delivery: AWS End User Messaging introduces new tools that give you fine-grained control:
    • Configuration Sets: Apply specific rules for logging via Event Destinations, routing (using specific number pools), and opt-out management per message.
    • Phone Pools: Group your sending phone numbers or sender IDs to manage sender reputation, improve reliability with failover, and handle different use cases more effectively.
    • Protect Configurations: Set account-level safety rules, like blocking messages to certain countries, or filtering messages suspected to be Artificially Inflated Traffic (AIT), enhancing security and compliance.
    • Message Feedback: Enable detailed feedback mechanisms and track message conversion data like one time passcode conversions.
  • Better Monitoring & Troubleshooting: With Configuration Sets and Event Destinations, you retain detailed delivery logs, Delivery Receipts (DLRs), and event tracking, similar to Pinpoint’s event streaming. This allows comprehensive monitoring via Amazon EventBridge, Amazon CloudWatch, Amazon Data Firehose, or Amazon SNS.
  • Expanded Capabilities: The AWS End User Messaging v2 API exclusively supports Media Messaging Service (MMS) and includes integrated tools for managing control plane activities, such as sender registrations required in many countries.
  • Future-Proofing: AWS is actively developing new features exclusively for the AWS End User Messaging v2 API. Migrating ensures you can leverage the latest advancements in messaging technology.

Understanding Key AWS End User Messaging Components

Migration involves understanding and utilizing several core AWS End User Messaging components:

Phone Pools

  • What they are: A Phone Pool is a collection of your origination identities (phone numbers, Sender IDs) that share common settings. When you send a message using a pool, AWS End User Messaging can automatically select an appropriate identity from that pool.
  • Benefits:
    • Improved Reliability: Pools provide automatic failover; if one number in the pool fails, another can be used.
    • Reputation Management: You can create separate pools for different use-cases, or types of messages (e.g., transactional vs. promotional) to isolate sender reputations.
    • Simplified Configuration: Apply settings like opt-out lists or two-way SMS configurations to the entire pool.
  • When to Use: Pools are highly recommended for managing multiple origination identities, ensuring high availability, or separating traffic. However, they are optional. If you only use a single phone number or Sender ID for a specific use case, you can continue to specify that single identity directly in your SendTextMessage API calls.

Protect Configurations

  • What they are: Protect Configurations allow you to define account-wide or configuration-set-level rules that safeguard against unwanted traffic, including Artificially Inflated Traffic (AIT) and messages to specific destinations. They operate using rules applied per country, which can be set to different modes: Block (prevent sending to specified countries), Monitor (analyze traffic for AIT risk without blocking, providing visibility), or Filter (automatically block messages suspected of being AIT based on risk analysis, in addition to blocking specified countries).
  • Benefits:
    • Enhanced Security: Prevent accidental or malicious sending to unintended destinations by explicitly blocking specific countries.
    • Proactive AIT Defense (Filter): Automatically block suspected fraudulent SMS pumping traffic based on risk analysis before messages are sent, reducing exposure to financial costs and potential reputation damage associated with AIT.
    • Risk Visibility (Monitor): Gain insights into potential AIT patterns targeting your account and understand the likely impact of Filter rules without disrupting legitimate message delivery. Recommendations are provided via event destinations.
    • Compliance: Helps enforce geographic sending restrictions required by regulations or internal policies.
    • Cost Control: Avoid unexpected charges from sending to blocked/filtered destinations.
    • Granular Application: Apply different rules (Block/Monitor/Filter) per country and use multiple Protect Configurations tailored to different workflows (e.g., stricter filtering for public-facing forms vs. internal notifications).
  • Note: Protect Configurations, including the Monitor and Filter modes for AIT, are features unique to the AWS End User Messaging v2 API and are not available in the Pinpoint v1 API. Check out Defending Against SMS Pumping: New AWS Features to Help Combat Artificially Inflated Traffic to learn more.

Configuration Sets

  • What they are: Configuration Sets are collections of rules applied to messages when you send them. You specify which Configuration Set to use in your SendTextMessage API call.
  • Benefits:
    • Essential for Monitoring: Configuration Sets are required to receive message event data (including Delivery Receipts – DLRs). They replace the automatic event streaming provided by Pinpoint v1. You must associate an Event Destination (EventBridge, CloudWatch Logs, Amazon Data Firehose, or SNS) with your Configuration Set to capture delivery status, failures, and other events.
    • Granular Control: Apply specific settings per message, such as routing messages through specific Phone Pools, using different default Sender IDs, or associating different opt-out lists.
    • Message Feedback: Enable detailed feedback mechanisms.
  • Key Takeaway: Migrating users must create and use Configuration Sets with associated Event Destinations if they need to monitor message delivery status, replicating the functionality previously provided by Pinpoint event streams.

Registrations

  • What they are: In many countries and regions, regulations require businesses to register their Sender IDs or phone numbers (like US 10DLC numbers) before sending A2P (Application-to-Person) messages. Some regions (like India or China) may also require pre-registering message templates.
  • Benefits:
    • Compliance: Ensures adherence to local telecommunication laws and carrier requirements.
    • Improved Deliverability: Registered traffic is often treated with higher priority and is less likely to be filtered as spam by carriers.
  • When Needed: Registration requirements — or lack thereof — vary significantly by country (e.g., US 10DLC, UK Sender IDs, India Sender IDs) and the type of number/Sender ID used. While some origination identities in certain regions may not require pre-registration, the landscape is complex and evolving. Always check the AWS documentation for the specific, current requirements of the countries you send messages to. AWS End User Messaging provides tools within the console and API to help manage any necessary registrations.

Additional Key Differences & Benefits

  • MMS Support: The AWS End User Messaging v2 API provides clear, first-class support for sending Multimedia Messaging Service (MMS) messages via the SendMediaMessage API call, offering richer media possibilities than typically available via the older Pinpoint API.
  • API Simplicity: The SendTextMessage API call is significantly less nested and complex than the SendMessages API structure, making integration and maintenance easier.
    • Example Comparison:
    • # Pinpoint v1 SendMessages (Nested Structure)
      response = pinpoint_client.send_messages(
          ApplicationId='YOUR_PINPOINT_PROJECT_ID',
          MessageRequest={
              'Addresses': {
                  '+12065550100': { # Destination Address
                      'ChannelType': 'SMS'
                  }
              },
              'MessageConfiguration': {
                  'SMSMessage': {
                      'Body': 'Your message content',
                      'MessageType': 'TRANSACTIONAL',
                      'OriginationNumber': '+12065550199' # Origination Number
                  }
              }
          }
      )
      
      # AWS End User Messaging v2 SendTextMessage (Flatter Structure)
      response = end_user_messaging_client.send_text_message(
          DestinationPhoneNumber='+12065550100',
          OriginationIdentity='+12065550199', # Can be Number, SenderID, Pool ARN/ID
          MessageBody='Your message content',
          MessageType='TRANSACTIONAL'
          # Optional: ConfigurationSetName='MyConfigSet'
      )

      This side-by-side comparison clearly shows the reduced nesting and more direct parameter usage in the AWS End User Messaging SendTextMessage API call.

  • Broader Regional Availability: The AWS End User Messaging v2 API offers significantly broader regional availability compared to the older Pinpoint v1 API (currently supported in over 30 regions versus 13). AWS also plans to expand this support to an additional 4 regions soon (reaching 34 total), further improving global reach and potentially reducing latency.

How to Use AWS End User Messaging Features Functionally (API Examples)

Here’s how you use the SendTextMessage API (using AWS SDK for Python Boto3 as an example) to leverage these features:

import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Initialize the AWS End User Messaging v2 client
# Note the client name change from 'pinpoint'
end_user_messaging_client = boto3.client('pinpoint-sms-voice-v2')

# --- Basic SMS Send ---
try:
    response = end_user_messaging_client.send_text_message(
        DestinationPhoneNumber='+12065550100',
        OriginationIdentity='+12065550199', # Your AWS End User Messaging registered Phone Number, Sender ID, or Pool ARN/ID
        MessageBody='Hello from AWS End User Messaging!',
        MessageType='TRANSACTIONAL' # Or 'PROMOTIONAL'
    )
    logger.info(f"Basic Send - Message ID: {response.get('MessageId')}")
except Exception as e:
    logger.error(f"Basic Send Failed: {e}")

# --- Send with a Configuration Set (for DLRs/Events) ---
try:
    response = end_user_messaging_client.send_text_message(
        DestinationPhoneNumber='+12065550101',
        OriginationIdentity='+12065550199',
        MessageBody='This message uses a configuration set.',
        MessageType='TRANSACTIONAL',
        ConfigurationSetName='MyConfigSet' # Specify your Configuration Set
    )
    logger.info(f"Config Set Send - Message ID: {response.get('MessageId')}")
except Exception as e:
    logger.error(f"Config Set Send Failed: {e}")

# --- Send using a Phone Pool ---
try:
    response = end_user_messaging_client.send_text_message(
        DestinationPhoneNumber='+12065550102',
        OriginationIdentity='arn:aws:sms-voice:us-east-1:111122223333:pool/MyPhonePool', # Use Pool ARN or ID
        MessageBody='This message is sent via a phone pool.',
        MessageType='TRANSACTIONAL',
        ConfigurationSetName='MyConfigSet' # Still need a Config Set for events
    )
    logger.info(f"Pool Send - Message ID: {response.get('MessageId')}")
except Exception as e:
    logger.error(f"Pool Send Failed: {e}")

# --- Send with a Protect Configuration (via Config Set or directly) ---
# Option 1: Protect Config applied via Configuration Set
# (Configure association in the AWS End User Messaging console or via AssociateProtectConfiguration API)
# No change needed in SendTextMessage call beyond specifying the ConfigurationSetName

# Option 2: Protect Config applied directly per message
try:
    response = end_user_messaging_client.send_text_message(
        DestinationPhoneNumber='+12065550103',
        OriginationIdentity='+12065550199',
        MessageBody='This message has direct protect config applied.',
        MessageType='TRANSACTIONAL',
        ProtectConfigurationId='MyProtectConfig' # Specify Protect Configuration ID or ARN
        # ConfigurationSetName='MyConfigSet' # Can also be used if needed for other rules like events
    )
    logger.info(f"Protect Config Send - Message ID: {response.get('MessageId')}")
except Exception as e:
    logger.error(f"Protect Config Send Failed: {e}")

# --- Standard Exception Handling ---
try:
    response = end_user_messaging_client.send_text_message(
        DestinationPhoneNumber='+12065550104',
        OriginationIdentity='+12065550199',
        MessageBody='Testing exception handling.',
        MessageType='TRANSACTIONAL',
        ConfigurationSetName='MyConfigSet'
    )
    logger.info(f"Exception Test Send - Message ID: {response.get('MessageId')}")
except end_user_messaging_client.exceptions.ThrottlingException:
    logger.error("Rate limit exceeded. Implementing backoff.")
except end_user_messaging_client.exceptions.ValidationException as e:
    logger.error(f"Validation error: {str(e)}")
except Exception as e:
     logger.error(f"Generic error sending message: {e}")

How to Migrate SDKs

Migrating your application code involves updating your AWS SDK initialization:

  1. Identify SDK Usage: Locate where your code uses the AWS SDK to interact with the Pinpoint v1 API, specifically for sending SMS (likely using client.send_messages(...)).
  2. Update Client Initialization: Change the service client you initialize.
    • Python (Boto3): Change boto3.client('pinpoint') to boto3.client('pinpoint-sms-voice-v2').
    • Other SDKs: Consult the specific AWS SDK documentation for the equivalent change. The service identifier will typically change from pinpoint or similar to pinpoint-sms-voice-v2 or equivalent.
  3. Update API Calls: Replace calls to the Pinpoint v1 SendMessages operation with calls to the AWS End User Messaging v2 SendTextMessage operation, adjusting the parameter structure as shown in the examples above.
  4. Dependencies: Ensure your application deployment includes the necessary updated SDK libraries.

Data Migration Considerations

Endpoint Contextual Data: Pinpoint allows associating rich attributes and user data with endpoints, often used in campaigns. If your application logic for sending direct SMS via the Pinpoint SendMessages API previously relied on accessing these Pinpoint endpoint attributes at the time of sending (e.g., for personalization), note that the AWS End User Messaging SendTextMessage API operates independently of the Pinpoint endpoint data model. Your application will now need to fetch any required contextual data (user attributes, preferences, etc.) itself before calling SendTextMessage if that information is needed for message construction or logic.

Opt-Out Lists (Optional):

IMPORTANT: End User Messaging has automatically been adding opt-outs to a “default optout list” for all SMS you have sent out unless you have been self managing opt-outs. Check to see if you have numbers in the “default” list in the console or by using DescribeOptedOutNumbers and using “default” as the OptOutListName.

If you are managing opt-outs at the endpoint level, managing them within your application, or only have opt-outs in the “default” list, it’s recommended that you export those numbers into a new End User Messaging Opt-Out List.

  1. Extract from Pinpoint: Identify and extract the phone numbers opted out of SMS within your Pinpoint project. This typically involves exporting endpoint data (using the Pinpoint API, like GetEndPoints, or GetSegmentExportJobs) and filtering for endpoints associated with the SMS channel that have an OptOut status set (e.g., ALL). You may need custom processing to isolate the correct phone numbers.
  2. Create AWS End User Messaging List: Create a new opt-out list in AWS End User Messaging using the CreateOptOutList API operation (e.g., name it MigratedPinpointOptOuts).
  3. Import Numbers: Add the phone numbers extracted from Pinpoint into the newly created AWS End User Messaging opt-out list using the PutOptedOutNumber API operation for each number.
  4. Associate List: Associate your new AWS End User Messaging Opt-Out List with the relevant Phone Pool(s) or individual origination phone number(s)/Sender ID(s) using the appropriate AWS End User Messaging API calls (e.g., SetDefaultPoolOptOutList, SetPhoneNumberOptedOut). This ensures AWS End User Messaging automatically blocks sends to these numbers when using those specific origination identities. Note: Opt-out lists are associated with origination identities, not directly with Configuration Sets.

Here’s an accurate AWS SDK for Python (Boto3) example that demonstrates this process:

import boto3

# Initialize clients
pinpoint = boto3.client('pinpoint')
eum = boto3.client('pinpoint-sms-voice-v2')

# Step 1: Extract opted-out numbers from Pinpoint
def get_opted_out_numbers(project_id):
    opted_out_numbers = set()
    paginator = pinpoint.get_paginator('get_endpoints')
    
    for page in paginator.paginate(ApplicationId=project_id):
        for item in page['ItemResponse'].values():
            if item['ChannelType'] == 'SMS' and item.get('OptOut') == 'ALL':
                opted_out_numbers.add(item['Address'])
    
    return opted_out_numbers

# Example usage
project_id = 'YOUR_PINPOINT_PROJECT_ID'
opted_out_numbers = get_opted_out_numbers(project_id)

# Step 2: Create AWS End User Messaging Opt-Out List
opt_out_list_name = 'MigratedPinpointOptOuts'
eum.create_opt_out_list(OptOutListName=opt_out_list_name)

# Step 3: Import Numbers to the new Opt-Out List
for number in opted_out_numbers:
    eum.put_opted_out_number(
        OptOutListName=opt_out_list_name,
        OptedOutNumber=number
    )

# Step 4: Associate the Opt-Out List with a Phone Pool
phone_pool_id = 'YOUR_PHONE_POOL_ID'
eum.set_default_pool_opt_out_list(
    PhonePoolId=phone_pool_id,
    OptOutListName=opt_out_list_name
)

# If you're using individual numbers not in a pool:
# phone_number = 'YOUR_PHONE_NUMBER'
# eum.set_phone_number_opted_out(
#     PhoneNumber=phone_number,
#     OptOutListName=opt_out_list_name
# )

print(f"Migration complete. {len(opted_out_numbers)} numbers added to the opt-out list.")

Conclusion

Migrating from the legacy Amazon Pinpoint v1 SendMessages API to the modern AWS End User Messaging v2 SendTextMessage API aligns strategically with End User Messaging, the focus of AWS’s ongoing messaging development and advancements. As we’ve explored, this transition is driven by tangible benefits and enhanced capabilities designed for contemporary communication needs.

This guide detailed the key advantages, including a significantly simplified API structure that streamlines development and maintenance. We also covered the core components that provide enhanced control and functionality: Configuration Sets, which are crucial for enabling detailed monitoring and delivery reporting (DLRs); Phone Pools for flexible and reliable sender identity management; Protect Configurations for improved security and compliance; and Registrations for adhering to regional requirements and maximizing deliverability.

This post also outlined the practical steps involved in this migration, from updating your SDK client initialization and adapting your code to use the SendTextMessage API with its new features, to the critical process of migrating existing opt-out lists to ensure continuity and compliance.

By understanding these components, leveraging the new features, and executing the necessary technical and data migration steps, you can successfully transition your SMS operations. This move not only modernizes your infrastructure but also positions you to take full advantage of future advancements on the AWS End User Messaging platform, enabling you to build more robust, scalable, and sophisticated messaging solutions.

SMS Onboarding for SaaS, ISV, and Multi-Tenant Applications with AWS End User Messaging

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/sms-onboarding-for-saas-isv-and-multi-tenant-applications-with-aws-end-user-messaging/

Introduction

SMS messaging continues to be one of the most reliable and effective communication channels. However, for Software as a Service (SaaS) companies, Independent Software Vendors (ISVs), and multi-tenant solution providers looking to incorporate SMS capabilities into their offerings, the journey can be complex and filled with challenges.

This guide is specifically designed for technology providers—whether you’re a SaaS company, an ISV, or any platform that enables your customers to send SMS messages to their end users. Throughout this article, the following terminology will be used:

  • Provider: An organization offering SMS capabilities as part of your product or service
  • Customer: The entities using Provider technology to send SMS messages
  • End User: The recipients who opt in to receive SMS messages from Customers

The landscape of SMS implementation can be complicated, with varying country-specific regulations, lengthy registration processes that can take weeks or even months, different originator types (Long Code, Short Code, Sender ID, etc.) with unique capabilities, and the diverse needs of Customers and End Users. These challenges are amplified when you’re a Provider offering SMS services to your own Customers, who in turn serve their End Users.

By the end of this guide, you’ll understand:

  • How opt-in influences architecture
  • Options for how to structure your SMS offering to Customers
  • Strategies for reducing friction in the SMS implementation process

Let’s dive in.

The Registration Dilemma: Who Owns the Relationship?

One of the most critical decisions for your SMS Originator registration is determining whose information is used to apply. The biggest mistake AWS sees Providers make is not knowing how their relationship with their Customers and their Customers’ End Users affects their architecture and how they complete any registrations that are necessary.

Mobile carriers want to know who will be sending SMS to their customers, how that entity will opt them in, and what content they will be sending. When registering for originators, especially in the United States, you will need to succinctly explain how End Users will opt in and how that data will not be shared with any third parties. Your architecture must ensure:

AWS consistently sees Providers register themselves when obtaining an Originator when they do not have a relationship with their Customers’ End Users. The decision of whose information belongs in the registration hinges primarily on a fundamental question: Who does the End User believe they’re entering into a relationship with when they provide their phone number?

The most common scenarios are below:

Scenario 1: End Users interact with the Customer’s brand only

In most cases, End Users are completely unaware of your existence as the Provider. They believe they’re opting in to receive messages from your Customer directly. In this scenario:

  • Registration should be completed using the Customer’s information. There are many ways you can facilitate this process and some ways to reduce this common friction point will be discussed later in this post.
  • Messages should appear to come from the Customer, not the Provider, your service name should not appear in messaging

Scenario 2: End Users explicitly opt in through the Provider application

In some cases, End Users clearly understand they’re opting in to receive messages via your technology platform, on behalf of your Customer. The opt-in data will not be shared with your Customers and your brand, as the Provider, will be the named entity in all SMS sent.

There are a number of ways that this can happen:

  • End Users could opt in using a widget you build that your Customers install on their site or in their app
  • A paper form or verbal script that you supply that clearly identifies you, the Provider

AWS commonly sees this occurring with Providers that supply:

  • Third-party payment processing
  • Shipping and logistics support
  • Customer service platforms
  • One-Time Password (OTP) capabilities

In this scenario your company name would typically appear in the messaging and registration would use your company information.

NOTE: There are edge cases to these two scenarios but the implementation can be complicated, so if you are a Provider and you don’t think that you fit into these two scenarios above make sure to reach out to your Account Manager, open a case, or speak to a specialist before starting to implement anything.

Architectural Models for SMS Implementation

Let’s explore various architectural models for structuring your SMS offering based on your business needs and Customer relationships. Each model has distinct characteristics in the following areas:

1. “Bring Your Own AWS Account” Model

Who does the registration and configuration?

  • The Customer connects their own AWS account, so the registration and any configuration happens in the Customer account.
  • Usually in this scenario the information that is input into the registration is the Customer’s since it’s their account

Customer responsibilities:

  • Customer handles all registration and configuration requirements themselves
  • Customer integrates their account with the Provider service
  • Customer manages sending, opt-out lists, etc.
  • Pays the AWS bill

Provider responsibilities:

  • The Provider offers a user-friendly interface that calls the AWS End User Messaging Service APIs using the Customer’s credentials.
  • The depth of services offered by the Provider can vary

Best for: Technical Customers who want full control and already use AWS; Providers who want to avoid registration and configuration complexities.

2. Provider Account – Manual Registration and Configuration

Who does the registration and configuration?

  • The Provider owns the account and is not providing the Customer with a way to submit their own information so the Provider must enter the information
  • The Customer’s information is captured manually
  • The Provider handles the complexity of registration and configuration through the console

Customer responsibilities:

  • Provide necessary information to the Provider for registration purposes

Provider responsibilities:

  • Captures the registration information manually from Customers.
  • Manages the complexity on behalf of your Customers.

This can be implemented either with separate AWS accounts for each Customer or a multi-tenant architecture in a single account.

Best for: Providers with a small number of high-value Customers who need hand-holding through the SMS implementation process.

3. Semi-Automated Solution – Customer Sending

Who does the registration and configuration?

  • The Provider builds a way for the Customer to submit their registration information, which the Provider then programmatically submits to carriers/regulators.

Customer responsibilities:

  • Your platform manages the technical configuration and provides sending capabilities, but the Customer is responsible for maintaining compliance.

Provider responsibilities:

  • You provide a streamlined way for Customers to submit registration information (webhooks, forms, APIs).
  • You programmatically submit the registration data to carriers/regulators.
  • You manage the technical configuration and provide sending capabilities.

Best for: Providers with moderate technical sophistication who want to reduce friction while maintaining separation of regulatory responsibilities.

4. Fully Automated Solution – Provider Sending

Who does the registration and configuration?

  • The Customer’s information is used in the registration, which you handle programmatically.

Customer responsibilities:

  • You handle all technical aspects of registration, but the Customer is still responsible for maintaining messaging compliance.

Provider responsibilities:

  • You provide hosted, customizable Terms & Conditions and Privacy Policies for each Customer that are compliant out of the box.
  • You offer compliant opt-in pathways (web forms, verbal scripts, etc.).
  • You handle all technical aspects of registration.

Best for: Large-scale Providers serving many Customers with varying levels of technical sophistication.

5. Template-Restricted Fully Automated Messaging

Who does the registration and configuration?

  • The Customer’s information is used in the registration, which you handle programmatically.

Customer responsibilities:

  • You manage all regulatory compliance centrally, and the Customer can only personalize specific fields in pre-approved message templates.

Provider responsibilities:

  • You provide a suite of pre-approved message templates.
  • You manage all regulatory compliance centrally.
  • You simplify the registration process since the content is tightly controlled.

Best for: Use cases with predictable messaging needs like appointment reminders, shipping notifications, or one-time passwords.

6. Fully Managed Programs

Who does the registration and configuration?

  • The Customer authorizes you to send messages on their behalf, so you own the relationship with the end-user and the registration.

Customer responsibilities:

  • Only required to give you any pertinent information necessary for you to send messages to the End-Users. This could be things like tracking numbers or other information that the particular use case requires and is part of the personalization that is allowed.

Provider responsibilities:

  • You manage all aspects of the end-user relationship.
  • You control the entire messaging experience, including opt-in collection and the end-user relationship.

Example: A shipping notification service might send messages like: “ShipTrack: Your order from ACME Corp will arrive tomorrow. Track at [link]”

Best for: Specialized use cases where your platform adds significant value as an identified intermediary.

Shaping Your SMS Offering: Strategic Considerations

Pricing Strategies

When incorporating SMS into your product, one of the first considerations is how to structure your pricing. Unlike many digital services with predictable costs, SMS pricing varies significantly based on destination country, originator type, and volume.

AWS End User Messaging Service bills based on volume sent per country, with each country having its own price point. This pricing is determined by the recipient’s handset country code, not their physical location. This means that even if you primarily serve U.S. based Customers, you may need to account for international rates when recipients have non-U.S. phone numbers.

There are also one-time and ongoing fees to be accounted for. Registrations often have one-time processing fees and Originators can have leasing costs that range from free to more than $1,000 a month for short codes in some countries. Make sure that you think through how those costs will or will not be passed to your Customers.

As you design your pricing model, consider these common volume based approaches:

  • SMS Credits: Create a standardized credit system where Customers purchase credits regardless of destination country. You would internally manage the conversion between credits and actual costs.
  • Dollar-Based Allocation: Provide Customers with a budget that gets depleted based on actual costs per message sent.
  • Tiered Country Pricing: Group countries into tiers (e.g., Tier 1 for North America, Tier 2 for Western Europe) with different pricing for each tier.
  • Bundled Messaging: Include a certain number of messages in your base subscription with overage fees for additional messages.

Each approach has trade-offs in terms of simplicity, transparency, and risk management. Your decision should align with your overall business model and Customer expectations.

Geographic Considerations

Different countries have distinct regulatory requirements for SMS messaging, including:

  • Originator Support: Not all countries support all originator types, view the details here
  • Originator Selection: In cases where multiple types of originators are supported, how do you support your Customer in selecting the right originator for the right use case?
  • Read through this tutorial to help decide what originator(s) are right for your use case(s)
  • Registration: An increasing numbers of countries require you to register before being allowed to send
  • Quiet hours: Many countries restrict when promotional messages can be sent
  • Content restrictions: Certain types of content (gambling, alcohol, adult content, etc.) may be prohibited or heavily restricted. A more comprehensive list can be found here
  • Template requirements: Some jurisdictions require pre-approval of message templates
  • Sender ID regulations: Rules regarding who can use alphanumeric sender IDs vary widely

As a Provider, you need to decide which countries you’ll support and how you’ll ensure compliance across markets. This decision affects not just your pricing but your entire product architecture, especially if you serve global Customers.

Strategies to Reduce Implementation Friction

Implementing SMS can be complex for your Customers. Here are some strategies that can simplify and/or streamline the process. Some of these can be mixed and matched and could also be used as a value-add or even as a paid offering to your Customers:

Provider-Hosted Privacy Policy and/or Terms & Conditions

Create customizable, compliant templates for Privacy Policies and Terms & Conditions that your Customers can use. This ensures proper disclosure of SMS practices without requiring Customers to update their own legal documents.

Registration Webforms and Workflows

Develop user-friendly webforms that collect all required registration information in a guided process. These can significantly simplify complex registrations like 10DLC brand and campaign registration.

Below, Figures 1-3, you will find several examples of compliant forms that could be customized for your use:

Fig. 1

Fig. 2

Fig. 3

Pre-Approved Opt-In Widgets

Create embeddable widgets, such as Figures 1-3 above, that your Customers can add to their websites or apps that implement compliant opt-in processes. These can include all required disclosures and confirmations while being easy to integrate.

Template Libraries

Provide a library of pre-approved message templates for common use cases. This reduces compliance risks and simplifies the sending process for your Customers.

Testing Environments

Create sandbox environments where Customers can test their SMS implementation before going live. This helps catch issues with formatting, opt-in processes, or content compliance.

Documentation and Training

Develop clear documentation and training resources specific to each originator type and use case. This empowers your Customers while reducing support burden.

Conclusion

Incorporating SMS capabilities into your platform can enhance Customer engagement, but the journey can be complex. This guide has explored key considerations to help you navigate it successfully.

This post examined various architectural models, each with tradeoffs in Customer responsibilities and Provider responsibilities. This post reviewed strategic factors like pricing, geographic regulations, and originator types that must be carefully considered.
Finally, practical strategies to reduce implementation friction for Customers such as hosted compliance documents, streamlined registration workflows, and pre-approved templates, you can use to simplify the integration process were discussed .

The critical first step though, is understanding the relationship between you as the Provider, your Customers, and their End Users. This shapes whose information is used for originator registration, which in turn defines the SMS experience.

Ultimately, a successful SMS solution requires balancing technical, regulatory, and Customer-centric factors. Leveraging this guidance will equip you to design and deploy an offering that delights your Customers and their End Users.

Additional resources:

Defending Against SMS Pumping: New AWS Features to Help Combat Artificially Inflated Traffic

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/defending-against-sms-pumping-new-aws-features-to-help-combat-artificially-inflated-traffic/

As businesses increasingly rely on SMS messaging to engage customers, AWS End User Messaging is enhancing its SMS Protect feature to now include automated message filtering based on the risk of Artificially Inflated Traffic (AIT) from each message request. This new capability helps protect against AIT, also known as SMS pumping. AIT occurs when malicious actors use bots and other measures to generate fake SMS traffic, targeting businesses’ customer communication workflows like one-time password triggers, app downloads, and promotional signups. In a recent report co-authored by Enea it was shown that AIT accounted for 19.8 billion to 35.7 billion fraudulent SMS messages in 2023, costing over $1 billion. All workflows with user generated messages are susceptible to AIT but insecure public webforms are the most commonly used as a vector to exploit and generate SMS messages. The goal is to artificially inflate the number of SMS messages a business sends, resulting in increased costs and a negative impact on the sender’s reputation.

We launched AWS End User Messaging Protect to help our customers combat this growing threat. Initially launched with Country Level Blocking, we’ve now launched two new features, called Monitor and Filter, within AWS End User Messaging’s Protect capabilities. Updating your current security posture for SMS with Monitor and Filter, along with adhering to some other best practice security measures we will cover later, will make it harder for bad actors to target and inflate your SMS costs with bots or other measures.

What is SMS Protect Filter and Monitor?

Filter and Monitor are the next layers of defense in our Protect Feature Set. These features are designed to provide enhanced protection against AIT for countries in which you need to send messages by analyzing and proactively blocking messages that are suspected to be fraudulent. The Filter setting blocks suspected AIT messages. The Monitor mode allows you to evaluate how Filter would affect your sending, without blocking. Monitor could also be used for the events it emits, which could be leveraged in your own custom AIT solutions, but again, does not automatically block messages.

Filter Mode: Automated Blocking of Suspected Artificial Traffic

The Filter mode in Protect takes your AIT mitigation efforts to the next level by automatically blocking messages that exhibit patterns of artificial inflation. When you set your configuration to “Filter” the model will automatically filter any messages being sent that match patterns indicative of AIT.

Filter mode provides automated defense against AIT by analyzing and proactively blocking AIT messages before they leave AWS, reducing your exposure to the financial and reputational impacts of SMS pumping. Turning on Filter at the Account level is the quickest way to protecting yourself. The tutorial below will walk you through configuration.

Importantly, when a message is blocked in Filter mode, you do not incur the normal per-message fees, instead you only pay for the lesser costs associated with the Protect Filter capabilities, providing a more cost effective approach to message security.

Monitor Mode: Gain Visibility and Insights into Potentially Suspicious Traffic

The Monitor mode in Protect works identical to filter, it uses the same AIT prediction models behind the scenes, but rather than blocking suspected AIT it simply emits recommendations for blocking based on the patterns of data. The recommendations are delivered in a new field attached to the Delivery Receipts (DLRs) that are already streamed via Event Destinations. The recommendations are also logged in summary to CloudWatch and the End User Messaging Console Dashboards. This provides you with valuable data and insights to help inform your AIT mitigation strategy.

Messages sent while in monitor mode will not be blocked and will be charged the country per message cost as well as the Protect Monitor per message cost.

If you want to see what our AIT prediction models recommend without AWS actually blocking messages, you can start in Monitor Mode and change to Filter when you are more comfortable. This allows you to understand how your traffic is analyzed by our AIT prediction models without immediately blocking messages, offering a cautious and informed approach to how Filter will affect your Account.

The Monitor mode reports include detailed analytics on blocked message volumes, geographic distribution, carrier patterns, and more. By analyzing this data, you can identify specific countries, number ranges, or sending behaviors that may be indicative of artificially inflated traffic. This helps you make informed decisions about where to apply more stringent controls.

Importantly, during the monitoring phase, Protect also provides recommendations on whether a particular message would have been blocked and whether certain numbers should be blocked in the future. This gives you the ability to fine-tune your configurations and better understand your traffic before taking enforcement actions.

How do you get started with Protect Monitor and Filter?

Every customer’s needs are unique, but for most customers, we suggest the following steps:

  1. Block all countries to which you do not send messages
    1. Your first line of defense should be to block all traffic to countries where you don’t conduct business or need to send messages. Preventing unwanted messages from being sent is the simplest way to help prevent SMS pumping in the first place. You can use Protect Country Blocking rules to do this and they can can be applied to SMS, MMS, and voice messages sent from your AWS account. For a tutorial on how to do this you can read this earlier blog on Protect.
  2. Create an account level “Filter” configuration
    1. When considering the risk of AIT in a specific country we recommend aligning risk level with the SMS per message cost. The higher the cost the higher the risk.
  3. Make sure that your forms and other vulnerable public facing messaging workflows are protected with best practice security measures that we will review further on in this post.

How to create a protect configuration

You can use a Protect configuration at different levels of granularity:

  1. As the default for your entire AWS account(Good for customers with a single use case)
  2. Associated with a specific Configuration Set
  3. Directly specified when calling the SendMediaMessage, SendTextMessage, or SendVoiceMessage APIs
    NOTE: You can only change your MMS country rules list through the AWS End User Messaging SMS and voice v2 API or AWS CLI. The Voice rules can be changed in the console but only after creating an SMS Protect Configuration. Once you have created your first Configuration you can edit it and select the “Voice Rules” tab.

The main benefit of Protect configurations is the ability to control where you send messages and avoid unexpected costs or compliance issues. By creating multiple configurations you can apply specific rules that control how messages are processed and delivered based on your unique business needs. Let’s walk through how to set them up.

Creating a Protect Configuration

  1. To create a Protect Configuration, log into the AWS Management Console and navigate to End User Messaging.
  2. From there, go to the “SMS” section and select “Protect configurations”.
  3. Click the “Create protect configuration” button and give your new configuration a name.
    1. Define the specific allow and block rules for SMS, MMS, and voice messages.
      1. Checking a box next to a country blocks that country and checking the box for a region will block all countries associated with that region.

Once you’ve configured the country rules, you can choose how to associate this Protect configuration:

  1. Set it as the default for your entire AWS account
    1. For many customers this should be the default. Having an account level configuration as a fallback helps protect you incase you forget to specify a protect configuration in your request.
    2. Note: To use a protect configuration with other AWS services to send messages, like Amazon SNS, Amazon Connect, or Amazon Pinpoint, you need to set your protect configuration as the account default
  2. Associate it with one or more Configuration Sets
    1. This setting will be applied anytime you send SMS with the config set associated with this Protect Configuration
  3. Leave it unassociated to use it explicitly in API calls
    1. This setting allows you to apply it whenever you want. This will override any previous associations when you reference the “ProtectConfigurationId” in your SendMediaMessage, SendTextMessage, or SendVoiceMessage calls

You can also add optional tags to help organize your resources.

  1. Click “Create protect configuration”
    1. NOTE: You can only change your MMS country rules list through the AWS End User Messaging SMS and voice v2 API or AWS CLI. The Voice rules can be changed in the console but only after creating an SMS Protect Configuration. Once you have created your first Configuration you can edit it and select the “Voice Rules” tab.
  2. How to add Filter or Monitor to the Protect Configuration you just created
    1. Click into the Protect Configuration you just created
      1. Note the “SMS Rules” tab and the “Voice Rules” tab can have different rule settings. Make sure you are editing the right channel
  3. You will once again select the country or region you wish to set to Filter(recommended) or Monitor

    1. Confirm the changes and you will see your changes in the next screen

Getting more granular with Protect Configurations

In most cases you should be using “Filter” account wide for the countries you are concerned about AIT in, but If you have different public and/or private messaging workflows you may benefit from a more precise, or granular, approach to your messaging and security practices. If you want more control, the first step is to identify your traffic that is a high risk for SMS pumping. Any public-facing forms or workflows that trigger SMS being sent are prime targets for attackers to try and pump SMS are at high risk, such as:

  • One-time passwords or 2FA flows
  • Password/User resets
  • New user registrations
  • Other

Creating a separate Protect Configuration for each of these different workflows will help the models in Protect more effectively identify anomalies and tailor its detection models to your specific messaging patterns. Service-initiated messages, such as appointment reminders or marketing campaigns that are not user-generated are at much less risk of SMS pumping attacks so you may decide not to include them in the same Protect config as a public facing workflow to reduce overall costs.

You can follow the directions above for creating a Protect Configuration for each of the workflows you identify. You might configure something like the below, where “OTP New Sign Up” and “Password Reset” have Filter enabled for the countries of concern and the “Marketing Newsletter” Configuration would not have either configured since that use case does not involve a publicly available form that triggers an SMS being sent. Creating a Protect Configuration for different use cases gives you more granular control over your messaging, your messaging budget, and ensuring the integrity of your communications

Updating an Existing Protect Configuration

After creating a Protect configuration, you may need to modify the country rules, change the association or as we saw above, add Filter or Monitor to certain countries. To do this, simply navigate back to the “Protect configurations” section and select the one you want to update.

From here you can edit the allow/block country lists, change the association, or even delete the configuration if needed. Just be careful with the account default – you’ll want to be sure you have another default in place before removing the existing one.

Using Protect Configurations

Once you have your Protect configurations set up, you can start putting them to use. If you’ve associated one with a Configuration Set, any messages sent using that Configuration Set will automatically have the Protect rules applied.

Alternatively, you can specify the ProtectConfigurationId parameter when calling the SendMediaMessage, SendTextMessage, or SendVoiceMessage APIs. This allows you to override the account default or Configuration Set association on a per-message basis.

Reporting on Protect Configurations

There are two places within the console that you can see metrics for your Protect Configurations. The Monitoring tab on a protect configuration provides an overview of message delivery metrics for the protect configuration. To view all metrics for your account in the AWS End User Messaging SMS console choose Dashboard in the left hand navigation. You can also use CloudWatch to view and create alarms. For more information on CloudWatch metrics, see Dashboard metrics, and Create CloudWatch Alarms.

Monitoring tab on a specific Protect Configuration

End User Messaging provides multiple charts that helps you understand how your country rule configurations (Allow, Block, Monitor, or Filter), along with phone number rule overrides are controlling SMS sending overall, and to specific countries.

The included charts are:

  • Number and Percentage of Blocked Messages: Shows the count and percentage of SMS and MMS messages that were blocked during the selected time period. This includes messages blocked by country rules set to ‘block’ or ‘filter’ mode, as well as messages blocked by phone number override rules.
  • Number of Blocked Messages by Country: Shows the count of SMS and MMS messages that were blocked during the selected time period, broken down by destination country.
  • Number and Percentage of Messages Recommended to Block: Shows the count and percentage of SMS and MMS messages that were identified as risky by the AIT risk prediction model. This includes messages in both ‘monitor’ and ‘filter’ modes. In monitor mode, these messages are delivered but flagged; in filter mode, these messages are blocked.
  • Number of Messages Recommended to Block by Country: Shows the count of SMS and MMS messages identified as risky by the AIT prediction model, broken down by destination country.

Implementing a Layered Approach to SMS Security

While Filter and Monitor are new tools in the fight against AIT, they should be implemented as part of a broader, layered security strategy for your SMS messaging infrastructure. Here are some best practices to consider:

Identify and compartmentalize Your Traffic

You are able to create multiple Protect Configurations based on different use cases, such as one-time passwords, marketing campaigns, and appointment reminders. This granular approach allows Protect’s prediction models to better understand your expected traffic patterns and identify anomalies more accurately. Once you have identified your traffic types you can assign different configurations to them. You may set a marketing configuration to not be filtered or monitored because it’s not user generated but an OTP type with a publicly available form you may want to set to Filter. In this way you save money by protecting only the messages that are more likely to be susceptible to AIT. Each of these may block the same countries but operate differently with regards to identifying and blocking potentially fraudulent traffic.

Leverage Geographic Controls:

Always start by blocking countries where you have no business presence, then allow-list the regions where you actively engage customers and have not seen AIT issues. For countries where you suspect potential abuse, utilize the Monitor mode to gather data before deciding on a blocking strategy.

Allow-list Legitimate phone numbers in countries you are blocking

To avoid impacting your critical messaging workflows, implement phone number rule overrides for specific countries where you are blocking traffic. As an example, if you have engineers in Columbia that you want to be able to send SMS to but you don’t have any legitimate reason other than that to send to Columbian handsets you can block Columbia but allow-list those engineer’s phone numbers. You can also provide your front end support teams the functionality to add numbers to allow-lists in case a number is mistakenly blocked by Filter recommendations

  1. To create a phone number override rule using the console, follow these steps:
  2. Open the AWS End User Messaging SMS console at https://console.aws.amazon.com/sms-voice/.
  3. In the navigation pane, under Protect, choose the Protect configuration you want to add allow-list numbers in
  4. Choose the Rule overrides tab and in the Rules override section choose Add override.
    1. In the Rule override details section, enter the following:
      1. For Destination phone number enter the phone number to create the rule for. The phone number must start with a ‘+’ and can’t contain any spaces, hyphens, or parentheses. For example, +1 (206) 555-0142 is not in the correct format, but +12065550142 is.
      2. For Override type choose either Always allow or Always block.
      3. For Expiration date – optional choose a date for the rule expire or leave it blank for the rule to never expire.
  5. Choose Add rule override.

Integrate with Complementary Security Services

Enhance your SMS security posture by integrating Protect with other AWS services, such as AWS Web Application Firewall (WAF) for web-based attack protection and Amazon Cognito for robust user authentication. See this post on Cognito Security for more detailed information on how to add self-service sign-up, sign-in, and control access features to your web and mobile applications while benefitting from SMS authentication and fraud protection with End User Messaging Protect Block, Monitor, and Filter.

WAF has out of the box support for complementary security protections such as CAPTCHA, IP blocking, and JA3 fingerprint matching which are all best practice features to help protect your public forms that may be at risk for SMS pumping.

Review and Iterate

Regularly review your Protect configurations, analyze false positive rates, and update your allow-lists and rules as your messaging patterns evolve. If you are satisfied with your blocking, leave it alone. If you want to get more precise and remove false positives, look for which protect configurations have identified suspected AIT, and try to make them more granular. For example, if you have a sign-up form that is currently being triggered from two separate web pages, you could have a config set for each of those pages and trigger a different config set with Filter mode activated for each. Maintaining an agile, data-driven approach is key to ensuring optimal balance between security and service availability for your legitimate customers.

Conclusion

Take a proactive, multilayered approach to combating the growing threat of SMS fraud by leveraging the new Filter and Monitor capabilities within AWS End User Messaging Protect. These features empower you to gain visibility into potentially malicious traffic, automate the blocking of suspected AIT, and protect your messaging infrastructure while preserving the seamless experience your customers expect.

To get started with Protect and explore these new features, visit the AWS End User Messaging documentation or reach out to your AWS account team. We’re here to help you strengthen the security and integrity of your SMS communications.

Automating Sender ID Configuration for SMS with AWS End User Messaging APIs

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/automating-sender-id-configuration-for-sms-with-aws-end-user-messaging-apis/

Global SMS messaging with consistent Sender ID branding requires configuring the same Sender ID across multiple countries, which is a time-consuming process for businesses operating internationally. In this post, we’ll show you how to automate the configuration of Sender IDs for countries that do not have registration requirements using the AWS End User Messaging v2 API.

The Challenge of Multi-Country Sender ID Configuration

When sending SMS messages internationally, if you are using Sender ID, you want your brand to be consistently recognized. This means configuring the same Sender ID in each country you send to. However there are several challenges related to this:

  • Each country must be done manually, one at a time, if using the AWS Console
  • If you have multiple environments for testing the process must be repeated for each Account/Region
  • If you are moving account/regions you have to reconfigure each country in the new Account/Region
  • Manual configuration can be error prone
  • Errors can be detrimental to a brand

The Solution: AWS Lambda Automation

This solution can be applied to any country that supports Sender ID configurations and does not require registration. You can view a comprehensive list of these eligible countries here.

Below is an AWS Lambda function that streamlines this process by handling bulk configuration requests. The function solves the challenges in handling multiple country configurations in a single automated workflow. Here’s the complete code:

import boto3
import uuid
import json
import time
from typing import Dict, Any, List

def validate_input(sender_id: str, countries: List[str]) -> bool:
    if not 1 <= len(sender_id) <= 11:
        raise ValueError("Sender ID must be between 1 and 11 characters")
    
    if not sender_id.replace('_', '').replace('-', '').isalnum():
        raise ValueError("Sender ID can only contain alphanumeric characters, underscore, and hyphen")
    
    if not countries:
        raise ValueError("At least one country code must be provided")
    
    return True

def request_sender_id(client, sender_id: str, countries: List[str], message_types: List[str] = None, tags: List[Dict] = None) -> List[Dict]:
    if message_types is None:
        message_types = ["TRANSACTIONAL", "PROMOTIONAL"]
    
    results = []
    
    for i, country in enumerate(countries):
        if i > 0:
            time.sleep(1)  # Rate limiting: 1 request per second
            
        try:
            print(f"Processing country: {country} ({i+1}/{len(countries)})")
            request_params = {
                'ClientToken': str(uuid.uuid4()),
                'SenderId': sender_id,
                'IsoCountryCode': country.upper(),
                'MessageTypes': message_types,
                'DeletionProtectionEnabled':True
            }
            
            if tags:
                request_params['Tags'] = tags
                
            response = client.request_sender_id(**request_params)
            
            results.append({
                'Country': country,
                'Status': 'Success',
                'SenderIdArn': response.get('SenderIdArn'),
                'MonthlyLeasingPrice': response.get('MonthlyLeasingPrice')
            })
            
        except Exception as e:
            results.append({
                'Country': country,
                'Status': 'Failed',
                'Error': str(e)
            })
            
        print(f"Completed {country}: {'Success' if results[-1]['Status'] == 'Success' else 'Failed'}")
    
    return results

def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
    try:
        # Extract parameters from event
        sender_id = event['sender_id']
        countries = [c.strip().upper() for c in event['countries'] if c.strip()]
        tags = event.get('tags')  # Optional
        message_types = event.get('message_types', ["TRANSACTIONAL", "PROMOTIONAL"])  # Optional
        
        # Validate input
        validate_input(sender_id, countries)
        
        # Initialize the AWS SMS Voice v2 client
        client = boto3.client('pinpoint-sms-voice-v2')
        
        # Process the request
        results = request_sender_id(
            client=client,
            sender_id=sender_id,
            countries=countries,
            message_types=message_types,
            tags=tags
        )
        
        # Calculate summary
        successful = sum(1 for r in results if r['Status'] == 'Success')
        
        return {
            'statusCode': 200,
            'body': {
                'results': results,
                'summary': {
                    'total': len(countries),
                    'successful': successful,
                    'failed': len(countries) - successful
                }
            }
        }
        
    except Exception as e:
        return {
            'statusCode': 500,
            'body': {
                'error': str(e)
            }
        }

How the Lambda Function Works to Configure Sender IDs

The Lambda function automates the Sender ID configuration process through these key steps:

  • Input Validation: Ensures the Sender ID meets format requirements (1-11 alphanumeric characters, with optional underscores or hyphens).
  • Bulk Registration: Processes each country sequentially with built-in rate limiting (1 request per second) to prevent API throttling.
  • Logging: Returns the full ARN of each successfully configured Sender ID
  • Flexible Configuration Settings:
    • Supports multiple message types (transactional, promotional, or both)
    • Enables resource tagging for organizational and cost tracking
    • Provides deletion protection to prevent accidental removal
  • Cost Transparency: Displays monthly leasing price for each successful country configuration
  • Error Handling: Individual country failures don’t halt the entire process, allowing partial success if a single country were to fail for some reason.

Using the Lambda Function

To use this function, create a Lambda with the code above and configure an event. The tags are optional and we have provided an example below:
NOTE: Depending on the number of countries you are attempting to register at a time, you may need to increase the 3 second default Lambda timeout. For reference, in our testing, we were able to do all Sender IDs(160) in less than 3 minutes.

Test Event Example

{
    "sender_id": "YourBrand",
    "countries": ["GB", "DE", "FR"],
    "tags": [
        {
            "Key": "Environment",
            "Value": "Production"
        },
        {
            "Key": "Department",
            "Value": "Marketing"
        }
    ]
}

IAM Permissions

Your Lambda will need these minimum AWS Identity and Access Management (IAM) permissions, scale back the resource if necessary:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sms-voice:RequestSenderId",
                "sms-voice:TagResource"
            ],
            "Resource": "arn:aws:sms-voice:*:**ACCOUNT#**:sender-id/*"
        }
    ]
}

The Trust Policy required for Lambda to assume the role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Results Example

The Lambda will return results for each country, including configuration status and monthly costs, if any. Below you will see an example of 3 countries being configured:


{
  "statusCode": 200,
  "body": {
    "results": [
      {
        "Country": "GB",
        "Status": "Success",
        "SenderIdArn": "arn:aws:sms-voice:us-west-2:**ACCOUNT#**:sender-id/LAMBDATEST2/GB",
        "MonthlyLeasingPrice": "0.00"
      },
      {
        "Country": "DE",
        "Status": "Success",
        "SenderIdArn": "arn:aws:sms-voice:us-west-2:**ACCOUNT#**:sender-id/LAMBDATEST2/DE",
        "MonthlyLeasingPrice": "0.00"
      },
      {
        "Country": "FR",
        "Status": "Success",
        "SenderIdArn": "arn:aws:sms-voice:us-west-2:**ACCOUNT#**:sender-id/LAMBDATEST2/FR",
        "MonthlyLeasingPrice": "0.00"
      }
    ],
    "summary": {
      "total": 3,
      "successful": 3,
      "failed": 0
    }
  }
}
Function Logs:
START RequestId: 81d2d144-9023-413d-b976-c87c79a82eae Version: $LATEST
Processing country: GB (1/3)
Completed GB: Success
Processing country: DE (2/3)
Completed DE: Success
Processing country: FR (3/3)
Completed FR: Success

After processing your Sender ID configurations, it’s crucial to verify them. You can do this via the AWS console or by using the DescribeSenderIds API. This API offers flexible retrieval options:

  • Specify individual Sender IDs for targeted information
    • Providing an invalid Sender ID will result in an error
  • Apply filters to narrow your results
  • Retrieve all Sender IDs associated with your AWS account by omitting both

Conclusion

Automating Sender ID configuration with the AWS End User Messaging v2 API and a Lambda function will dramatically reduce the time spent on manual configuration, ensure consistent branding across all supported and configured countries, and simplify a complex process. You’ll gain a scalable, reliable solution that allows you to deploy and manage your Sender IDs with confidence.

Additional resources:

AWS End User Messaging SMS documentation

SMS V2 API

Improving email security with Amazon SES Mail Manager and Hornetsecurity’s Vade Advanced Email Security Add On

Post Syndicated from Zip Zieper original https://aws.amazon.com/blogs/messaging-and-targeting/improving-email-security-with-amazon-ses-mail-manager-and-hornetsecuritys-vade-advanced-email-security-add-on/

Email continues to be a critical communication channel for businesses, powering essential communications across time zones and locations. But as cyber threats grow more sophisticated, how can organizations protect their most vulnerable communication channel? With the increasing complexity of email-based security risks, businesses need robust solutions to safeguard their digital communications. Today, we’re excited to announce the launch of Hornetsecurity’s Vade Advanced Email Security Add On for Amazon Simple Email Service (SES) Mail Manager, a powerful new tool in the fight against email-borne threats.

Amazon SES: Powering email communication at scale

Amazon SES is a cloud-based email service that helps you automate high-volume email communications seamlessly. In May 2024, we launched Mail Manager, introducing email relay and gateway features that help you manage email traffic, ensure compliance and enforce corporate policies. The launch also included an introduction to Mail Manager Email Add Ons which provides optional access to a collection of powerful security tools from certified providers that help you manage and filter incoming emails. Add Ons from our partners deliver advanced email security with flexible, meter-based pricing that is easily activated and integrated into your email workflows directly from the Mail Manager console or Mail Manager APIs.

In this blog, we’ll introduce Hornetsecurity’s Vade Email Add On for Amazon SES Mail Manager, and demonstrate how to enable its advanced email security capabilities to help protect your critical email communications.

Introducing the Vade Email Add On by Hornet Security

Hornetsecurity, a global leader in email security, produces next-generation cloud-based security, compliance, backup, and security awareness solutions that help companies and organizations of all sizes around the world. Its email filters process billions of emails daily, using a vast global email database to power their artificial intelligence (AI) engine. This approach allows the Vade Email Add On to continuously refine and adapt to the latest email threats and filter-bypassing techniques.

The Vade Email Add On brings Vade’s expertise directly to you, providing a seamless and powerful email security solution within the familiar AWS environment:

“Enhance your email service with advanced cybersecurity capabilities by integrating Vade Email Security’s state-of-the-art filtering solution. This Add On empowers users with automated, real-time defense against spam, malware, and phishing—ensuring safer communication. Vade’s AI-powered technology employs a multi-layered approach—combining heuristics, behavioral analysis, and natural language processing—to analyze messages in real time. Strengthen your platform by ensuring ongoing protection against evolving cyber threats.”

Advanced Email Security with the Vade Add On for Mail Manager

Hornetsecurity’s Vade Add On for Mail Manager provides automated, real-time defense against spam, malware, and phishing, which help ensure safer communication, including:

  • Advanced Threat Detection: Identifies and blocks sophisticated phishing attempts, malware, and ransomware, providing comprehensive protection against a wide range of cyber threats.
  • Behavioral Analysis: Examines the behavior patterns of message senders and content based on over 130 potential data points in each message to detect anomalies and potential threats.
  • Patented AI Technology: Leverages proprietary AI algorithms to analyze communication patterns and detect misuse of your service’s digital assets. This technology is powered by our global network of over 1 billion protected mailboxes.
  • Real-Time Scanning: Instantly analyze attachments without delaying delivery, thanks to its real time code interpreter.
  • Ease of Use: Seamless integration with Mail Manager rules, scanning only messages that meet specific criteria.

The Vade Email Add-On integrates with Mail Manager’s rules engine. This engine routes messages based on Vade’s scan results and optional detailed verdicts. These verdicts enable precise categorization and handling of incoming emails, improving security and email management.

Configure the Vade Email Add On

In the following example, we’ll walk thru the steps needed to subscribe and configure a rule set with two rules that are processed in priority order:

  • Rule 1drop-all-malicious-emails This rule has a condition that uses Vade to scan all incoming email and identify messages that are malicious (contain malware or phishing). These messages are then processed by Rule 1’s “Drop action“. Messages that are deemed “safe” are passed to Rule 2 after automatically being inspected and marked as “likely to be spam”, or “not-spam”.
  • Rule 2forward-to-mailbox Messages passed into Rule 2 are immediately forwarded to the user’s mailbox. In our example, we’re using Amazon WorkMail and Mail Manager’s built-in “Deliver to mailbox” action.
    • The Vade Add On also distinguishes between spam and clean email, and automatically adds a corresponding header to each message (see below) that can be used to route spam into the user’s “junk” folder.
      • X-SES-Vade-Advanced-Email-Security-AddonVerdict: spam:high
    • Thanks to the seamless integration between Mail Manager Add Ons and WorkMail, messages marked as spam are automatically sent to the user’s Junk folder, enhancing both security and user experience.

Vade Email Add On workflow

Follow the steps below to configure the Vade Email Add On using the Amazon SES console for the simple mail flow described above (note – the SES Mail Manager API can be used in lieu of the console).

  1. Open the Amazon SES console and in the left navigation rail, expand Mail Manager and click Email Add Ons.
  2. Select the Vade Add On, read the description. Click Subscribe and read the Terms and Conditions. Click Subscribe again to activate the Vade Advanced Email Security Add On in your SES account.
    • Pricing is detailed in the Email Add On description page. When this blog was published the price per 1,000 emails processed = $0.415 USD (subject to change, please refer to SES Pricing for the most up to date information).

Vade Email Add On

  1. In the left navigation rail under Mail Manager, click Rule Sets.
  2. Create a new Rule set ( process-via-vade ) (or modify an existing Rule set).
    1. Create a rule ( drop-all-malicious-emails )
    2. Under Rule conditions, click select property and select Vade Advanced Email Security Category from the drop-down menu (note the property modifiers allow for increasingly detailed inspection / results for the scan).
    3. Click the Select operator drop-down and select Equals from the menu.
    4. Click the Value drop-down and select Phishing and Malware.
    5. Under Actions, select Drop action to stop processing and discard messages that are found to be malicious.

Rule 1 - drop-all-malicious-emails

  1. Create rule ( forward-to-mailbox ) to process messages that were passed along by Rule 1.
  2. Under Actions, select Deliver to mailbox (note – if not using Amazon WorkMail, you would select a previously configured SMTPRelay action to send messages to your inbox provider. See this blog for more info).
    1. Provide your WorkMail ARN
    2. Select an IAM role that has permission for SES Mail Manager to access to your WorkMail mailbox

Rule 2 - forward-to-mailbox

  1. Save the Rule set (it will look like this):

New Vade Rule Set

  1. To use this new Rule set, add it to an active Mail Manager Ingress endpoint. When you click save, the Ingress endpoint will begin using the new Rule set immediately.

The Vade Add-On’s rule conditions (below) enable granular control of email routing. When combined with customizable actions, these rules create an automated email handling system that matches your business needs.

VADE result mapping

Conclusion

Hornetsecurity’s Vade Email Add On for Amazon SES Mail Manager represents a significant step forward in email security for Amazon SES Mail Manager customers. By combining an advanced artificial intelligence (AI)-driven security engine with the powerful management capabilities of Mail Manager, you can enhance your defense against email-borne threats while maintaining precise control over your email workflows.

Get started today and take your email security to the next level with the Vade Add On for Amazon SES Mail Manager

We encourage you to try the Vade Add On for Amazon SES Mail Manager and experience the benefits of enhanced email security firsthand. To learn more about implementation details and best practices, please visit:

Join the Conversation:
Connect with other administrators and security professionals on the AWS re:Post community to share insights and learn best practices.

Handling billions of invocations – best practices from AWS Lambda

Post Syndicated from Chris McPeek original https://aws.amazon.com/blogs/compute/handling-billions-of-invocations-best-practices-from-aws-lambda/

This post is written by Anton Aleksandrov, Principal Solution Architect, AWS Serverless and Rajesh Kumar Pandey, Principal Engineer, AWS Lambda

AWS Lambda is a highly scalable and resilient serverless compute service. With over 1.5 million monthly active customers and tens of trillions of invocations processed, scalability and reliability are two of the most important service tenets. This post provides recommendations and insights for implementing highly distributed applications based on the Lambda service team’s experience building its robust asynchronous event processing system. It dives into challenges you might face, solution techniques, and best practices for handling noisy neighbors.

Overview

Developers building serverless applications create Lambda functions to run their code in the cloud. After uploading the code, the functions are invoked using synchronous or asynchronous mode.

Synchronous invocations are commonly used for interactive applications that expect immediate responses, such as web APIs. The Lambda service receives the invocation request, invokes the function handler, waits for the handler response, and returns it in response to the original request. With synchronous invocations, the client waits for the function handler to return, and is responsible for managing timeouts and retries for failed invocations.

Synchronous invocation sequence diagram.

Figure 1. Synchronous invocation sequence diagram

Asynchronous invocations enable decoupled function executions. Clients submit payloads for processing without expecting immediate responses. This is used for scenarios like asynchronous data processing or order/job submissions. The Lambda service immediately returns a confirmation for accepted invocation and proceeds to manage further handler invocation, timeouts, and retries asynchronously.

Asynchronous invocation sequence diagram.

Figure 2. Asynchronous invocation sequence diagram

Asynchronous invocations under-the-hood

To accommodate asynchronous invocations, the Lambda service places requests into its internal queue and immediately returns HTTP 202 back to the client. After that, a separate internal poller component reads messages from the queue and synchronously invokes the function.

Asynchronous invocations workflow high-level topology.

Figure 3. Asynchronous invocations workflow high-level topology

The same system also takes care of timeouts and retries in case of handler exceptions. When code execution completes, the system sends handler response to either onSuccess or onFailure destination, if configured.

Asynchronous invocations workflow detailed sequence diagram.

Figure 4. Asynchronous invocations workflow detailed sequence diagram

Scaling highly distributed systems for billions of asynchronous requests presents unique challenges, such as managing noisy neighbors and potential traffic spikes to prevent system overload. Solutions vary by scale – what works for millions of requests may not suite billions. As workload size increases, solutions typically become more complex and costly, so right-sizing the approach is critical and should evolve with changing needs.

Simple queueing

A simple implementation of an asynchronous architecture can start with a single shared queue. This is a common approach for many asynchronous systems, particularly in early stages. It is effective when you’re not concerned about tenant isolation and when capacity planning indicates that a single queue can handle estimated incoming traffic efficiently.

Asynchronous workflow with a single queue.

Figure 5. Asynchronous workflow with a single queue

Even with this simple setup, it is critical to instrument your solution for observability to detect potential issues as soon as possible. You should monitor key metrics like queue backlog size, processing time, and errors, to indicate insufficient processing capacity early. Periods of unexpected traffic spikes and degraded performance may be a signal you have noisy neighbors impacting other tenants.Top of FormBottom of Form

To address this, you can scale your solution horizontally. You can implement random request placement across multiple queues to spread the load. Using a serverless service like Amazon SQS allows you to easily add and remove queues on-demand. One notable benefit of this approach is its simplicity – you do not need to introduce any complex routing mechanisms; requests are evenly spread across the queues. The downside is that you still do not have tenant boundaries. As your system grows, high-volume tenants and noisy neighbors can potentially affect all queues, thus impacting all tenants.

Asynchronous workflow with multiple queues and random request placement.

Figure 6. Asynchronous workflow with multiple queues and random request placement

Intelligent partitioning with consistent hashing

In order to further reduce potential impact, you can partition your tenants using sticky tenant-to-partition assignment with a hashing technique such as consistent hashing. This method uses a hash function to assign each tenant to a queue on a consistent hash ring.

Asynchronous workflow with multiple queues and consistent hashing placement.

Figure 7. Asynchronous workflow with multiple queues and consistent hashing placement

This technique ensures individual tenants stay in their queue partitions without the risk of disturbing the whole system. It helps to solve the problem where a few noisy neighbors have the potential to overflow all queues and as such impact all other tenants.

The consistent hashing approach proved to be efficient and enabled Lambda to offer robust asynchronous invocation performance to customers. As the volume of traffic and number of customers continued to grow, the Lambda service team came up with an innovative shuffle-sharding technique to further optimize the experience, and proactively eliminate any potential noisy-neighbor issues.

Shuffle-sharding

Drawing inspiration from the “The Power of Two Random Choices” paper, the Lambda team explored the shuffle-sharding technique for its asynchronous invocations processing. Using this technique, you shuffle-shard tenants into several randomly assigned queues. Upon receiving an asynchronous invocation, you place the message in the queue with the smallest backlog to optimize load distribution. This approach helps to minimize the likelihood of assigning tenants to a busy queue.

Asynchronous workflow with multiple queues and shuffle-sharding placement.

Figure 8. Asynchronous workflow with multiple queues and shuffle-sharding placement

To illustrate the benefit of this approach, consider a scenario where you’re using а 100 queues. The following formula helps to calculate the number of unique queue shards (combinations), where n is the total number of queues and r is the shard size (the number of queues you’re assigning per tenant).

Formula to show queue shard calculation.

With n=100, r=2 (each tenant is assigned randomly to 2 out of 100 queues), you get 4,950 unique combinations (shards). The probability of two tenants assigned to exactly the same shard is 0.02%. In case of r=3, the number of combinations spikes to 161,700. The probability of two tenants assigned to exactly the same shard drops to 0.0006%.

The shuffle-sharding technique proved remarkably effective. By distributing tenants across shards, the approach ensures that only a very small subset of tenants could be affected by a noisy neighbor. The potential impact is also minimized since each affected tenant maintains access to unaffected queues. As your workloads grow, increasing the number of queues enhances resilience and further reduces the probability of multiple tenants being assigned to the same shard. This significantly lowers the risk of a single point of failure, making shuffle sharding a robust strategy for workload isolation and fault tolerance.

Proactive detection, automated isolation, sidelining

Many distributed services will have a cohort of tenants with legitimate spiky asynchronous invocation traffic. This can be driven by seasonal factors, such as holiday shopping, or periodical batch processing. Recognizing these as real business needs, not malicious actions, you want to improve service quality for these tenants as well, while maintaining the overall system stability. For example, you can further improve solution performance by continuously monitoring queue depth to detect traffic spikes and route traffic to dynamically allocated dedicated queues. When you use Lambda asynchronous invocations, this internal complexity is managed for you by the service, ensuring seamless consumption experience.

Tenant D is automatically reallocated to a dedicated queue.

Figure 9. Tenant D is automatically reallocated to a dedicated queue

Resilience and failure handling

“Everything fails, all the time” is a famous quote from Amazon’s Chief Technology Officer Werner Vogels. Lambda’s distributed and resilient architecture is built to withstand potential outages of its dependencies and internal components to limit the fallout for customers. Specifically for asynchronous invocation processing, the frontend service builds a processing backlog during an outage, allowing the backend to gradually recover without losing any in-flight messages.

Lambda service maintains resilience during component outage.

Figure 10. Lambda service maintains resilience during component outage

Upon recovery, the service gradually ramps up the traffic to process the accumulated backlog. During this time, automated mechanisms are in place to coordinate between system components, preventing inadvertently DDoSing itself.

To further improve the recovery ramp-up process and provide a smooth restoration of normal operations, the Lambda service uses load-shedding technique to ensure fair resource allocation during recovery. While trying to drain the backlog as fast as possible, the service ensures that no single customer ends up consuming an outsized share of the available resources. Adopting such techniques can help you to improve your mean-time-to-recovery (MTTR).

Observability for asynchronous invocations processing

When using the Lambda service for asynchronous processing, you want to monitor your invocations for situational awareness and potential slowdowns. Use metrics such as AsyncEventReceived, AsyncEventAge, and AsyncEventDropped to get insights about internal processing.

AsyncEventReceived tracks the number of async invocations the Lambda service was able to successfully queue for processing. A drop in this metric indicates that invocations are not being delivered to the Lambda service and you should check your invocation source. Potential issues include misconfigurations, invalid access permissions, or throttling. Check your invocation source configuration, logs, and the function resource policy for further analysis.

AsyncEventAge tracks how long has a message spent in the internal queue before being processed by a function. This metric increases when async invocations processing is delayed due to insufficient concurrency, execution failures, or throttles. Increase your function concurrency to process more asynchronous invocations at a time and optimize function performance for better throughput, i.e. by increasing memory allocation to add more vCPU capacity. Experiment with adjusting batch size to enable functions to process more messages at a time. Use invocation logs to identify whether the problem is caused by function code throwing exceptions. Check Throttles and Errors metrics for further analysis.

AsyncEventDropped tracks the number of messages in the internal queue that were dropped because Lambda could not process them. This can be due to throttling, exceeding number of retries, exceeding maximum message age, or function code throwing an exception. Configure OnFailure destination or a dead-letter queue to avoid losing data and save dropped messages for re-processing. Use function logs and metrics described above to investigate whether you can address the issue by increasing function concurrency or allocating more memory.

By monitoring these metrics and addressing the underlying issues, you can ensure that your Lambda functions run smoothly, with minimal event processing delays and failures. You can also enable AWS X-Ray tracing to capture Lambda service traces. The AWS::Lambda trace segment captures the breakdown of the time that Lambda service spends routing requests to internal queues, the time a message spends in a queue, and the time before a function is invoked. This is a powerful tool to get insights into Lambda’s internal processing.

Conclusion

AWS Lambda processes tens of trillions of monthly invocations across more than 1.5 million active customers, demonstrating its exceptional scalability and resilience. Gaining an understanding of the underlying mechanisms of AWS services like Lambda enables you to proactively address potential challenges in your own applications. By learning how these services handle traffic, manage resources, and recover from failures, you can incorporate similar capabilities into your own solutions. For instance, leveraging Lambda’s asynchronous invocation metrics allows you to optimize workflow performance. This knowledge empowers you to implement strategies such as automated scaling, proactive monitoring, and graceful recovery during outages.

See below resources to learn about using queues and shuffle sharding at scale at Amazon

To learn more about Serverless architectures and asynchronous Lambda invocation patterns, see Serverless Land.

How to Register a Sender ID Using APIs with AWS End User Messaging

Post Syndicated from Tyler Holmes original https://aws.amazon.com/blogs/messaging-and-targeting/how-to-register-a-sender-id-using-apis-with-aws-end-user-messaging/

Introduction

Welcome to our comprehensive guide on using the AWS End User Messaging V2 APIs to obtain a Sender ID in countries that require registration. Sender ID registration is a crucial step for businesses looking to establish a trusted communication channel with their customers via SMS. In countries such as Jordan, the Philippines, Qatar, and others registering a Sender ID is mandatory to ensure compliance with local regulations and to enhance message deliverability. You can view a list of countries that support Sender ID and require registration here.

NOTE: This post is specific to Sender IDs, to learn more about choosing the right originator for your use case read this post on How to Send SMS Globally Using AWS End User Messaging.

This guide will walk you through the high-level process of creating and submitting a Sender ID registration using AWS End User Messaging V2 APIs. While we will use Jordan as a case study in this post, the principles and steps outlined here apply to other countries with similar registration requirements for Sender ID.

High-Level Understanding of the Registration APIs

To successfully register a Sender ID, you’ll need to interact with several AWS End User Messaging APIs. Here’s a brief overview of the key APIs involved and their roles in the registration process:

1. DescribeRegistrationTypeDefinitions

  • Purpose: Retrieves the specified registration type definitions.
  • Use Case: View the requirements for creating, filling out, and submitting each registration type.
  • Key Point: Each country has a specific “RegistrationType” that needs to be used in the next step to create a registration.
  • Documentation: DescribeRegistrationTypeDefinitions

2. CreateRegistration

  • Purpose: Creates a new registration “container”. This is an empty registration that we are going to fill with our data in later steps.
  • Key Field: RegistrationType
    • Controls the type of registration (e.g., Toll-Free, 10DLC, JO_SENDER_ID_REGISTRATION, etc.).
  • Documentation: CreateRegistration

3. DescribeRegistrationFieldDefinitions

  • Purpose: Retrieves the specified RegistrationType field definitions.
  • Use Case: View the requirements for creating, filling out, and submitting each registration type. There are different field types (SELECT, TEXT, ATTACHMENT) dependent on the type of data required to register as well as the actual questions that need to be answered.
  • Documentation: DescribeRegistrationFieldDefinitions

4. CreateRegistrationAttachment

  • Purpose: Uploads additional documentation that some countries require. Not all countries require documentation that needs to be uploaded so this may be an optional step depending on the country you are registering for. We will be registering for Jordan in this example which does require us to upload a document to complete the registration.
  • Key Field: RegistrationAttachmentId
    • Used in the next action to include an attachment in the registration when you are required to provide one. Not all registration types require an attachment.
  • File Specifications:
    • Maximum file size: 500kb
    • Valid file extensions: PDF, JPEG, or PNG
  • Documentation: CreateRegistrationAttachment

5. PutRegistrationFieldValue

  • Purpose: Sets the value for a specific registration field.
    • This action needs to be repeated for all required fields.
  • Documentation: PutRegistrationFieldValue

6. SubmitRegistrationVersion

  • Purpose: Submits the specified registration version for review and approval. You are able to create new versions of the registration using CreateRegistrationVersion so make sure if you created another Registration Version that you use the correct ID.
  • Important Notes:
    • Ensure that you are using the correct Version if you created multiple
    • Ensure all data is correct before submission.
    • Initial status will be “CREATED” and should change to “REVIEWING” within 24 hours.
    • You cannot edit or delete the registration until it is approved or rejected.
  • Documentation: SubmitRegistrationVersion

Detailed Steps for Sender ID Registration in Jordan

In the following sections, we’ll dive deeper into each of these steps, providing more detail on the API calls and responses as well as best practices to ensure a smooth registration process. Whether you’re registering in Jordan or another country with similar requirements, this guide will equip you with the knowledge you need to successfully register a Sender ID.

Step 1: DescribeRegistrationTypeDefinitions

The first step is to run DescribeRegistrationTypeDefinitions to retrieve all specified registration type definitions. This API provides a detailed response that includes various attributes related to the registration process. Let’s break down these attributes for Jordan:

  • Country: JO
    • Description: Specifies the country code for which the registration type definitions are being described. JO stands for Jordan.
    • Implication: Understanding the country code is crucial because registration requirements and processes can vary significantly from one country to another.
  • ResourceType: SENDER_ID
    • Description: Indicates the type of resource for which the registration is being defined.
    • Implication: Knowing that the resource type is SENDER_ID helps you understand that the registration process is focused on obtaining approval specifically for a Sender ID as there are some countries that have multiple registration types.
  • Registration Type: JO_SENDER_ID_REGISTRATION
    • Description: Specifies the exact type of registration required for the given country and resource type.
    • Implication: This registration type is critical because it dictates the specific steps, documentation, and criteria you need to meet to successfully register a Sender ID in Jordan.
    • You will use this value to create the initial registration
  • Association Behavior: ASSOCIATE_ON_APPROVAL
    • Description: Describes how the registered Sender ID will be associated with your AWS account once the registration is approved.
    • Implication: ASSOCIATE_ON_APPROVAL means that the Sender ID will be automatically associated with your account as soon as the registration is approved, simplifying the process post-approval. There will be nothing more for you to do once you have successfully submitted your registration and it has been approved. Some registration types require steps to be taken after the registration is approved, this is not one of them.
  • Disassociation Behavior: DISASSOCIATE_ALL_CLOSES_REGISTRATION
    • Description: Explains what happens when you disassociate the Sender ID from your account.
    • Implication: This behavior is important to note because it means that the origination identity must be disassociated from the registration before the registration can be closed.

Step 2: CreateRegistration

Next, use CreateRegistration with the RegistrationType for Jordan, “JO_SENDER_ID_REGISTRATION,” to generate a blank registration “container” for a Jordan Sender ID. Make sure to log the “RegistrationId” for later use as it will be used throughout the rest of the process.

Below is a screenshot of the registration that was created in the console

Step 3: DescribeRegistrationFieldDefinitions

Use DescribeRegistrationFieldDefinitions with “JO_SENDER_ID_REGISTRATION” as the RegistrationType to pull down all the fields that need to be filled out to submit the registration.

Important Field Attributes

  • FieldPath
    • Value: A string that specifies the path to the field within the registration form (e.g., companyInfo.companyName).
    • Description: The FieldPath attribute provides a hierarchical path to the specific field within the registration form. It identifies one of the fields we will use later to input the data into our registration
    • Implication: Ensures that you place the required information in the correct field, essential for accurate processing.
  • FieldRequirement
    • Value: Indicates whether the field is required, optional, or conditional (REQUIRED, OPTIONAL, CONDITIONAL).
    • Description: The FieldRequirement attribute specifies the necessity of the field in the registration process. A REQUIRED field must be filled out for the registration to be submitted, while an OPTIONAL field can be left blank if not applicable. A CONDITIONAL field depends on other fields and may become required based on certain conditions.
    • Implication: Helps prioritize which fields to complete and ensures critical information is not missed.
  • FieldType
    • Value: Describes the type of data expected in the field (SELECT, TEXT, ATTACHMENT).
    • Description: Indicates the format and type of data that should be entered into the field.
    • Implication: Ensures the registration form is valid and reduces the risk of errors or rejections due to incorrect data formats.

See the categories of the Jordan registration in the screenshot below

Let’s break down the required fields that are common across all Sender Id registrations and their descriptions in a more readable format:

Sender ID Information:

  1. Sender ID (Required)
    1. Must be 3-11 alphanumeric characters
    2. Must contain at least one letter
    3. Example: “EXAMPLE”
  2. Sender ID Description (Optional)
    1. Explain the connection between company name and sender ID
    2. Max 500 characters
  3. Proof of Sender ID Connection (Optional)
    1. Required only if the connection between company name and sender ID isn’t obvious
    2. Must provide evidence of intellectual property rights

Below is a screenshot of the Console version

Company Information:

  1. Company Name (Required)
    1. Legal company name
    2. Max 100 characters
    3. Example: “Example Corp”
  2. Company ID (Required)
    1. Legal identification number (EIN/VAT)
    2. Alphanumeric only
    3. Max 30 characters
  3. DBA Name (Optional)
    1. “Doing Business As” name if different from legal name
    2. Max 100 characters
  4. Website (Required)
    1. Company’s full URL
    2. Example: “https://www.example.com”
  5. Area of Business (Required)
    1. Choose one: Agriculture, Communication, Construction, Education, Energy, Entertainment, Financial, Government, Healthcare, Hospitality, Insurance, Manufacturing, Real estate, Retail, Technology, Other

Below is a screenshot of the Console version

Company Address:

  1. Address Line 1 (Required)
  2. Address Line 2 (Optional)
  3. City (Required)
  4. State/Province (Optional)
  5. Postal Code (Optional)
  6. Country Code (Required)
    1. Two-letter ISO code
    2. Example: “US”

Below is a screenshot of the Console version

Contact Information:

  1. Email Address (Required)
    1. Valid email format
    2. Example: “[email protected]
  2. Phone Number (Required)
    1. Must contain at least 3 digits
    2. Example: “+12065550100“

Below is a screenshot of the Console version

Messaging Use Case:

  1. Use Case Category (Required)
    1. Choose one: One-time passcodes, Account/security alerts, Purchase/delivery notifications, Public service announcements, Polling/surveys, Info on demand, Other
  2. Use Case Description (Required)
    1. Max 500 characters
  3. Monthly Message Volume (Required)
    1. Choose one: 10, 100, 1,000, 10,000, 100,000, 1,000,000, 10,000,000+
  4. Opt-in Description (Required)
    1. How users will opt-in to receiving messages
    2. Max 500 characters

Below is a screenshot of the Console version

Message Samples:

  1. Message Sample 1 (Required)
    1. Max 306 characters
  2. Message Sample 2 (Optional)
    1. Max 306 characters
  3. Message Sample 3 (Optional)
    1. Max 306 characters

Below is a screenshot of the Console version

Jordan-Specific Requirements

Some countries, not all, also have country-specific requirements. Jordan requires the following for this registration:

  1. Company Registration Documentation (Required)
    1. Must provide company registration docs (both local and international companies)
    2. This is an Attachment type so we will need to use “CreateRegistrationAttachment” first in order to put this value into the registration. We will cover this further down in the process
  2. Transactional Acknowledgement (Required)
    1. Must acknowledge that only transactional messages will be sent
    2. Promotional content is not allowed
    3. This is a “Select” field type with the only option being “Yes” meaning you will be unable to register unless you agree to this acknowledgement

Below is a screenshot of the Console version

Step 4: CreateRegistrationAttachment

Now that you know all the fields required for the Jordan Sender ID registration, you need to gather all the necessary data, including the required attachment. The Jordan Sender ID registration requires only one attachment. Let’s review how to add this attachment to your registration.

To add an attachment to your registration, use the CreateRegistrationAttachment API. You have two options for providing this document:

  1. Specify a file in S3:
    1. Ensure you use Standard buckets, S3 Express is not supported.
  2. Upload it as a Base64-encoded binary data object:
    1. This method allows you to directly upload the document without needing to store it in S3 first.

Important: After successfully running the CreateRegistrationAttachment command, you will receive a “RegistrationAttachmentId.” Make sure to log this ID, as you will need it to attach the upload to your registration.

Step 5: PutRegistrationFieldValue

Use PutRegistrationFieldValue to input data into each field. Loop through each input as each call only inputs a single value. Specify the “RegistrationId” logged earlier when making each call. Your options for field values are:

  • RegistrationAttachmentId: The unique identifier for the registration attachment
  • SelectChoices: An array of values for the form field that were specified in the payload earlier
  • TextValue: The text data for a free form field

Step 6: Review your registration

Once you have successfully inputted all the values for your registration, you can review your inputs in one of two ways:

  1. View in the Console:
    1. Your registration details are accessible directly in the AWS Management Console.
  2. Use DescribeRegistrationFieldValues:
    1. You can pull down your registration and review each of its values using the DescribeRegistrationFieldValues API. Make sure to use the right version ID of your registration.

Step 7: Submitting Your Registration

Once all values in your registration are complete and correct, submit your registration for review using the SubmitRegistrationVersion API. Provide your “RegistrationId” when making this call.

Initial Status:

  • The initial status of your registration will be “CREATED.”
  • It should change to “REVIEWING” within 24 hours.
  • If the status does not change from “CREATED” to “REVIEWING” within 24 hours and you’ve confirmed you SUBMITTED your registration version, create a support case for assistance.

Sender ID Registration Review Process

Each country has its own review process and timeline. Each registration is examined on a first-in/first-out basis by the registrar for each country. AWS does not review your registrations so make sure that you are completing this registration with this in mind. There are humans reviewing these registrations that do not know your company or your use case so make sure to be clear and concise in your responses.

If the registrar is confused by your submission, they may reject it, and you will need to start the process over, amending the registration where necessary and resubmitting. This puts you in the back of the line again, which will increase your timeline.

Conclusion

Completing a Sender ID registration using the End User Messaging V2 APIs involves several steps, each critical to ensuring compliance and successful registration. By following this guide, you can navigate the process efficiently, from understanding the required fields to submitting your registration for review. Whether you’re registering in Jordan or another country with different requirements, this guide provides the knowledge and steps needed to successfully obtain a Sender ID and establish a trusted communication channel with your customers via SMS.