本文へ移動
cccskills
無料GitHub で公開

aws-ses

Amazon SES (Simple Email Service) sends and receives email through AWS: transactional and marketing mail, templates, bounce and complaint tracking, and inbound mail processing. Use when a user asks to send email with SES, verify a domain or set up DKIM, move an SES account out of the sandbox, create or bulk-send email templates, add an attachment or unsubscribe header, handle bounces and complaints with SNS, manage the suppression list, or store incoming mail in S3 with receipt rules. Covers the SES v2 API (aws sesv2, boto3 sesv2).

インストール方法を見る

含まれるファイル(2)

  • SKILL.md14.1 KB
  • _scores.json1.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

AWS SES

Overview

Amazon Simple Email Service (SES) is a pay-per-message email platform for transactional, marketing, and notification mail. It also receives incoming email and hands it to S3, SNS, or Lambda. Use the v2 API (aws sesv2, boto3.client('sesv2')) for everything except receipt rules and get-send-statistics, which exist only in the v1 API (aws ses). Identities, templates, quotas and the sandbox status are all per Region.

  • Verified identity — domain or email address authorized to send
  • Configuration set — named group of settings and event destinations applied per message
  • Template — stored subject and body with {{variable}} placeholders
  • Suppression list — account-level list of addresses that hard-bounced or complained
  • Sandbox — the state of every new account: verified recipients only, 200 messages per 24 hours, 1 per second

Instructions

Verify a domain

# Create the identity; Easy DKIM (2048-bit) is the default and doubles as domain verification
aws sesv2 create-email-identity --email-identity mail.brightcart.io

# Three tokens plus the hosted zone to build the CNAME records from
aws sesv2 get-email-identity --email-identity mail.brightcart.io \
  --query 'DkimAttributes.{Tokens:Tokens,Zone:SigningHostedZone,Status:Status}'

For each token publish TOKEN._domainkey.mail.brightcart.io CNAME TOKEN.SIGNING_HOSTED_ZONE. The hosted zone differs per Region, so read it from the response instead of hard-coding dkim.amazonses.com. Verification completes when SES sees all three records (DNS changes can take up to 72 hours).

# A single address instead of a domain: SES emails a confirmation link valid for 24 hours
aws sesv2 create-email-identity --email-identity orders@brightcart.io

# Custom MAIL FROM (aligns SPF for DMARC). Then publish on bounce.mail.brightcart.io:
#   MX  10 feedback-smtp.us-east-1.amazonses.com      TXT  "v=spf1 include:amazonses.com ~all"
aws sesv2 put-email-identity-mail-from-attributes --email-identity mail.brightcart.io \
  --mail-from-domain bounce.mail.brightcart.io --behavior-on-mx-failure USE_DEFAULT_VALUE

aws sesv2 list-email-identities --query 'EmailIdentities[].[IdentityName,VerificationStatus]'

Sandbox, quota and statistics

aws sesv2 get-account --query '{Production:ProductionAccessEnabled,Quota:SendQuota,Sending:SendingEnabled}'
aws ses get-send-statistics --query 'SendDataPoints[-5:]'   # sends, bounces, complaints per 15-minute interval

aws sesv2 put-account-details --production-access-enabled --mail-type TRANSACTIONAL \
  --website-url https://brightcart.io --contact-language EN \
  --use-case-description "Order confirmations and password resets for registered customers" \
  --additional-contact-email-addresses ops@brightcart.io

AWS Support gives a first response within 24 hours. Until access is granted you can only send to verified identities and the mailbox simulator. Sandbox status is per Region.

Send email

aws sesv2 send-email \
  --from-email-address "BrightCart <orders@mail.brightcart.io>" \
  --destination '{"ToAddresses":["dana.whitfield@oakridgeclinic.org"]}' \
  --content '{
    "Simple": {
      "Subject": {"Data": "Order confirmation #48213"},
      "Body": {
        "Html": {"Data": "<h1>Thank you!</h1><p>Your order has been confirmed.</p>"},
        "Text": {"Data": "Thank you! Your order has been confirmed."}
      }
    }
  }' \
  --configuration-set-name prod-tracking

--configuration-set-name must name an existing configuration set: create prod-tracking first (see Bounce and complaint handling) or omit the flag. Content takes exactly one of Simple, Template or Raw (a full MIME message). Simple and Template also accept Headers and Attachments, so attachments no longer require building raw MIME (see Example 1).

Email templates

aws sesv2 create-email-template \
  --template-name order-confirmation \
  --template-content '{
    "Subject": "Order confirmation #{{orderNumber}}",
    "Html": "<h1>Hi {{customerName}},</h1><p>Your order #{{orderNumber}} for {{itemName}} is confirmed.</p><p>Total: ${{total}}</p>",
    "Text": "Hi {{customerName}},\nYour order #{{orderNumber}} for {{itemName}} is confirmed.\nTotal: ${{total}}"
  }'

# Render locally-supplied data against the stored template before sending
aws sesv2 test-render-email-template --template-name order-confirmation \
  --template-data '{"orderNumber":"48213","customerName":"Dana","itemName":"Trail Pack 30L","total":"89.00"}'

aws sesv2 send-email \
  --from-email-address "orders@mail.brightcart.io" \
  --destination '{"ToAddresses":["dana.whitfield@oakridgeclinic.org"]}' \
  --content '{"Template": {"TemplateName": "order-confirmation",
    "TemplateData": "{\"orderNumber\":\"48213\",\"customerName\":\"Dana\",\"itemName\":\"Trail Pack 30L\",\"total\":\"89.00\"}"}}'
# Bulk send: one personalized message per entry, at most 50 entries per call. Assumes a
# `weekly-newsletter` template with {{name}} and {{picks}} and a `marketing-tracking` configuration set.
import json
import boto3

ses = boto3.client('sesv2', region_name='us-east-1')
subscribers = [
    {'email': 'alice.moreno@oakridgeclinic.org', 'name': 'Alice', 'picks': 'Trail Pack 30L, Merino Socks'},
    {'email': 'omar.haddad@fernwoodlabs.net', 'name': 'Omar', 'picks': 'Summit Tent 2P, Camp Stove'},
]

response = ses.send_bulk_email(
    FromEmailAddress='news@mail.brightcart.io',
    DefaultContent={'Template': {'TemplateName': 'weekly-newsletter',
                                 'TemplateData': json.dumps({'name': 'there', 'picks': ''})}},
    BulkEmailEntries=[
        {'Destination': {'ToAddresses': [s['email']]},
         'ReplacementEmailContent': {'ReplacementTemplate': {
             'ReplacementTemplateData': json.dumps({'name': s['name'], 'picks': s['picks']})}}}
        for s in subscribers
    ],
    ConfigurationSetName='marketing-tracking',
)
for sub, result in zip(subscribers, response['BulkEmailEntryResults']):
    print(sub['email'], result['Status'], result.get('MessageId') or result.get('Error'))

The call succeeds even when individual entries fail; check each Status (SUCCESS, MESSAGE_REJECTED, ACCOUNT_THROTTLED, ...). A message whose template data is missing a variable is accepted and then dropped, visible only as a RENDERING_FAILURE event.

Bounce and complaint handling

aws sesv2 create-configuration-set --configuration-set-name prod-tracking

aws sesv2 create-configuration-set-event-destination \
  --configuration-set-name prod-tracking \
  --event-destination-name bounce-handler \
  --event-destination '{
    "Enabled": true,
    "MatchingEventTypes": ["BOUNCE", "COMPLAINT", "RENDERING_FAILURE"],
    "SnsDestination": {"TopicArn": "arn:aws:sns:us-east-1:111122223333:ses-events"}
  }'
# Lambda subscribed to the SNS topic
import json

def handler(event, context):
    for record in event['Records']:
        message = json.loads(record['Sns']['Message'])
        # Event publishing uses "eventType"; identity feedback notifications use "notificationType"
        kind = message.get('eventType') or message.get('notificationType')

        if kind == 'Bounce' and message['bounce']['bounceType'] == 'Permanent':
            for recipient in message['bounce']['bouncedRecipients']:
                mark_undeliverable(recipient['emailAddress'])      # your own data store
        elif kind == 'Complaint':
            for recipient in message['complaint']['complainedRecipients']:
                unsubscribe(recipient['emailAddress'])

SES also keeps an account-level suppression list and silently skips addresses on it:

aws sesv2 put-account-suppression-attributes --suppressed-reasons BOUNCE COMPLAINT
aws sesv2 list-suppressed-destinations --reasons BOUNCE
aws sesv2 get-suppressed-destination --email-address dana.whitfield@oakridgeclinic.org
aws sesv2 put-suppressed-destination --email-address old.account@fernwoodlabs.net --reason BOUNCE

Receiving email

Verify the receiving domain itself as an identity (aws sesv2 create-email-identity --email-identity brightcart.io; the mail. subdomain does not cover it), publish an MX record for it (10 inbound-smtp.us-east-1.amazonaws.com; only some Regions have an inbound endpoint), then create receipt rules with the v1 API:

aws ses create-receipt-rule-set --rule-set-name inbound-rules
aws ses set-active-receipt-rule-set --rule-set-name inbound-rules

aws ses create-receipt-rule \
  --rule-set-name inbound-rules \
  --rule '{
    "Name": "process-support-emails",
    "Enabled": true,
    "Recipients": ["support@brightcart.io"],
    "Actions": [
      {"S3Action": {"BucketName": "brightcart-inbound-mail", "ObjectKeyPrefix": "support/"}},
      {"LambdaAction": {"FunctionArn": "arn:aws:lambda:us-east-1:111122223333:function:process-support-email"}}
    ]
  }'

The bucket policy must allow ses.amazonaws.com to s3:PutObject, and the function needs a resource policy that lets SES invoke it; otherwise create-receipt-rule fails.

Examples

Example 1: Order confirmation with a PDF invoice

User request: "Send the order confirmation from our Python backend with the invoice PDF attached, and make sure a throttled send is retried."

import boto3
from botocore.config import Config
from botocore.exceptions import ClientError

ses = boto3.client('sesv2', region_name='us-east-1',
                   config=Config(retries={'mode': 'adaptive', 'max_attempts': 5}))

with open('invoices/INV-48213.pdf', 'rb') as f:
    invoice = f.read()

try:
    response = ses.send_email(
        FromEmailAddress='BrightCart <orders@mail.brightcart.io>',
        Destination={'ToAddresses': ['dana.whitfield@oakridgeclinic.org']},
        ReplyToAddresses=['support@brightcart.io'],
        Content={'Simple': {
            'Subject': {'Data': 'Your BrightCart order #48213'},
            'Body': {'Html': {'Data': '<p>Thanks, Dana. Your invoice is attached.</p>'},
                     'Text': {'Data': 'Thanks, Dana. Your invoice is attached.'}},
            'Attachments': [{'FileName': 'INV-48213.pdf', 'RawContent': invoice,
                             'ContentType': 'application/pdf'}],
        }},
        ConfigurationSetName='prod-tracking',
        EmailTags=[{'Name': 'type', 'Value': 'order-confirmation'}],
    )
    print(response['MessageId'])
except ClientError as err:
    # MessageRejected, MailFromDomainNotVerifiedException, AccountSuspendedException, ...
    print(err.response['Error']['Code'], err.response['Error']['Message'])
    raise

Result: the script prints the SES message ID, for example 0100019a2c4e7f31-5d0c8b7e-3f41-4a55-9d2e-7c1b6a40e9d2-000000. TooManyRequestsException is retried by the SDK; in the sandbox an unverified recipient raises MessageRejected with "Email address is not verified".

Example 2: Test bounce handling without hurting reputation

User request: "Before we go live, prove that a hard bounce reaches our SNS topic."

aws sesv2 send-email \
  --from-email-address orders@mail.brightcart.io \
  --destination '{"ToAddresses":["bounce@simulator.amazonses.com"]}' \
  --content '{"Simple":{"Subject":{"Data":"Bounce test"},"Body":{"Text":{"Data":"Simulated hard bounce"}}}}' \
  --configuration-set-name prod-tracking

Within seconds the SNS topic receives a record like this (trimmed):

{
  "eventType": "Bounce",
  "bounce": {
    "bounceType": "Permanent",
    "bounceSubType": "General",
    "bouncedRecipients": [
      {"emailAddress": "bounce@simulator.amazonses.com", "action": "failed", "status": "5.1.1",
       "diagnosticCode": "smtp; 550 5.1.1 user unknown"}
    ]
  },
  "mail": {"source": "orders@mail.brightcart.io", "tags": {"ses:configuration-set": ["prod-tracking"]}}
}

Other simulator addresses: success@, complaint@, ooto@ and suppressionlist@simulator.amazonses.com. Simulator mail works in the sandbox and does not count toward the daily quota or the bounce and complaint rates, but it is billed.

Guidelines

  • Send from a subdomain (mail.brightcart.io) with DKIM, a custom MAIL FROM and a DMARC record, so marketing problems do not damage the main domain.
  • Set up bounce and complaint handling before sending at volume. AWS puts an account under review at a 5% bounce rate or a 0.1% complaint rate and may pause sending at 10% or 0.5%.
  • Remove permanently bounced addresses from your own lists as well; the suppression list only stops SES from retrying them.
  • Bulk and marketing mail must carry one-click unsubscribe (List-Unsubscribe and List-Unsubscribe-Post headers), required by Gmail and Yahoo. Either pass them in Headers, or use an SES contact list with ListManagementOptions and the {{amazonSESUnsubscribeUrl}} placeholder.
  • TemplateData is a JSON string, not an object; build it with json.dumps rather than by hand.
  • Grant the sending role only ses:SendEmail (and ses:SendBulkEmail if needed), restricted to the ARNs of the identity, configuration set and templates it uses; do not hand application servers ses:*.
  • Never put AWS keys in code. Use an instance or task role, or a named profile through AWS_PROFILE.
  • Open tracking is unreliable (mail clients prefetch images; events carry isBotEvent). Use delivery, bounce and complaint events for decisions.
  • Not a mailbox: SES receiving hands messages to S3, SNS or Lambda and offers no IMAP or POP3. For hosted mailboxes use a mail provider.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Scripts and configures production rendering in Autodesk 3ds Max with the V-Ray and Corona renderers: output size and files, render elements, denoising, light mix, batch and command-line rendering, and network rendering. Use when a user asks to set up a production render, render several cameras in one batch, render from the command line or on a render farm, add render passes for compositing, or cut render time for archviz and product shots.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

Covers scripting Autodesk 3ds Max, the 3D modeling and rendering application, with MAXScript and Python (pymxs): scene manipulation, object creation, material assignment, camera and light setup, batch operations, and file I/O. Use when tasks involve automating repetitive 3ds Max workflows, batch processing scenes, running scripts headless with 3dsmaxbatch, creating custom tools, or scripting scene setup for archviz, product visualization, or VFX.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

3proxy

無料

3proxy is a small open-source proxy server that runs HTTP/HTTPS, SOCKS4/5, SNI and TCP/UDP port-mapping proxies from one config file. Use when a user asks to set up an HTTP or SOCKS5 proxy, add proxy users and passwords, write 3proxy access rules, chain or rotate upstream (parent) proxies, limit bandwidth, connections or monthly traffic per user, run 3proxy in Docker, or fix a 3proxy.cfg that will not start.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

Builds Agent2Agent (A2A) servers and clients, the open protocol (originally from Google, now under the Linux Foundation) that lets AI agents from different frameworks call each other. Use when the user wants to create an A2A-compliant agent, build an Agent Card, implement task management, connect agents across frameworks, set up agent discovery, handle streaming responses, implement push notifications, or orchestrate multi-agent workflows. Trigger words: a2a, agent to agent, agent2agent, a2a protocol, a2a server, a2a client, agent card, agent interoperability, agent collaboration, multi-agent, agent discovery, a2a sdk, a2a task.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

Plans a controlled experiment (A/B test) so its result can be trusted: writes the hypothesis, picks one primary metric and the guardrails, computes sample size and run time, specifies how visitors are assigned and when exposure is logged, and reads out the result with a confidence interval. Use when someone says "set up an A/B test", "split test this page", "how many visitors do I need", "how long should the experiment run", "is this result significant", "can I stop the test early", or wants to test a headline, price, layout or onboarding change against the current version.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

ably

無料

Ably is a hosted realtime messaging service: clients publish and subscribe to named channels over WebSockets, see who is present, replay message history, and resume after a dropped connection. Use when a user asks to "add realtime updates", "push live notifications to the browser", "show who is online", "add a chat room with typing indicators", "publish from a serverless function", or "authenticate Ably clients without exposing the API key". Covers the ably 2.x JavaScript SDK (Realtime and REST), JWT token authentication, presence, history and rewind, batch publishing, and the @ably/chat 1.x SDK.

日本語の概要は準備中です。原文の説明を表示しています。

TerminalSkills/skills1652026年10月4日 更新

TerminalSkills のスキルをすべて見る

このスキルの問題を報告する