Agent → Email Service Architecture

High-throughput, async, durable email pipeline. Agent (ECS) enqueues; Email (Lambda) sends via SES; DynamoDB is source of truth; SQS/SNS decouple producers from consumers.

Components

Component Role
Agent (ECS Fargate, NestJS) API surface. Accepts single/batch send requests, writes job rows to DynamoDB, publishes to SQS.
Email Lambda (plain Node/TS) SQS-triggered worker. Renders + sends via SES, updates DynamoDB. No DI framework — handler is a plain function for fast cold starts.
Event Lambda (plain Node/TS) SNS-triggered. Updates job status, maintains suppression.
SQS Standard (email-jobs) Main work queue. High throughput, at-least-once.
SQS DLQ (email-jobs-dlq) Catches messages exceeding maxReceiveCount.
SQS DLQ (event-lambda-dlq) Catches SNS deliveries Event Lambda failed to process after retries.
SNS (ses-events) Fan-out for SES bounce/complaint/delivery notifications.
DynamoDB EmailJobs Job state, idempotency, audit trail.
DynamoDB Suppression Bounce/complaint suppression list (checked before send).
SES Actual mail transport.

High-Level Flow

flowchart LR
    Client[Client / Upstream] -->|POST /emails| Agent[Agent ECS Fargate]
    Agent -->|PutItem job=PENDING| DDB[(DynamoDB EmailJobs)]
    Agent -->|SendMessage| SQS[[SQS email-jobs]]
    SQS -->|trigger batch| Lambda[Email Lambda]
    Lambda -->|GetItem| DDB
    Lambda -->|check| Supp[(DynamoDB Suppression)]
    Lambda -->|SendEmail / SendBulkEmail| SES[SES]
    Lambda -->|UpdateItem SENT/FAILED| DDB
    SES -->|bounce/complaint/delivery| SNS[[SNS ses-events]]
    SNS --> EvtLambda[Event Lambda]
    EvtLambda -->|UpdateItem| DDB
    EvtLambda -->|PutItem| Supp
    SQS -. failures .-> DLQ[[SQS DLQ]]
    SNS -. failures .-> EDLQ[[Event DLQ]]
    DLQ --> Alarm{{CloudWatch Alarm}}
    EDLQ --> Alarm