`aws_cognito.UserPool` doesn't wait for a new `aws_ses.EmailIdentity` to be ready
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### Describe the feature
I might be doing something wrong, but I'm using [aws_cognito.UserPoolEmail.withSes()](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cognito.UserPoolEmail.html#static-withwbrsesoptions), and no matter what I tried, I couldn't get CloudFormation to wait until a new `aws_ses.EmailIdentity` was ready before trying to find it to use it in a Cognito `UserPool`.
### Use Case
I'd like to use a single CDK stack to create both an `aws_ses.EmailIdentity` and a `aws_cognito.UserPool` that references the Simple Email Service's `EmailIdentity`. I'd also like to create an `aws_ses.ReceiptRuleSet` in the same stack as the `aws_ses_EmailIdentity` without having to add a lot of `addDependency()` calls.
### Proposed Solution
If it's possible, `aws_cognito.UserPoolEmail.withSes` should allow an `aws_ses.EmailIdentity` to be passed in to make sure any dependencies are properly configured. The same would also be nice for an `ses.ReceiptRuleSet`.
### Other Information
The below is what I tried, but no matter what `add_dependency()` calls I added, I couldn't get it to work with a single stack and had to split it up into two separate stacks. I kept getting errors like this:
```
CDK-Bug-Test-Cognito | 8/11 | 6:55:26 AM | CREATE_FAILED | AWS::Cognito::UserPool | CognitoUserPool (CognitoUserPool53E37E69) Resource handler returned message: "Cognito received the following error from Amazon SES when attempting to send email: Email address is not verified. The following identities failed the check in region US-EAST-2: arn:aws:ses:us-east-2:245161217798:identity/paulie.livedata.com (Service: CognitoIdentityProvider, Status Code: 400, Request ID: c9d4ffe5-7d80-4a30-ad50-fc3ee712a3bc)" (RequestToken: 6af80751-1d91-b041-aaf3-8d086fb31439, HandlerErrorCode: InvalidRequest)
```
Here's the Python code:
```python
import aws_cdk as cdk
from aws_cdk import App, Environment, Stack
from aws_cdk import aws_cognito as cognito
from aws_cdk import aws_route53 as route_53
from aws_cdk import aws_ses as ses
from aws_cdk import aws_ses_actions as ses_actions
from constructs import Construct
class SesStack(Stack):
def __init__(self, scope: Construct, construct_id: str, route53_hosted_zone: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ses.EmailIdentity(
self, 'EmailIdentity',
identity=ses.Identity.public_hosted_zone(
route_53.HostedZone.from_hosted_zone_attributes(
self, 'HostedZone',
hosted_zone_id=self.node.try_get_context('route53_hosted_zone_id'),
zone_name=route53_hosted_zone,
)
),
mail_from_domain=f'mail.{route53_hosted_zone}'
)
class CognitoStack(Stack):
def __init__(self, scope: Construct, construct_id: str, route53_hosted_zone: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
identity = ses.EmailIdentity(
self, 'EmailIdentity',
identity=ses.Identity.public_hosted_zone(
route_53.HostedZone.from_lookup(self, 'HostedZone', domain_name=route53_hosted_zone)
),
mail_from_domain=f'mail.{route53_hosted_zone}'
)
from_email = f'noreply@{route53_hosted_zone}'
email_rule_set = ses.ReceiptRuleSet(self, 'EmailRuleSet')
email_rule_set.add_rule('EmailReceiptNoReply', recipients=[from_email],
actions=[ses_actions.Bounce(
sender=from_email, template=ses_actions.BounceTemplate.MAILBOX_DOES_NOT_EXIST)])
# ### This did seem to work for the ReceiptRuleSet:
# make sure all the SES identity parts are done before the ReceiptRuleSet tries referencing the identity
for child in identity.node.children:
if child.node.default_child: # this is a higher-level construct, so depend on its children
for grandchild in child.node.children:
email_rule_set.node.add_dependency(grandchild)
else:
email_rule_set.node.add_dependency(child)
user_pool = cognito.UserPool(
self, 'CognitoUserPool',
user_pool_name='test-cdk-bug',
removal_policy=cdk.RemovalPolicy.DESTROY,
email=cognito.UserPoolEmail.with_ses(
from_email=from_email,
from_name='Administrator',
reply_to='support@example.com',
ses_verified_domain=route53_hosted_zone,
)
)
# ### But this was not sufficient for the UserPool:
# make sure all the SES identity parts are done before the UserPool tries referencing the identity
for child in identity.node.children:
if child.node.default_child: # this is a higher-level construct, so depend on its children
for grandchild in child.node.children:
user_pool.node.add_dependency(grandchild)
else:
user_pool.node.add_dependency(child)
app = App()
route53_hosted_zone: str = app.node.try_get_context('route53_hosted_zone')
# ses_stack = SesStack(
# app, 'CDK-Bug-Test-SES', route53_hosted_zone,
# env=Environment(account=app.node.try_get_context('account'), region=app.node.try_get_context('region')),
# )
stack = CognitoStack(
app, 'CDK-Bug-Test-Cognito', route53_hosted_zone,
env=Environment(account=app.node.try_get_context('account'), region=app.node.try_get_context('region')),
)
# stack.add_dependency(ses_stack)
app.synth()
```
### Acknowledgements
- [ ] I may be able to implement this feature request
- [ ] This feature might incur a breaking change
### CDK version used
2.117.0
### Environment details (OS name and version, etc.)
Windows 11
Contributor guide
Research direction
Start at aws_cognito.UserPoolEmail.withSes and inspect how it handles aws_ses.EmailIdentity dependencies, then compare the dependency behavior described for ses.ReceiptRuleSet. Done means a passed EmailIdentity can configure the Cognito UserPool and ensure CloudFormation waits for the identity without manual add_dependency calls; verify with the supplied single-stack Python example.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python, typescript
- Domain
- cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100