Outbound Mail Agent
HomebrewedAfter inbound, Processing Q and Thank-you Q run in parallel — process accepted mail (today SES forward) and send the category-framed reply — each with its own retries and DLQ.
Amazon SQS · Lambda · SES · S3 · DynamoDB · OpenAI gpt-4o-mini / Typesafe Jev · CloudWatch · Terraform
Overview
Layer 4 Act on the Mental Model. Outbound Mail runs after inbound accepts clean contact mail: parallel Processing Q and Thank-you Q workers (no SES send on inbound).
Behavior
- Parallelization (Anthropic). Inbound enqueues Processing Q and Thank-you Q together; the two paths run independently. See Building effective agents.
- Independent outcomes. Process (today: forward) and thank-you do not wait on each other. Each records its own DynamoDB fields (
forward_ses_id,thank_you_ses_id/thank_you_status). - Per-queue idempotency. Retries skip work already done on that queue so hotmail is not double-forwarded and the sender is not double-thanked.
- Hard send failures retry. SES or unexpected errors raise so that queue redelivers (up to 3 receives), then that queue’s DLQ. Soft thank-you compose failures still attempt a template send.
- Shared raw MIME. Both workers reload
ses-raw/<messageId>from S3; they do not depend on the inbound Lambda staying warm.
Send flow
Inbound fans out to both queues (Parallelization); either path can finish first. Diagram key: ✦ AI agent · second line = Anthropic workflow · purple = actor · white = service.
---
config:
theme: default
themeVariables:
background: "#ffffff"
fontSize: "14px"
---
flowchart TB
inbound["✦ Inbound Mail agent
Routing"]
procQ[Processing Q]
thanksQ[Thank-you Q]
procAgent["Processing worker
SES forward"]
thanksAgent["✦ Thank-you Mail
Parallelization"]
actionNode["SES forward
FORWARD_TO"]
composeNode["✦ Compose thank-you
Parallelization"]
thanksNode["SES thank-you
to sender"]
procDone[Process recorded]
thanksDone[Thank-you recorded]
procDlq["Processing DLQ
after 3 receives"]
thanksDlq["Thank-you DLQ
after 3 receives"]
alarm[CloudWatch alarm]
inbound --> procQ
inbound --> thanksQ
procQ --> procAgent --> actionNode --> procDone
thanksQ --> thanksAgent --> composeNode --> thanksNode --> thanksDone
procAgent -->|hard failure| procQ
procQ -->|max receives| procDlq --> alarm
thanksAgent -->|hard SES failure| thanksQ
thanksQ -->|max receives| thanksDlq --> alarm
classDef agent fill:#e8f0ee,stroke:#0f3d36,stroke-width:2px,color:#0d0d0d
classDef service fill:#fafaf8,stroke:#c8c8c2,stroke-width:1px,color:#0d0d0d
classDef actor fill:#f3eef8,stroke:#6b4f9a,stroke-width:2px,color:#0d0d0d
class inbound,thanksAgent,composeNode agent
class procQ,thanksQ,procAgent,actionNode,thanksNode,procDone,thanksDone,procDlq,thanksDlq,alarm service
After the Inbound Mail agent accepts a message, it enqueues Processing Q and Thank-you Q together. Processing takes the appropriate action for the job (currently SES forward to FORWARD_TO); Thank-you drafts and sends the reply to the original sender. The two do not wait on each other. DynamoDB records each step so queue retries do not double-send.
This agent is part of the OPG Labs project (Project tab).