

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Amazon SES 使用场景 AWS SDKs
<a name="service_code_examples_ses_scenarios"></a>

以下代码示例向您展示了如何使用在 Amazon SES 中实现常见场景 AWS SDKs。这些场景向您展示了如何通过调用 Amazon SES 中的多个函数或与其他 AWS 服务结合来完成特定任务。每个场景都包含完整源代码的链接，您可以在其中找到有关如何设置和运行代码的说明。

场景以中等水平的经验为目标，可帮助您结合具体环境了解服务操作。

**Topics**
+ [构建 Amazon Transcribe 流式传输应用程序](ses_example_cross_TranscriptionStreamingApp_section.md)
+ [跨区域复制电子邮件和域身份](ses_example_ses_Scenario_ReplicateIdentities_section.md)
+ [创建 Web 应用程序来跟踪 DynamoDB 数据](ses_example_cross_DynamoDBDataTracker_section.md)
+ [创建 Web 应用程序来跟踪 Amazon Redshift 数据](ses_example_cross_RedshiftDataTracker_section.md)
+ [创建 Aurora Serverless 工作项跟踪器](ses_example_cross_RDSDataTracker_section.md)
+ [检测图像中的 PPE](ses_example_cross_RekognitionPhotoAnalyzerPPE_section.md)
+ [检测图像中的对象](ses_example_cross_RekognitionPhotoAnalyzer_section.md)
+ [检测视频中的人物和对象](ses_example_cross_RekognitionVideoDetection_section.md)
+ [生成凭证以连接到 SMTP 端点](ses_example_ses_Scenario_GenerateSmtpCredentials_section.md)
+ [使用 Step Functions 调用 Lambda 函数](ses_example_cross_ServerlessWorkflows_section.md)
+ [验证电子邮件身份与发送消息](ses_example_ses_Scenario_SendEmail_section.md)

# 构建 Amazon Transcribe 流式传输应用程序
<a name="ses_example_cross_TranscriptionStreamingApp_section"></a>

以下代码示例展示如何构建可实时录制、转录与翻译实时音频，并通过电子邮件发送结果的应用程序。

------
#### [ JavaScript ]

**适用于 JavaScript (v3) 的软件开发工具包**  
 演示了如何使用 Amazon Transcribe 构建可实时录制、转录与翻译实时音频，并通过 Amazon Simple Email Service (Amazon SES) 以电子邮件发送结果的应用程序。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3/example_code/cross-services/transcribe-streaming-app)。  

**本示例中使用的服务**
+ Amazon Comprehend
+ Amazon SES
+ Amazon Transcribe
+ Amazon Translate

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用软件开发工具包将 Amazon AWS SES 电子邮件和域名身份从一个 AWS 地区复制到另一个区域
<a name="ses_example_ses_Scenario_ReplicateIdentities_section"></a>

以下代码示例显示如何将 Amazon SES 电子邮件和域名身份从一个 AWS 区域复制到另一个区域。由 Route 53 管理域身份时，会为目标区域将验证记录复制到域。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 还有更多相关信息 GitHub。在 [AWS 代码示例存储库](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/ses#code-examples)中查找完整示例，了解如何进行设置和运行。

```
import argparse
import json
import logging
from pprint import pprint
import boto3
from botocore.exceptions import ClientError

logger = logging.getLogger(__name__)


def get_identities(ses_client):
    """
    Gets the identities for the current Region. The Region is specified in the
    Boto3 Amazon SES client object.

    :param ses_client: A Boto3 Amazon SES client.
    :return: The list of email identities and the list of domain identities.
    """
    email_identities = []
    domain_identities = []
    try:
        identity_paginator = ses_client.get_paginator("list_identities")
        identity_iterator = identity_paginator.paginate(
            PaginationConfig={"PageSize": 20}
        )
        for identity_page in identity_iterator:
            for identity in identity_page["Identities"]:
                if "@" in identity:
                    email_identities.append(identity)
                else:
                    domain_identities.append(identity)
        logger.info(
            "Found %s email and %s domain identities.",
            len(email_identities),
            len(domain_identities),
        )
    except ClientError:
        logger.exception("Couldn't get identities.")
        raise
    else:
        return email_identities, domain_identities


def verify_emails(email_list, ses_client):
    """
    Starts verification of a list of email addresses. Verification causes an email
    to be sent to each address. To complete verification, the recipient must follow
    the instructions in the email.

    :param email_list: The list of email addresses to verify.
    :param ses_client: A Boto3 Amazon SES client.
    :return: The list of emails that were successfully submitted for verification.
    """
    verified_emails = []
    for email in email_list:
        try:
            ses_client.verify_email_identity(EmailAddress=email)
            verified_emails.append(email)
            logger.info("Started verification of %s.", email)
        except ClientError:
            logger.warning("Couldn't start verification of %s.", email)
    return verified_emails


def verify_domains(domain_list, ses_client):
    """
    Starts verification for a list of domain identities. This returns a token for
    each domain, which must be registered as a TXT record with the DNS provider for
    the domain.

    :param domain_list: The list of domains to verify.
    :param ses_client: A Boto3 Amazon SES client.
    :return: The generated domain tokens to use to completed verification.
    """
    domain_tokens = {}
    for domain in domain_list:
        try:
            response = ses_client.verify_domain_identity(Domain=domain)
            token = response["VerificationToken"]
            domain_tokens[domain] = token
            logger.info("Got verification token %s for domain %s.", token, domain)
        except ClientError:
            logger.warning("Couldn't get verification token for domain %s.", domain)
    return domain_tokens


def get_hosted_zones(route53_client):
    """
    Gets the Amazon Route 53 hosted zones for the current account.

    :param route53_client: A Boto3 Route 53 client.
    :return: The list of hosted zones.
    """
    zones = []
    try:
        zone_paginator = route53_client.get_paginator("list_hosted_zones")
        zone_iterator = zone_paginator.paginate(PaginationConfig={"PageSize": 20})
        zones = [
            zone for zone_page in zone_iterator for zone in zone_page["HostedZones"]
        ]
        logger.info("Found %s hosted zones.", len(zones))
    except ClientError:
        logger.warning("Couldn't get hosted zones.")
    return zones


def find_domain_zone_matches(domains, zones):
    """
    Finds matches between Amazon SES verified domains and Route 53 hosted zones.
    Subdomain matches are taken when found, otherwise root domain matches are taken.

    :param domains: The list of domains to match.
    :param zones: The list of hosted zones to match.
    :return: The set of matched domain-zone pairs. When a match is not found, the
             domain is included in the set with a zone value of None.
    """
    domain_zones = {}
    for domain in domains:
        domain_zones[domain] = None
        # Start at the most specific sub-domain and walk up to the root domain until a
        # zone match is found.
        domain_split = domain.split(".")
        for index in range(0, len(domain_split) - 1):
            sub_domain = ".".join(domain_split[index:])
            for zone in zones:
                # Normalize the zone name from Route 53 by removing the trailing '.'.
                zone_name = zone["Name"][:-1]
                if sub_domain == zone_name:
                    domain_zones[domain] = zone
                    break
            if domain_zones[domain] is not None:
                break
    return domain_zones


def add_route53_verification_record(domain, token, zone, route53_client):
    """
    Adds a domain verification TXT record to the specified Route 53 hosted zone.
    When a TXT record already exists in the hosted zone for the specified domain,
    the existing values are preserved and the new token is added to the list.

    :param domain: The domain to add.
    :param token: The verification token for the domain.
    :param zone: The hosted zone where the domain verification record is added.
    :param route53_client: A Boto3 Route 53 client.
    """
    domain_token_record_set_name = f"_amazonses.{domain}"
    record_set_paginator = route53_client.get_paginator("list_resource_record_sets")
    record_set_iterator = record_set_paginator.paginate(
        HostedZoneId=zone["Id"], PaginationConfig={"PageSize": 20}
    )
    records = []
    for record_set_page in record_set_iterator:
        try:
            txt_record_set = next(
                record_set
                for record_set in record_set_page["ResourceRecordSets"]
                if record_set["Name"][:-1] == domain_token_record_set_name
                and record_set["Type"] == "TXT"
            )
            records = txt_record_set["ResourceRecords"]
            logger.info(
                "Existing TXT record found in set %s for zone %s.",
                domain_token_record_set_name,
                zone["Name"],
            )
            break
        except StopIteration:
            pass
    records.append({"Value": json.dumps(token)})
    changes = [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": domain_token_record_set_name,
                "Type": "TXT",
                "TTL": 1800,
                "ResourceRecords": records,
            },
        }
    ]
    try:
        route53_client.change_resource_record_sets(
            HostedZoneId=zone["Id"], ChangeBatch={"Changes": changes}
        )
        logger.info(
            "Created or updated the TXT record in set %s for zone %s.",
            domain_token_record_set_name,
            zone["Name"],
        )
    except ClientError as err:
        logger.warning(
            "Got error %s. Couldn't create or update the TXT record for zone %s.",
            err.response["Error"]["Code"],
            zone["Name"],
        )


def generate_dkim_tokens(domain, ses_client):
    """
    Generates DKIM tokens for a domain. These must be added as CNAME records to the
    DNS provider for the domain.

    :param domain: The domain to generate tokens for.
    :param ses_client: A Boto3 Amazon SES client.
    :return: The list of generated DKIM tokens.
    """
    dkim_tokens = []
    try:
        dkim_tokens = ses_client.verify_domain_dkim(Domain=domain)["DkimTokens"]
        logger.info("Generated %s DKIM tokens for domain %s.", len(dkim_tokens), domain)
    except ClientError:
        logger.warning("Couldn't generate DKIM tokens for domain %s.", domain)
    return dkim_tokens


def add_dkim_domain_tokens(hosted_zone, domain, tokens, route53_client):
    """
    Adds DKIM domain token CNAME records to a Route 53 hosted zone.

    :param hosted_zone: The hosted zone where the records are added.
    :param domain: The domain to add.
    :param tokens: The DKIM tokens for the domain to add.
    :param route53_client: A Boto3 Route 53 client.
    """
    try:
        changes = [
            {
                "Action": "UPSERT",
                "ResourceRecordSet": {
                    "Name": f"{token}._domainkey.{domain}",
                    "Type": "CNAME",
                    "TTL": 1800,
                    "ResourceRecords": [{"Value": f"{token}.dkim.amazonses.com"}],
                },
            }
            for token in tokens
        ]
        route53_client.change_resource_record_sets(
            HostedZoneId=hosted_zone["Id"], ChangeBatch={"Changes": changes}
        )
        logger.info(
            "Added %s DKIM CNAME records to %s in zone %s.",
            len(tokens),
            domain,
            hosted_zone["Name"],
        )
    except ClientError:
        logger.warning(
            "Couldn't add DKIM CNAME records for %s to zone %s.",
            domain,
            hosted_zone["Name"],
        )


def configure_sns_topics(identity, topics, ses_client):
    """
    Configures Amazon Simple Notification Service (Amazon SNS) notifications for
    an identity. The Amazon SNS topics must already exist.

    :param identity: The identity to configure.
    :param topics: The list of topics to configure. The choices are Bounce, Delivery,
                   or Complaint.
    :param ses_client: A Boto3 Amazon SES client.
    """
    for topic in topics:
        topic_arn = input(
            f"Enter the Amazon Resource Name (ARN) of the {topic} topic or press "
            f"Enter to skip: "
        )
        if topic_arn != "":
            try:
                ses_client.set_identity_notification_topic(
                    Identity=identity, NotificationType=topic, SnsTopic=topic_arn
                )
                logger.info("Configured %s for %s notifications.", identity, topic)
            except ClientError:
                logger.warning(
                    "Couldn't configure %s for %s notifications.", identity, topic
                )


def replicate(source_client, destination_client, route53_client):
    logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")

    print("-" * 88)
    print(
        f"Replicating Amazon SES identities and other configuration from "
        f"{source_client.meta.region_name} to {destination_client.meta.region_name}."
    )
    print("-" * 88)

    print(f"Retrieving identities from {source_client.meta.region_name}.")
    source_emails, source_domains = get_identities(source_client)
    print("Email addresses found:")
    print(*source_emails)
    print("Domains found:")
    print(*source_domains)

    print("Starting verification for email identities.")
    dest_emails = verify_emails(source_emails, destination_client)
    print("Getting domain tokens for domain identities.")
    dest_domain_tokens = verify_domains(source_domains, destination_client)

    # Get Route 53 hosted zones and match them with Amazon SES domains.
    answer = input(
        "Is the DNS configuration for your domains managed by Amazon Route 53 (y/n)? "
    )
    use_route53 = answer.lower() == "y"
    hosted_zones = get_hosted_zones(route53_client) if use_route53 else []
    if use_route53:
        print("Adding or updating Route 53 TXT records for your domains.")
        domain_zones = find_domain_zone_matches(dest_domain_tokens.keys(), hosted_zones)
        for domain in domain_zones:
            add_route53_verification_record(
                domain, dest_domain_tokens[domain], domain_zones[domain], route53_client
            )
    else:
        print(
            "Use these verification tokens to create TXT records through your DNS "
            "provider:"
        )
        pprint(dest_domain_tokens)

    answer = input("Do you want to configure DKIM signing for your identities (y/n)? ")
    if answer.lower() == "y":
        # Build a set of unique domains from email and domain identities.
        domains = {email.split("@")[1] for email in dest_emails}
        domains.update(dest_domain_tokens)
        domain_zones = find_domain_zone_matches(domains, hosted_zones)
        for domain, zone in domain_zones.items():
            answer = input(
                f"Do you want to configure DKIM signing for {domain} (y/n)? "
            )
            if answer.lower() == "y":
                dkim_tokens = generate_dkim_tokens(domain, destination_client)
                if use_route53 and zone is not None:
                    add_dkim_domain_tokens(zone, domain, dkim_tokens, route53_client)
                else:
                    print(
                        "Add the following DKIM tokens as CNAME records through your "
                        "DNS provider:"
                    )
                    print(*dkim_tokens, sep="\n")

    answer = input(
        "Do you want to configure Amazon SNS notifications for your identities (y/n)? "
    )
    if answer.lower() == "y":
        for identity in dest_emails + list(dest_domain_tokens.keys()):
            answer = input(
                f"Do you want to configure Amazon SNS topics for {identity} (y/n)? "
            )
            if answer.lower() == "y":
                configure_sns_topics(
                    identity, ["Bounce", "Delivery", "Complaint"], destination_client
                )

    print(f"Replication complete for {destination_client.meta.region_name}.")
    print("-" * 88)


def main():
    boto3_session = boto3.Session()
    ses_regions = boto3_session.get_available_regions("ses")
    parser = argparse.ArgumentParser(
        description="Copies email address and domain identities from one AWS Region to "
        "another. Optionally adds records for domain verification and DKIM "
        "signing to domains that are managed by Amazon Route 53, "
        "and sets up Amazon SNS notifications for events of interest."
    )
    parser.add_argument(
        "source_region", choices=ses_regions, help="The region to copy from."
    )
    parser.add_argument(
        "destination_region", choices=ses_regions, help="The region to copy to."
    )
    args = parser.parse_args()
    source_client = boto3.client("ses", region_name=args.source_region)
    destination_client = boto3.client("ses", region_name=args.destination_region)
    route53_client = boto3.client("route53")
    replicate(source_client, destination_client, route53_client)


if __name__ == "__main__":
    main()
```
+ 有关 API 详细信息，请参阅《AWS SDK for Python (Boto3) API Reference》**中的以下主题。
  + [ListIdentities](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/ListIdentities)
  + [SetIdentityNotificationTopic](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/SetIdentityNotificationTopic)
  + [VerifyDomainDkim](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/VerifyDomainDkim)
  + [VerifyDomainIdentity](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/VerifyDomainIdentity)
  + [VerifyEmailIdentity](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/VerifyEmailIdentity)

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 创建 Web 应用程序来跟踪 DynamoDB 数据
<a name="ses_example_cross_DynamoDBDataTracker_section"></a>

以下代码示例显示如何创建一个 Web 应用程序，来跟踪 Amazon DynamoDB 表中的工作项，并使用 Amazon Simple Email Service（Amazon SES）来发送报告。

------
#### [ .NET ]

**适用于 .NET 的 SDK**  
 展示如何使用 Amazon DynamoDB .NET API 创建用于跟踪 DynamoDB 工作数据的动态 Web 应用程序。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/DynamoDbItemTracker)。  

**本示例中使用的服务**
+ DynamoDB
+ Amazon SES

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 展示如何使用 Amazon DynamoDB API 创建用于跟踪 DynamoDB 工作数据的动态 Web 应用程序。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_dynamodb_web_app)。  

**本示例中使用的服务**
+ DynamoDB
+ Amazon SES

------
#### [ Kotlin ]

**适用于 Kotlin 的 SDK**  
 展示如何使用 Amazon DynamoDB API 创建用于跟踪 DynamoDB 工作数据的动态 Web 应用程序。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin/usecases/itemtracker_dynamodb)。  

**本示例中使用的服务**
+ DynamoDB
+ Amazon SES

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 演示如何使用创建 REST 服务，通过亚马逊简单电子邮件服务 (Amazon SES) 跟踪亚马逊 DynamoDB 中的工作项目并通过电子邮件发送报告。 适用于 Python (Boto3) 的 AWS SDK 此示例使用 Flask Web 框架处理 HTTP 路由，并且与 React 网页集成来呈现完整功能的 Web 应用程序。  
+ 构建与 AWS 服务集成的 Flask REST 服务。
+ 读取、写入和更新存储在 DynamoDB 表中的工作项。
+ 使用 Amazon SES 发送工作项的电子邮件报告。
 有关完整的源代码以及如何设置和运行的说明，请参阅上的 “[AWS 代码示例存储库” 中的完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/cross_service/dynamodb_item_tracker) GitHub。  

**本示例中使用的服务**
+ DynamoDB
+ Amazon SES

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 创建 Amazon Redshift 项目追踪器
<a name="ses_example_cross_RedshiftDataTracker_section"></a>

以下代码示例展示如何使用 Amazon Redshift 数据库创建用于跟踪和报告工作项的 Web 应用程序。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 展示如何创建 Web 应用程序来跟踪与报告存储与 Amazon Redshift 数据库的工作项。  
 有关如何设置查询 Amazon Redshift 数据的 Spring REST API 以及供 React 应用程序使用的完整源代码和说明，请参阅上的完整示例。[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/CreatingSpringRedshiftRest)  

**本示例中使用的服务**
+ Amazon Redshift
+ Amazon SES

------
#### [ Kotlin ]

**适用于 Kotlin 的 SDK**  
 展示如何创建 Web 应用程序来跟踪与报告存储与 Amazon Redshift 数据库的工作项。  
 有关如何设置查询 Amazon Redshift 数据的 Spring REST API 以及供 React 应用程序使用的完整源代码和说明，请参阅上的完整示例。[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin/usecases/creating_redshift_application)  

**本示例中使用的服务**
+ Amazon Redshift
+ Amazon SES

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 创建 Aurora Serverless 工作项跟踪器
<a name="ses_example_cross_RDSDataTracker_section"></a>

以下代码示例演示了如何创建用于跟踪 Amazon Aurora Serverless 数据库中的工作项，以及使用 Amazon Simple Email Service（Amazon SES）发送报告的 Web 应用程序。

------
#### [ .NET ]

**适用于 .NET 的 SDK**  
 演示如何使用创建一个 Web 应用程序，该 适用于 .NET 的 AWS SDK 应用程序可跟踪 Amazon Aurora 数据库中的工作项目，并使用亚马逊简单电子邮件服务 (Amazon SES) 通过电子邮件发送报告。此示例使用使用 React.js 构建的前端与 RESTful .NET 后端进行交互。  
+ 将 React Web 应用程序与 AWS 服务集成。
+ 列出、添加、更新和删除 Aurora 表中的项目。
+ 使用 Amazon SES 以电子邮件形式发送已筛选工作项的报告。
+ 使用随附的 AWS CloudFormation 脚本部署和管理示例资源。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/AuroraItemTracker)。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ C\$1\$1 ]

**SDK for C\$1\$1**  
 演示了如何创建用于跟踪和报告存储在 Amazon Aurora Serverless 数据库中的工作项的 Web 应用程序。  
 有关如何设置查询 Amazon Aurora Serverless 数据的 C\$1\$1 REST API 以及如何由 React 应用程序使用的完整源代码和说明，请参阅上的[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/cross-service/serverless-aurora)完整示例。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 展示如何创建 Web 应用程序来跟踪与报告存储与 Amazon RDS 数据库的工作项。  
 有关如何设置查询 Amazon Aurora Serverless 数据的 Spring REST API 以及如何让 React 应用程序使用的完整源代码和说明，请参阅上的[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_Spring_RDS_Rest)完整示例。  
 有关如何设置和运行使用 JDBC API 的示例的完整源代码和说明，请参阅上的完整示例。[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/Creating_rds_item_tracker)  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ JavaScript ]

**适用于 JavaScript (v3) 的软件开发工具包**  
 演示如何使用 适用于 JavaScript 的 AWS SDK (v3) 创建一个 Web 应用程序，该应用程序使用亚马逊简单电子邮件服务 (Amazon SES) Service 跟踪亚马逊 Aurora 数据库中的工作项目并通过电子邮件发送报告。此示例使用由 React.js 构建的前端与 Express Node.js 后端进行交互。  
+ 将 React.js 网络应用程序与集成 AWS 服务。
+ 列出、添加以及更新 Aurora 表中的项目。
+ 使用 Amazon SES 以电子邮件形式发送已筛选工作项的报告。
+ 使用随附的 AWS CloudFormation 脚本部署和管理示例资源。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3/example_code/cross-services/aurora-serverless-app)。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ Kotlin ]

**适用于 Kotlin 的 SDK**  
 展示如何创建 Web 应用程序来跟踪与报告存储与 Amazon RDS 数据库的工作项。  
 有关如何设置查询 Amazon Aurora Serverless 数据的 Spring REST API 以及如何让 React 应用程序使用的完整源代码和说明，请参阅上的[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin/usecases/serverless_rds)完整示例。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ PHP ]

**适用于 PHP 的 SDK**  
 演示如何使用创建一个 Web 应用程序，该 适用于 PHP 的 AWS SDK 应用程序通过亚马逊简单电子邮件服务 (Amazon SES) Semple Service 跟踪亚马逊 RDS 数据库中的工作项目并通过电子邮件发送报告。此示例使用使用 React.js 构建的前端与 RESTful PHP 后端进行交互。  
+ 将 React.js 网络应用程序与 AWS 服务集成。
+ 列出、添加、更新和删除 Amazon RDS 表中的项目。
+ 使用 Amazon SES 以电子邮件发送已筛选工作项的报告。
+ 使用随附的 AWS CloudFormation 脚本部署和管理示例资源。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/php/cross_service/aurora_item_tracker)。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 演示如何使用创建 REST 服务，该服务通过亚马逊简单电子邮件服务 (Amazon SES) 跟踪亚马逊Aurora无服务器数据库中的工作项目并通过电子邮件发送报告。 适用于 Python (Boto3) 的 AWS SDK 此示例使用 Flask Web 框架处理 HTTP 路由，并且与 React 网页集成来呈现完整功能的 Web 应用程序。  
+ 构建与 AWS 服务集成的 Flask REST 服务。
+ 读取、写入和更新存储在 Aurora Serverless 数据库中的工作项。
+ 创建包含数据库凭据的 AWS Secrets Manager 密钥，并使用它来验证对数据库的调用。
+ 使用 Amazon SES 发送工作项的电子邮件报告。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/cross_service/aurora_item_tracker)。  

**本示例中使用的服务**
+ Aurora
+ Amazon RDS
+ Amazon RDS 数据服务
+ Amazon SES

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用软件开发工具包使用 Amazon Rekognition 检测图像中的个人防护装备 AWS
<a name="ses_example_cross_RekognitionPhotoAnalyzerPPE_section"></a>

以下代码示例展示如何构建采用 Amazon Rekognition 来检测图像中的个人防护设备（PPE）的应用程序。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 演示如何创建使用个人防护设备检测图像的 AWS Lambda 功能。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_lambda_ppe)。  

**本示例中使用的服务**
+ DynamoDB
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用软件开发工具包使用 Amazon Rekognition 检测图像中的物体 AWS
<a name="ses_example_cross_RekognitionPhotoAnalyzer_section"></a>

以下代码示例展示如何构建采用 Amazon Rekognition 来按类别检测图像中对象的应用程序。

------
#### [ .NET ]

**适用于 .NET 的 SDK**  
 展示如何使用 Amazon Rekognition .NET API 创建应用程序，该应用程序采用 Amazon Rekognition 来按类别识别位于 Amazon Simple Storage Service (Amazon S3) 存储桶的图像中的对象。该应用程序使用 Amazon Simple Email Service (Amazon SES) 向管理员发送包含结果的电子邮件通知。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAnalyzerApp)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 展示如何使用 Amazon Rekognition Java API 创建应用程序，该应用程序采用 Amazon Rekognition 来按类别识别位于 Amazon Simple Storage Service (Amazon S3) 存储桶的图像当中的对象。该应用程序使用 Amazon Simple Email Service (Amazon SES) 向管理员发送包含结果的电子邮件通知。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_photo_analyzer_app)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------
#### [ JavaScript ]

**适用于 JavaScript (v3) 的软件开发工具包**  
 演示如何使用 Amazon Rekogn 适用于 JavaScript 的 AWS SDK ition 和，创建一款应用程序，该应用程序使用 Amazon Rekognition 按类别识别位于亚马逊简单存储服务 (Amazon S3) Simple S3 存储桶中的图像中的对象。该应用程序使用 Amazon Simple Email Service (Amazon SES) 向管理员发送包含结果的电子邮件通知。  
了解如何：  
+ 使用 Amazon Cognito 创建未经身份验证的用户。
+ 使用 Amazon Rekognition 分析包含对象的图像。
+ 为 Amazon SES 验证电子邮件地址。
+ 使用 Amazon SES 发送电子邮件通知。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3/example_code/cross-services/photo_analyzer)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------
#### [ Kotlin ]

**适用于 Kotlin 的 SDK**  
 展示如何使用 Amazon Rekognition Kotlin API 创建应用程序，该应用程序采用 Amazon Rekognition 来按类别识别位于 Amazon Simple Storage Service（Amazon S3）存储桶的图像当中的对象。该应用程序使用 Amazon Simple Email Service (Amazon SES) 向管理员发送包含结果的电子邮件通知。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin/usecases/creating_photo_analyzer_app)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 向您展示如何使用创建 适用于 Python (Boto3) 的 AWS SDK 允许您执行以下操作的 Web 应用程序：  
+ 将照片上载到 Amazon Simple Storage Service (Amazon S3) 存储桶。
+ 使用 Amazon Rekognition 来分析和标注照片。
+ 使用 Amazon Simple Email Service (Amazon SES) 发送图像分析的电子邮件报告。
 此示例包含两个主要组件：使用 React 构建的 JavaScript 网页和使用 Flask-RESTful 构建的用 Python 编写的 REST 服务。  
可以使用 React 网页执行以下操作：  
+ 显示存储在 S3 存储桶中的图像列表。
+ 将计算机中的图像上载到 S3 存储桶。
+ 显示图像和用于识别图像中检测到的物品的标注。
+ 获取 S3 存储桶中所有图像的报告并发送报告电子邮件。
该网页调用 REST 服务。该服务将请求发送到 AWS 以执行以下操作：  
+ 获取并筛选 S3 存储桶中的图像列表。
+ 将照片上载到 S3 存储桶。
+ 使用 Amazon Rekognition 分析各张照片并获取标注列表，这些标注用于识别在照片中检测到的物品。
+ 分析 S3 存储桶中的所有照片，然后使用 Amazon SES 通过电子邮件发送报告。
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/cross_service/photo_analyzer)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用 Amazon Rekognition 使用软件开发工具包检测视频中的人物和物体 AWS
<a name="ses_example_cross_RekognitionVideoDetection_section"></a>

以下代码示例展示如何使用 Amazon Rekognition 检测视频中的人物和对象。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 展示如何使用 Amazon Rekognition Java API 创建应用程序，以检测位于 Amazon Simple Storage Service (Amazon S3) 存储桶的视频当中的人脸和对象。该应用程序使用 Amazon Simple Email Service (Amazon SES) 向管理员发送包含结果的电子邮件通知。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/video_analyzer_application)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES
+ Amazon SNS
+ Amazon SQS

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 通过启动异步检测任务，使用 Amazon Rekognition 来检测视频中的人脸、对象和人物。此示例还将 Amazon Rekognition 配置为在任务完成时通知 Amazon Simple Notification Service (Amazon SNS) 主题，并订阅该主题的 Amazon Simple Queue Service (Amazon SQS) 队列。当队列收到有关任务的消息时，将检索该任务并输出结果。  
 最好在上查看此示例 GitHub。有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/rekognition)。  

**本示例中使用的服务**
+ Amazon Rekognition
+ Amazon S3
+ Amazon SES
+ Amazon SNS
+ Amazon SQS

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 生成凭证以连接到 Amazon SES SMTP 端点
<a name="ses_example_ses_Scenario_GenerateSmtpCredentials_section"></a>

以下代码示例展示如何生成连接以连接到 Amazon SES SMTP 端点。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 还有更多相关信息 GitHub。在 [AWS 代码示例存储库](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/ses#code-examples)中查找完整示例，了解如何进行设置和运行。

```
#!/usr/bin/env python3

import hmac
import hashlib
import base64
import argparse

SMTP_REGIONS = [
    "us-east-2",  # US East (Ohio)
    "us-east-1",  # US East (N. Virginia)
    "us-west-2",  # US West (Oregon)
    "ap-south-1",  # Asia Pacific (Mumbai)
    "ap-northeast-2",  # Asia Pacific (Seoul)
    "ap-southeast-1",  # Asia Pacific (Singapore)
    "ap-southeast-2",  # Asia Pacific (Sydney)
    "ap-northeast-1",  # Asia Pacific (Tokyo)
    "ca-central-1",  # Canada (Central)
    "eu-central-1",  # Europe (Frankfurt)
    "eu-west-1",  # Europe (Ireland)
    "eu-west-2",  # Europe (London)
    "eu-south-1",  # Europe (Milan)
    "eu-north-1",  # Europe (Stockholm)
    "sa-east-1",  # South America (Sao Paulo)
    "us-gov-west-1",  # AWS GovCloud (US)
    "us-gov-east-1",  # AWS GovCloud (US)
]

# These values are required to calculate the signature. Do not change them.
DATE = "11111111"
SERVICE = "ses"
MESSAGE = "SendRawEmail"
TERMINAL = "aws4_request"
VERSION = 0x04


def sign(key, msg):
    return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()


def calculate_key(secret_access_key, region):
    if region not in SMTP_REGIONS:
        raise ValueError(f"The {region} Region doesn't have an SMTP endpoint.")

    signature = sign(("AWS4" + secret_access_key).encode("utf-8"), DATE)
    signature = sign(signature, region)
    signature = sign(signature, SERVICE)
    signature = sign(signature, TERMINAL)
    signature = sign(signature, MESSAGE)
    signature_and_version = bytes([VERSION]) + signature
    smtp_password = base64.b64encode(signature_and_version)
    return smtp_password.decode("utf-8")


def main():
    parser = argparse.ArgumentParser(
        description="Convert a Secret Access Key to an SMTP password."
    )
    parser.add_argument("secret", help="The Secret Access Key to convert.")
    parser.add_argument(
        "region",
        help="The AWS Region where the SMTP password will be used.",
        choices=SMTP_REGIONS,
    )
    args = parser.parse_args()
    print(calculate_key(args.secret, args.region))


if __name__ == "__main__":
    main()
```

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用 Step Functions 调用 Lambda 函数
<a name="ses_example_cross_ServerlessWorkflows_section"></a>

以下代码示例说明如何创建按顺序调用 AWS Lambda 函数的 AWS Step Functions 状态机。

------
#### [ Java ]

**适用于 Java 的 SDK 2.x**  
 演示如何使用 AWS Step Functions 和创建 AWS 无服务器工作流程。 AWS SDK for Java 2.x每个工作流程步骤都是使用 AWS Lambda 函数实现的。  
 有关如何设置和运行的完整源代码和说明，请参阅上的完整示例[GitHub](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/usecases/creating_workflows_stepfunctions)。  

**本示例中使用的服务**
+ DynamoDB
+ Lambda
+ Amazon SES
+ Step Functions

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。

# 使用软件开发工具包验证电子邮件身份并通过 Amazon AWS SES 发送消息
<a name="ses_example_ses_Scenario_SendEmail_section"></a>

以下代码示例展示了如何：
+ 使用 Amazon SES 添加和验证电子邮件地址。
+ 发送标准电子邮件。
+ 创建模板和发送模板化电子邮件。
+ 使用 Amazon SES SMTP 服务器发送邮件。

------
#### [ Python ]

**适用于 Python 的 SDK（Boto3）**  
 还有更多相关信息 GitHub。在 [AWS 代码示例存储库](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python/example_code/ses#code-examples)中查找完整示例，了解如何进行设置和运行。
使用 Amazon SES 验证电子邮件地址，然后发送邮件。  

```
def usage_demo():
    print("-" * 88)
    print("Welcome to the Amazon Simple Email Service (Amazon SES) email demo!")
    print("-" * 88)

    logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")

    ses_client = boto3.client("ses")
    ses_identity = SesIdentity(ses_client)
    ses_mail_sender = SesMailSender(ses_client)
    ses_template = SesTemplate(ses_client)
    email = input("Enter an email address to send mail with Amazon SES: ")
    status = ses_identity.get_identity_status(email)
    verified = status == "Success"
    if not verified:
        answer = input(
            f"The address '{email}' is not verified with Amazon SES. Unless your "
            f"Amazon SES account is out of sandbox, you can send mail only from "
            f"and to verified accounts. Do you want to verify this account for use "
            f"with Amazon SES? If yes, the address will receive a verification "
            f"email (y/n): "
        )
        if answer.lower() == "y":
            ses_identity.verify_email_identity(email)
            print(f"Follow the steps in the email to {email} to complete verification.")
            print("Waiting for verification...")
            try:
                ses_identity.wait_until_identity_exists(email)
                print(f"Identity verified for {email}.")
                verified = True
            except WaiterError:
                print(
                    f"Verification timeout exceeded. You must complete the "
                    f"steps in the email sent to {email} to verify the address."
                )

    if verified:
        test_message_text = "Hello from the Amazon SES mail demo!"
        test_message_html = "<p>Hello!</p><p>From the <b>Amazon SES</b> mail demo!</p>"

        print(f"Sending mail from {email} to {email}.")
        ses_mail_sender.send_email(
            email,
            SesDestination([email]),
            "Amazon SES demo",
            test_message_text,
            test_message_html,
        )
        input("Mail sent. Check your inbox and press Enter to continue.")

        template = {
            "name": "doc-example-template",
            "subject": "Example of an email template.",
            "text": "This is what {{name}} will {{action}} if {{name}} can't display "
            "HTML.",
            "html": "<p><i>This</i> is what {{name}} will {{action}} if {{name}} "
            "<b>can</b> display HTML.</p>",
        }
        print("Creating a template and sending a templated email.")
        ses_template.create_template(**template)
        template_data = {"name": email.split("@")[0], "action": "read"}
        if ses_template.verify_tags(template_data):
            ses_mail_sender.send_templated_email(
                email, SesDestination([email]), ses_template.name(), template_data
            )
            input("Mail sent. Check your inbox and press Enter to continue.")

        print("Sending mail through the Amazon SES SMTP server.")
        boto3_session = boto3.Session()
        region = boto3_session.region_name
        credentials = boto3_session.get_credentials()
        port = 587
        smtp_server = f"email-smtp.{region}.amazonaws.com"
        password = calculate_key(credentials.secret_key, region)
        message = """
Subject: Hi there

This message is sent from the Amazon SES SMTP mail demo."""
        context = ssl.create_default_context()
        with smtplib.SMTP(smtp_server, port) as server:
            server.starttls(context=context)
            server.login(credentials.access_key, password)
            server.sendmail(email, email, message)
        print("Mail sent. Check your inbox!")

    if ses_template.template is not None:
        print("Deleting demo template.")
        ses_template.delete_template()
    if verified:
        answer = input(f"Do you want to remove {email} from Amazon SES (y/n)? ")
        if answer.lower() == "y":
            ses_identity.delete_identity(email)
    print("Thanks for watching!")
    print("-" * 88)
```
创建函数来封装 Amazon SES 身份操作。  

```
class SesIdentity:
    """Encapsulates Amazon SES identity functions."""

    def __init__(self, ses_client):
        """
        :param ses_client: A Boto3 Amazon SES client.
        """
        self.ses_client = ses_client


    def verify_domain_identity(self, domain_name):
        """
        Starts verification of a domain identity. To complete verification, you must
        create a TXT record with a specific format through your DNS provider.

        For more information, see *Verifying a domain with Amazon SES* in the
        Amazon SES documentation:
            https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-domain-procedure.html

        :param domain_name: The name of the domain to verify.
        :return: The token to include in the TXT record with your DNS provider.
        """
        try:
            response = self.ses_client.verify_domain_identity(Domain=domain_name)
            token = response["VerificationToken"]
            logger.info("Got domain verification token for %s.", domain_name)
        except ClientError:
            logger.exception("Couldn't verify domain %s.", domain_name)
            raise
        else:
            return token


    def verify_email_identity(self, email_address):
        """
        Starts verification of an email identity. This function causes an email
        to be sent to the specified email address from Amazon SES. To complete
        verification, follow the instructions in the email.

        :param email_address: The email address to verify.
        """
        try:
            self.ses_client.verify_email_identity(EmailAddress=email_address)
            logger.info("Started verification of %s.", email_address)
        except ClientError:
            logger.exception("Couldn't start verification of %s.", email_address)
            raise


    def wait_until_identity_exists(self, identity):
        """
        Waits until an identity exists. The waiter polls Amazon SES until the
        identity has been successfully verified or until it exceeds its maximum time.

        :param identity: The identity to wait for.
        """
        try:
            waiter = self.ses_client.get_waiter("identity_exists")
            logger.info("Waiting until %s exists.", identity)
            waiter.wait(Identities=[identity])
        except WaiterError:
            logger.error("Waiting for identity %s failed or timed out.", identity)
            raise


    def get_identity_status(self, identity):
        """
        Gets the status of an identity. This can be used to discover whether
        an identity has been successfully verified.

        :param identity: The identity to query.
        :return: The status of the identity.
        """
        try:
            response = self.ses_client.get_identity_verification_attributes(
                Identities=[identity]
            )
            status = response["VerificationAttributes"].get(
                identity, {"VerificationStatus": "NotFound"}
            )["VerificationStatus"]
            logger.info("Got status of %s for %s.", status, identity)
        except ClientError:
            logger.exception("Couldn't get status for %s.", identity)
            raise
        else:
            return status


    def delete_identity(self, identity):
        """
        Deletes an identity.

        :param identity: The identity to remove.
        """
        try:
            self.ses_client.delete_identity(Identity=identity)
            logger.info("Deleted identity %s.", identity)
        except ClientError:
            logger.exception("Couldn't delete identity %s.", identity)
            raise


    def list_identities(self, identity_type, max_items):
        """
        Gets the identities of the specified type for the current account.

        :param identity_type: The type of identity to retrieve, such as EmailAddress.
        :param max_items: The maximum number of identities to retrieve.
        :return: The list of retrieved identities.
        """
        try:
            response = self.ses_client.list_identities(
                IdentityType=identity_type, MaxItems=max_items
            )
            identities = response["Identities"]
            logger.info("Got %s identities for the current account.", len(identities))
        except ClientError:
            logger.exception("Couldn't list identities for the current account.")
            raise
        else:
            return identities
```
创建函数来封装 Amazon SES 模板操作。  

```
class SesTemplate:
    """Encapsulates Amazon SES template functions."""

    def __init__(self, ses_client):
        """
        :param ses_client: A Boto3 Amazon SES client.
        """
        self.ses_client = ses_client
        self.template = None
        self.template_tags = set()

    def _extract_tags(self, subject, text, html):
        """
        Extracts tags from a template as a set of unique values.

        :param subject: The subject of the email.
        :param text: The text version of the email.
        :param html: The html version of the email.
        """
        self.template_tags = set(re.findall(TEMPLATE_REGEX, subject + text + html))
        logger.info("Extracted template tags: %s", self.template_tags)


    def create_template(self, name, subject, text, html):
        """
        Creates an email template.

        :param name: The name of the template.
        :param subject: The subject of the email.
        :param text: The plain text version of the email.
        :param html: The HTML version of the email.
        """
        try:
            template = {
                "TemplateName": name,
                "SubjectPart": subject,
                "TextPart": text,
                "HtmlPart": html,
            }
            self.ses_client.create_template(Template=template)
            logger.info("Created template %s.", name)
            self.template = template
            self._extract_tags(subject, text, html)
        except ClientError:
            logger.exception("Couldn't create template %s.", name)
            raise


    def delete_template(self):
        """
        Deletes an email template.
        """
        try:
            self.ses_client.delete_template(TemplateName=self.template["TemplateName"])
            logger.info("Deleted template %s.", self.template["TemplateName"])
            self.template = None
            self.template_tags = None
        except ClientError:
            logger.exception(
                "Couldn't delete template %s.", self.template["TemplateName"]
            )
            raise


    def get_template(self, name):
        """
        Gets a previously created email template.

        :param name: The name of the template to retrieve.
        :return: The retrieved email template.
        """
        try:
            response = self.ses_client.get_template(TemplateName=name)
            self.template = response["Template"]
            logger.info("Got template %s.", name)
            self._extract_tags(
                self.template["SubjectPart"],
                self.template["TextPart"],
                self.template["HtmlPart"],
            )
        except ClientError:
            logger.exception("Couldn't get template %s.", name)
            raise
        else:
            return self.template


    def list_templates(self):
        """
        Gets a list of all email templates for the current account.

        :return: The list of retrieved email templates.
        """
        try:
            response = self.ses_client.list_templates()
            templates = response["TemplatesMetadata"]
            logger.info("Got %s templates.", len(templates))
        except ClientError:
            logger.exception("Couldn't get templates.")
            raise
        else:
            return templates


    def update_template(self, name, subject, text, html):
        """
        Updates a previously created email template.

        :param name: The name of the template.
        :param subject: The subject of the email.
        :param text: The plain text version of the email.
        :param html: The HTML version of the email.
        """
        try:
            template = {
                "TemplateName": name,
                "SubjectPart": subject,
                "TextPart": text,
                "HtmlPart": html,
            }
            self.ses_client.update_template(Template=template)
            logger.info("Updated template %s.", name)
            self.template = template
            self._extract_tags(subject, text, html)
        except ClientError:
            logger.exception("Couldn't update template %s.", name)
            raise
```
创建函数来封装 Amazon SES 电子邮件操作。  

```
class SesDestination:
    """Contains data about an email destination."""

    def __init__(self, tos, ccs=None, bccs=None):
        """
        :param tos: The list of recipients on the 'To:' line.
        :param ccs: The list of recipients on the 'CC:' line.
        :param bccs: The list of recipients on the 'BCC:' line.
        """
        self.tos = tos
        self.ccs = ccs
        self.bccs = bccs

    def to_service_format(self):
        """
        :return: The destination data in the format expected by Amazon SES.
        """
        svc_format = {"ToAddresses": self.tos}
        if self.ccs is not None:
            svc_format["CcAddresses"] = self.ccs
        if self.bccs is not None:
            svc_format["BccAddresses"] = self.bccs
        return svc_format



class SesMailSender:
    """Encapsulates functions to send emails with Amazon SES."""

    def __init__(self, ses_client):
        """
        :param ses_client: A Boto3 Amazon SES client.
        """
        self.ses_client = ses_client


    def send_email(self, source, destination, subject, text, html, reply_tos=None):
        """
        Sends an email.

        Note: If your account is in the Amazon SES  sandbox, the source and
        destination email accounts must both be verified.

        :param source: The source email account.
        :param destination: The destination email account.
        :param subject: The subject of the email.
        :param text: The plain text version of the body of the email.
        :param html: The HTML version of the body of the email.
        :param reply_tos: Email accounts that will receive a reply if the recipient
                          replies to the message.
        :return: The ID of the message, assigned by Amazon SES.
        """
        send_args = {
            "Source": source,
            "Destination": destination.to_service_format(),
            "Message": {
                "Subject": {"Data": subject},
                "Body": {"Text": {"Data": text}, "Html": {"Data": html}},
            },
        }
        if reply_tos is not None:
            send_args["ReplyToAddresses"] = reply_tos
        try:
            response = self.ses_client.send_email(**send_args)
            message_id = response["MessageId"]
            logger.info(
                "Sent mail %s from %s to %s.", message_id, source, destination.tos
            )
        except ClientError:
            logger.exception(
                "Couldn't send mail from %s to %s.", source, destination.tos
            )
            raise
        else:
            return message_id


    def send_templated_email(
        self, source, destination, template_name, template_data, reply_tos=None
    ):
        """
        Sends an email based on a template. A template contains replaceable tags
        each enclosed in two curly braces, such as {{name}}. The template data passed
        in this function contains key-value pairs that define the values to insert
        in place of the template tags.

        Note: If your account is in the Amazon SES  sandbox, the source and
        destination email accounts must both be verified.

        :param source: The source email account.
        :param destination: The destination email account.
        :param template_name: The name of a previously created template.
        :param template_data: JSON-formatted key-value pairs of replacement values
                              that are inserted in the template before it is sent.
        :return: The ID of the message, assigned by Amazon SES.
        """
        send_args = {
            "Source": source,
            "Destination": destination.to_service_format(),
            "Template": template_name,
            "TemplateData": json.dumps(template_data),
        }
        if reply_tos is not None:
            send_args["ReplyToAddresses"] = reply_tos
        try:
            response = self.ses_client.send_templated_email(**send_args)
            message_id = response["MessageId"]
            logger.info(
                "Sent templated mail %s from %s to %s.",
                message_id,
                source,
                destination.tos,
            )
        except ClientError:
            logger.exception(
                "Couldn't send templated mail from %s to %s.", source, destination.tos
            )
            raise
        else:
            return message_id
```
+ 有关 API 详细信息，请参阅《AWS SDK for Python (Boto3) API Reference》**中的以下主题。
  + [CreateTemplate](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/CreateTemplate)
  + [DeleteIdentity](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/DeleteIdentity)
  + [DeleteTemplate](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/DeleteTemplate)
  + [GetIdentityVerificationAttributes](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/GetIdentityVerificationAttributes)
  + [GetTemplate](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/GetTemplate)
  + [ListIdentities](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/ListIdentities)
  + [ListTemplates](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/ListTemplates)
  + [SendEmail](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/SendEmail)
  + [SendTemplatedEmail](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/SendTemplatedEmail)
  + [UpdateTemplate](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/UpdateTemplate)
  + [VerifyDomainIdentity](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/VerifyDomainIdentity)
  + [VerifyEmailIdentity](https://docs.aws.amazon.com/goto/boto3/email-2010-12-01/VerifyEmailIdentity)

------

有关 S AWS DK 开发者指南和代码示例的完整列表，请参阅[将 Amazon SES 与 AWS 软件开发工具包配合使用](sdk-general-information-section.md)。本主题还包括有关入门的信息以及有关先前的 SDK 版本的详细信息。