mailshot

Security

Data protection, encryption, IAM least-privilege permissions, and compliance guidance.

Data at rest

All subscriber data (emails, names, custom attributes) is stored in clear text in DynamoDB. This is appropriate for most use cases because DynamoDB encrypts all data at rest by default using AWS-owned keys.

Encryption options

OptionHowWhen to use
AWS-owned key (default)Automatic. No configuration needed.Most deployments. No compliance requirement for key control.
AWS-managed key (KMS)Set encryption: dynamodb.TableEncryption.AWS_MANAGED in the storage construct.When you need CloudTrail audit logs for key usage.
Customer-managed key (CMK)Create a KMS key and pass it to the table.When you need key rotation control, cross-account access policies, or per-tenant isolation.
Application-level encryptionEncrypt fields before writing using the AWS Database Encryption SDK.PCI-DSS, HIPAA, or when clear text PII is not acceptable even at the storage layer.

S3 templates

The template bucket uses SSE-S3 (AWS-managed server-side encryption) with all public access blocked. Templates contain HTML with Liquid placeholders — no subscriber PII.

Data in transit

All AWS SDK calls use HTTPS by default. No additional configuration needed.

IAM permissions

Every Lambda function follows least-privilege — each gets only the actions and resources it needs. No function has dynamodb:* or s3:*.

SendEmailFn

ActionResource
dynamodb:GetItem, PutItem, UpdateItem, QueryMain table
s3:GetObjectTemplate bucket
ses:SendEmailSES identity ARNs and configuration set
states:StopExecutionAll execution ARNs (required — execution ARNs contain random IDs)
states:DescribeStateMachine, ListExecutionsSequence state machine ARNs
states:DescribeExecution, GetExecutionHistoryExecution ARNs under sequence state machines

CheckConditionFn

ActionResource
dynamodb:GetItem, QueryMain table (read-only)

UnsubscribeFn

ActionResource
dynamodb:GetItem, PutItem, UpdateItemMain table
ses:PutSuppressedDestination* (SES API does not support resource-level permissions)
states:StopExecutionAll execution ARNs

BounceHandlerFn

ActionResource
dynamodb:GetItem, PutItem, UpdateItem, QueryMain table
ses:PutSuppressedDestination* (SES API does not support resource-level permissions)
states:StopExecutionAll execution ARNs

EngagementHandlerFn

ActionResource
dynamodb:PutItemEvents table only (write-only)

Backup and recovery

FeatureStatus
Point-in-time recoveryEnabled on both tables
Removal policyRETAIN — tables persist if the CloudFormation stack is deleted
Send log TTL90 days (automatic cleanup)
Engagement event TTL365 days (automatic cleanup)

PITR backups inherit the table's encryption settings.

Network security

Lambda functions run in the default Lambda execution environment (no VPC). If your compliance requirements demand that DynamoDB traffic stays within the AWS network:

  1. Place Lambdas in a VPC
  2. Add a DynamoDB gateway VPC endpoint
  3. Add an S3 gateway endpoint

This is not required for most deployments — all SDK traffic already uses HTTPS.

GDPR and data deletion

Mailshot stores subscriber PII (email, first name, custom attributes) in DynamoDB. To support data subject access requests:

  • Delete a subscriber — Use the delete_subscriber MCP tool or call the DynamoDB delete operations directly. This removes the profile, all execution records, and send logs.
  • Engagement events — The Events table has a 365-day TTL. For immediate deletion, query by PK = SUB#{email} and delete all matching items.
  • SES suppression list — Use the remove_suppression MCP tool to remove an email from the account-level suppression list.

What not to store

Subscriber attributes are flexible — any key-value pair can be stored as a top-level DynamoDB column. However, do not store:

  • Payment data (card numbers, bank accounts) — use a PCI-compliant vault
  • Passwords or secrets — these belong in Cognito, Auth0, or similar
  • Health information — requires HIPAA-compliant storage with BAA

Subscriber attributes are meant for personalization and segmentation: platform, country, plan, signup date, etc.