home / skills / different-ai / agent-bank / aws-ses-inbound

aws-ses-inbound skill

/.opencode/skill/aws-ses-inbound

This skill guides you through configuring AWS SES inbound Email reception with SNS webhook delivery, yielding active rule sets and confirmed subscriptions.

npx playbooks add skill different-ai/agent-bank --skill aws-ses-inbound

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.3 KB
---
name: aws-ses-inbound
description: Set up AWS SES for receiving inbound emails with SNS webhook delivery
license: MIT
compatibility: opencode
metadata:
  service: aws
  category: email
---

## Skill Contract

### Purpose

- Configure SES inbound email reception with SNS webhook delivery.

### Inputs

- AWS credentials, verified domain, and HTTPS webhook endpoint.

### Outputs

- Active receipt rule set and confirmed SNS subscription.

### Completion Signals

- `complete` when the rule set is active and SNS shows confirmed subscription.
- `continue` when awaiting DNS verification or subscription confirmation.
- `error` on permission failures or invalid credentials.

### Credential Missing Behavior

- If AWS credentials are missing, ask the user and stop.

## What I Do

Set up Amazon SES (Simple Email Service) for receiving inbound emails and forwarding them to a webhook via SNS (Simple Notification Service). This is commonly used for:

- AI email agents that process incoming emails
- Email-to-ticket systems
- Inbound email parsing APIs

## Prerequisites

- AWS CLI installed: `brew install awscli` or `pip install awscli`
- AWS credentials with SES and SNS permissions
- Domain with configurable DNS (for MX records)

## Credential Setup

Set credentials via environment variables:

```bash
export AWS_ACCESS_KEY_ID='AKIA...'
export AWS_SECRET_ACCESS_KEY='...'
export AWS_DEFAULT_REGION='us-east-1'
```

Or use AWS CLI profile:

```bash
aws configure --profile ses-admin
export AWS_PROFILE=ses-admin
```

## Supported Regions for SES Inbound

SES inbound email is only available in:

- `us-east-1` (N. Virginia)
- `us-west-2` (Oregon)
- `eu-west-1` (Ireland)

## Complete Setup Flow

### Step 1: Verify Domain in SES

```bash
# Register domain for verification
aws ses verify-domain-identity --domain example.com

# Response includes VerificationToken - add as TXT record:
# Name: _amazonses.example.com
# Value: <VerificationToken>
```

### Step 2: Get DKIM Tokens

```bash
# Get DKIM tokens for email authentication
aws ses verify-domain-dkim --domain example.com

# Response includes 3 DkimTokens - add as CNAME records:
# Name: <token>._domainkey.example.com
# Value: <token>.dkim.amazonses.com
```

### Step 3: Create SNS Topic

```bash
# Create topic for receiving email notifications
aws sns create-topic --name my-inbound-email-topic

# Save the TopicArn from response
```

### Step 4: Create SES Receipt Rule Set

```bash
# Create a rule set (container for rules)
aws ses create-receipt-rule-set --rule-set-name my-email-rules
```

### Step 5: Create Receipt Rule

```bash
# Create rule to forward emails to SNS
aws ses create-receipt-rule \
  --rule-set-name my-email-rules \
  --rule '{
    "Name": "forward-to-sns",
    "Enabled": true,
    "Recipients": ["example.com"],
    "Actions": [
      {
        "SNSAction": {
          "TopicArn": "arn:aws:sns:us-east-1:123456789:my-inbound-email-topic",
          "Encoding": "UTF-8"
        }
      }
    ],
    "ScanEnabled": true
  }'
```

### Step 6: Activate Rule Set

```bash
# Only one rule set can be active at a time
aws ses set-active-receipt-rule-set --rule-set-name my-email-rules
```

### Step 7: Subscribe Webhook to SNS

```bash
# Subscribe your HTTPS endpoint to the SNS topic
# IMPORTANT: Use --notification-endpoint, NOT --endpoint
# (--endpoint overrides the AWS API URL, which is NOT what you want)
aws sns subscribe \
  --topic-arn "arn:aws:sns:us-east-1:123456789:my-inbound-email-topic" \
  --protocol https \
  --notification-endpoint "https://example.com/api/email-webhook"
```

**Important**: Your webhook endpoint must handle the SNS subscription confirmation request. SNS sends a POST with:

- Header: `x-amz-sns-message-type: SubscriptionConfirmation`
- Body: JSON with `Type`, `SubscribeURL`, `Token`, etc.

Your endpoint must visit the `SubscribeURL` (make a GET request) to confirm the subscription.

## Required DNS Records

After running the SES commands, add these DNS records:

### Domain Verification (TXT)

```
Name: _amazonses.example.com
Type: TXT
Value: <VerificationToken from verify-domain-identity>
```

### DKIM Records (3 CNAMEs)

```
Name: <token1>._domainkey.example.com
Type: CNAME
Value: <token1>.dkim.amazonses.com

Name: <token2>._domainkey.example.com
Type: CNAME
Value: <token2>.dkim.amazonses.com

Name: <token3>._domainkey.example.com
Type: CNAME
Value: <token3>.dkim.amazonses.com
```

### MX Record (for receiving email)

```
Name: example.com (or subdomain like mail.example.com)
Type: MX
Priority: 10
Value: inbound-smtp.<region>.amazonaws.com
```

For us-east-1: `inbound-smtp.us-east-1.amazonaws.com`

## Checking Status

### Verify Domain Status

```bash
aws ses get-identity-verification-attributes --identities example.com
# VerificationStatus should be "Success"
```

### Check DKIM Status

```bash
aws ses get-identity-dkim-attributes --identities example.com
# DkimVerificationStatus should be "Success"
```

### List Receipt Rules

```bash
aws ses describe-active-receipt-rule-set
aws ses describe-receipt-rule --rule-set-name my-email-rules --rule-name forward-to-sns
```

### List SNS Subscriptions

```bash
aws sns list-subscriptions-by-topic --topic-arn "arn:aws:sns:..."
# SubscriptionArn should show confirmed ARN, not "PendingConfirmation"
```

## Webhook Payload Format

SNS sends JSON with this structure:

```json
{
  "Type": "Notification",
  "MessageId": "...",
  "TopicArn": "arn:aws:sns:...",
  "Message": "{\"notificationType\":\"Received\",\"content\":\"<raw MIME email>\",...}",
  "Timestamp": "...",
  "Signature": "...",
  "SigningCertURL": "..."
}
```

The `Message` field contains a JSON string with:

- `notificationType`: "Received" for incoming emails
- `content`: Raw MIME email content (needs parsing)
- `mail`: Metadata (messageId, source, destination, headers)

Use a library like `mailparser` (Node.js) or `email` (Python) to parse the MIME content.

## SNS Subscription Confirmation

When you first subscribe, SNS sends a confirmation request:

```json
{
  "Type": "SubscriptionConfirmation",
  "SubscribeURL": "https://sns.us-east-1.amazonaws.com/?Action=ConfirmSubscription&...",
  "Token": "...",
  "TopicArn": "..."
}
```

Your webhook must:

1. Detect `Type === "SubscriptionConfirmation"`
2. Make a GET request to the `SubscribeURL`
3. Return 200 OK

## Signature Verification

Always verify SNS message signatures in production:

1. Validate `SigningCertURL` is from `*.amazonaws.com`
2. Fetch the certificate
3. Build the canonical message string
4. Verify signature using the certificate's public key

## Troubleshooting

### "Domain not verified"

- Check TXT record: `dig _amazonses.example.com TXT`
- DNS propagation can take up to 72 hours (usually 5-30 min)

### "DKIM not verified"

- Check CNAME records: `dig <token>._domainkey.example.com CNAME`
- Ensure all 3 DKIM records are added

### Emails not arriving

- Verify MX record points to correct SES inbound server
- Check receipt rule set is active
- Verify recipient domain/address matches rule

### Webhook not receiving

- Check SNS subscription status (should not be "PendingConfirmation")
- Verify endpoint is publicly accessible via HTTPS
- Check endpoint handles SNS confirmation handshake
- Review CloudWatch logs for SNS delivery failures

### "Access Denied" errors

- Verify IAM user has `AmazonSESFullAccess` and `AmazonSNSFullAccess` policies
- Check region is correct (SES inbound only in us-east-1, us-west-2, eu-west-1)

Overview

This skill configures AWS SES to receive inbound email and forwards messages to an HTTPS webhook via SNS. It automates creating a receipt rule set, adding a receipt rule that publishes incoming mail to an SNS topic, and guiding DNS and subscription steps. The goal is a working inbound pipeline with a confirmed SNS subscription and an active SES rule set.

How this skill works

The skill runs the SES and SNS CLI commands to verify a domain, request DKIM tokens, create an SNS topic, create and activate a receipt rule set, and add a rule that publishes received email to SNS. It instructs you to add DNS records (TXT for verification, three CNAMEs for DKIM, and an MX record) and to confirm the HTTPS subscription by handling SNS SubscriptionConfirmation messages. It checks SES/DKIM verification status and SNS subscription state to signal completion.

When to use it

  • You need programmatic inbound email delivery into an AI agent or webhook.
  • Building email-to-ticket or email-parsing integrations.
  • Routing mail to a serverless processor or webhook for automated workflows.
  • Preparing a verified domain and AWS credentials for production inbound mail.
  • Migrating inbound email handling to SES/SNS in supported regions.

Best practices

  • Use AWS credentials with SES and SNS permissions, or set an aws CLI profile before running commands.
  • Only run SES inbound in supported regions: us-east-1, us-west-2, eu-west-1.
  • Add TXT, CNAME, and MX records exactly as returned by SES; DNS propagation may take up to 72 hours.
  • Ensure your webhook handles SNS SubscriptionConfirmation and verifies SNS message signatures in production.
  • Enable ScanEnabled on receipt rules to let SES scan for spam/virus where appropriate.

Example use cases

  • AI email agent that parses inbound messages and triggers workflows via webhook.
  • Email-to-ticket system that converts incoming mail into support items.
  • Inbound parsing service that extracts structured data from raw MIME payloads.
  • Secure webhook pipeline for incoming transactional or notification emails.
  • Serverless processors (Lambda behind HTTPS) subscribed to SNS for scaled handling.

FAQ

How do I confirm the SNS subscription?

Your webhook must handle SubscriptionConfirmation messages and perform a GET request to the SubscribeURL in the payload to confirm the subscription.

Which region should I use for SES inbound?

SES inbound is available only in us-east-1, us-west-2, and eu-west-1; pick one of these when creating topics and receipt rules.

What indicates completion?

The setup is complete when the SES rule set is active and aws sns list-subscriptions-by-topic shows a confirmed SubscriptionArn (not PendingConfirmation).