cognito-ses-domain
v0.0.0
Published
CDK construct that:
Readme
cognito-ses-domain
CDK construct that:
- Verifies an SES domain identity (Route53 hosted zone lookup & DNS records)
- (Optionally) Creates a Cognito Identity Pool + IAM Role permitting SES send actions
- (Optionally) Enables SES sending event logging to CloudWatch via the companion
ses-cloudwatchconstruct (Configuration Set + EventBridge rule + LogGroup)
The defaults are intentionally minimal: only the SES domain identity is created unless you opt-in to other capabilities.
ℹ️ This repository is managed by projen. Do not edit generated files (like
package.json, GitHub workflows, eslint configs) directly—make changes in.projenrc.tsand runnpx projento re-synthesize.
Features
| Capability | Enabled By | Notes |
|------------|------------|-------|
| SES Domain Identity | always | Creates AWS::SES::EmailIdentity for the domain. |
| Cognito Identity Pool + Role/Policy | createIdentityPool: true | Grants authenticated users SES Send* permissions for the verified domain. Default is false. |
| SES Sending Event Logging | sendingLogs props provided | Wraps ses-cloudwatch to capture SES sending events to CloudWatch Logs. |
Install
Add as a dependency to your construct library or CDK app (peer deps aws-cdk-lib and constructs required):
npm install cognito-ses-domain
# or
yarn add cognito-ses-domainQuick Start
import { Stack } from 'aws-cdk-lib';
import * as cognito from 'aws-cdk-lib/aws-cognito';
import { SesDomainIdentity } from 'cognito-ses-domain';
import { aws_ses as ses } from 'aws-cdk-lib';
class MyStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id, { env: { account: '123456789012', region: 'us-east-1' } });
const userPool = new cognito.UserPool(this, 'UserPool');
const client = userPool.addClient('Client');
new SesDomainIdentity(this, 'SesDomainIdentity', {
domain: 'example.com', // must exist in Route53 in this account/region
userPool,
userPoolClientId: client.userPoolClientId,
// Optional: provision Identity Pool & role (defaults to false)
createIdentityPool: true,
// Optional: enable logging of SES sending events
sendingLogs: {
configurationSetName: 'my-ses-config',
events: [ses.EmailSendingEvent.SEND, ses.EmailSendingEvent.DELIVERY],
},
});
}
}Props
| Name | Type | Default | Description |
|------|------|---------|-------------|
| domain | string | (required) | Domain to verify (must have a public hosted zone in Route53). |
| userPool | cognito.IUserPool | (required) | User Pool associated with email sending context. |
| userPoolClientId | string | (required) | User Pool client ID (used when creating Identity Pool). |
| createIdentityPool | boolean | false | Whether to create Identity Pool + role/policy for SES sending. |
| sendingLogs | SesCloudWatchProps? | undefined | Provide to enable SES sending event logging (Configuration Set + EventBridge rule + LogGroup). |
sendingLogs is passed directly to the ses-cloudwatch construct. See its README for full option docs (logGroupName, configurationSetName, eventRuleName, events).
Outputs
| Output | Description |
|--------|-------------|
| SesIdentityArnOutput | ARN of the created SES identity. |
| IdentityPoolIdOutput | Identity Pool ID (only if createIdentityPool: true). |
| SesConfigurationSetName | Configuration set name (only if sendingLogs.configurationSetName provided). |
Identity Pool Permissions
When createIdentityPool is true:
- A
Cognito::IdentityPoolis created referencing the supplied User Pool & client. - An IAM Role is created with a policy granting:
ses:SendEmail,ses:SendRawEmail,ses:SendTemplatedEmailon the verified domain identity.
Adjust or extend permissions by adding statements to the returned role (future enhancement: expose role as a property; contributions welcome).
Logging SES Sending Events
Provide sendingLogs to create a configuration set and route selected SES sending events (default from ses-cloudwatch) through EventBridge into a CloudWatch LogGroup. Useful for deliverability monitoring and troubleshooting.
Example enabling only default SEND event:
sendingLogs: {}Example customizing events & log group name:
sendingLogs: {
logGroupName: 'ses-sending-events',
events: [ses.EmailSendingEvent.SEND, ses.EmailSendingEvent.DELIVERY, ses.EmailSendingEvent.REJECT],
}Example Apps
TypeScript example: examples/typescript/
Python example: examples/python/ (install the generated Python dist after running npx projen package).
The TypeScript example demonstrates:
- Creating a User Pool & client
- Using the construct with sending logs enabled and Identity Pool disabled by default
Examples are intentionally outside projen management (ignored via .projenrc.ts) so you can add multiple examples without affecting the library build.
Run the example (ensure you have a matching hosted zone and bootstrapped environment):
cd examples/typescript
npm install
export CDK_DEFAULT_ACCOUNT=123456789012
export CDK_DEFAULT_REGION=us-east-1
npm run synth
npm run deployTo customize account/region you can also pass context: npx cdk synth -c account=123456789012 -c region=us-east-1.
Contributing
This project is generated & maintained with projen.
Projen Overview
/.projenrc.ts defines the construct library configuration (jsii, publishing, dependencies). Running npx projen regenerates:
package.json(scripts, deps, peer deps).projen/*task & dependency metadata- Lint/test configuration
- GitHub Actions (if enabled later)
Never hand-edit those generated files—your changes will be overwritten. Instead:
- Edit
.projenrc.ts - Run
npx projen - Commit both your
.projenrc.tschange and the synthesized outputs
To inspect available options for the construct project type, see the AwsCdkConstructLibrary API docs or run npx projen new awscdk-construct --help in a scratch directory.
Contribution Workflow (Using Projen)
- Fork & clone the repo.
- Install dependencies:
npm install(always do this before running any task). - Make changes:
- For library logic – edit files under
src/. - For generated config (lint rules, release settings, tasks) – edit
.projenrc.ts(never hand-edit the generated artifacts).
- For library logic – edit files under
- Re-synthesize after modifying
.projenrc.ts:npx projen - Fast feedback while coding:
npx projen compile # just jsii compile (fast, no tests) npx projen test # jest + eslint - Before pushing / opening a PR run the full pipeline:
npx projen build # synth -> compile -> test -> docgen -> package - Commit BOTH your source changes and any regenerated files (e.g.
package.json,API.md,.projen/*). - Open a pull request with a concise description and rationale.
Tip: Use npx projen watch during development to continuously recompile on change.
Common pitfalls:
- Forgetting to run
npx projenafter editing.projenrc.ts(CI will show drift). - Editing generated files directly – they will be overwritten.
- Introducing constructs or aws-cdk-lib version drift in examples – rely on root versions when possible.
Build & Test
git clone https://github.com/pablocano/cognito-ses-domain.git
cd cognito-ses-domain
npm install # installs dev deps
npm run build # full projen build pipeline
# Or granular:
npm run compile # jsii compile
npm test # jest + eslintCommon Tasks
| Task | Command | Description |
|------|---------|-------------|
| Synthesize project files | npx projen | Regenerates config files. |
| Compile | npm run compile | jsii compile to lib/. |
| Test | npm test | Jest + ESLint. |
| Package | npm run package | Builds distributable. |
| Upgrade deps | npm run upgrade | Applies dependency upgrades. |
Adding Features
- Modify source in
src/. - Add/adjust tests in
test/(100% coverage enforced in current setup). - Run
npm test. - Open PR with a concise description and motivation.
Releasing
Releases are automated through projen tasks (semantic versioning). A maintainer will run the release workflow; external contributors only need to focus on code + tests.
Design Notes
createIdentityPooldefaults tofalseto avoid provisioning auth infrastructure unless explicitly required.- Logging is opt-in via
sendingLogsto keep minimal footprint by default. - Hosted zone lookup uses
HostedZone.fromLookupwhich requires the domain hosted zone to exist in the target account/region; for unit tests this is mocked.
Development Workflow with Examples
The example app consumes the library via a relative file dependency (file:../..). After changing the library:
npm run compile # at repo root
cd examples/typescript
npm run synthIf you add more examples, place them under examples/<name> and ensure they are not published (already excluded by .npmignore).
License
Apache-2.0 © Merapar Technologies Group B.V.
Questions or ideas? Open an issue or PR — contributions are welcome.
