From bb50c1abc8c507e2b877a952377adc607b936eab Mon Sep 17 00:00:00 2001 From: Tietew Date: Thu, 5 Dec 2024 04:19:00 +0900 Subject: [PATCH] feat(ses): add support to disable account-level suppression list (#32168) ### Issue # (if applicable) Closes #32149. ### Reason for this change ConfigurationSet allows us to disable account-level suppression list but CDK missed the configuration. ### Description of changes Introduced `disableSuppressionList` property to disable account-level suppression list. ### Description of how you validated changes Added unit tests and integ test. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --------- Co-authored-by: Matsuda Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- ...efaultTestDeployAssert41D23FD8.assets.json | 19 ++ ...aultTestDeployAssert41D23FD8.template.json | 36 +++ ...rriding-suppression-list-integ.assets.json | 19 ++ ...iding-suppression-list-integ.template.json | 77 +++++++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 133 +++++++++++ .../tree.json | 212 ++++++++++++++++++ ...-set-override-suppression-list-settings.ts | 32 +++ packages/aws-cdk-lib/aws-ses/README.md | 39 +++- .../aws-ses/lib/configuration-set.ts | 16 +- .../aws-ses/test/configuration-set.test.ts | 82 +++++++ 12 files changed, 673 insertions(+), 5 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets.json new file mode 100644 index 0000000000000..a67ccd78c551e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.assets.json new file mode 100644 index 0000000000000..f48596ca61c95 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.assets.json @@ -0,0 +1,19 @@ +{ + "version": "38.0.1", + "files": { + "a8ec6cbdebdfee0a751851a84216f1643a9c332798775433963d315cf02401a1": { + "source": { + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a8ec6cbdebdfee0a751851a84216f1643a9c332798775433963d315cf02401a1.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.template.json new file mode 100644 index 0000000000000..d1d382741d259 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk-ses-configuration-set-overriding-suppression-list-integ.template.json @@ -0,0 +1,77 @@ +{ + "Resources": { + "DisableSuppressionList6B7ABFBF": { + "Type": "AWS::SES::ConfigurationSet", + "Properties": { + "SuppressionOptions": { + "SuppressedReasons": [] + } + } + }, + "OverrideSuppressionReasonsToBouncesOnly1280FADA": { + "Type": "AWS::SES::ConfigurationSet", + "Properties": { + "SuppressionOptions": { + "SuppressedReasons": [ + "BOUNCE" + ] + } + } + }, + "OverrideSuppressionReasonsToComplaintsOnly8F770ED6": { + "Type": "AWS::SES::ConfigurationSet", + "Properties": { + "SuppressionOptions": { + "SuppressedReasons": [ + "COMPLAINT" + ] + } + } + }, + "OverrideSuppressionReasonsToBouncesAndComplaints27254E32": { + "Type": "AWS::SES::ConfigurationSet", + "Properties": { + "SuppressionOptions": { + "SuppressedReasons": [ + "BOUNCE", + "COMPLAINT" + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk.out new file mode 100644 index 0000000000000..c6e612584e352 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"38.0.1"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/integ.json new file mode 100644 index 0000000000000..5918997d1e5c5 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "38.0.1", + "testCases": { + "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest": { + "stacks": [ + "cdk-ses-configuration-set-overriding-suppression-list-integ" + ], + "assertionStack": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert", + "assertionStackName": "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/manifest.json new file mode 100644 index 0000000000000..d59141c36fd84 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/manifest.json @@ -0,0 +1,133 @@ +{ + "version": "38.0.1", + "artifacts": { + "cdk-ses-configuration-set-overriding-suppression-list-integ.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdk-ses-configuration-set-overriding-suppression-list-integ.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdk-ses-configuration-set-overriding-suppression-list-integ": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdk-ses-configuration-set-overriding-suppression-list-integ.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a8ec6cbdebdfee0a751851a84216f1643a9c332798775433963d315cf02401a1.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdk-ses-configuration-set-overriding-suppression-list-integ.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "cdk-ses-configuration-set-overriding-suppression-list-integ.assets" + ], + "metadata": { + "/cdk-ses-configuration-set-overriding-suppression-list-integ/DisableSuppressionList/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DisableSuppressionList6B7ABFBF" + } + ], + "/cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesOnly/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OverrideSuppressionReasonsToBouncesOnly1280FADA" + } + ], + "/cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToComplaintsOnly/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OverrideSuppressionReasonsToComplaintsOnly8F770ED6" + } + ], + "/cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesAndComplaints/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "OverrideSuppressionReasonsToBouncesAndComplaints27254E32" + } + ], + "/cdk-ses-configuration-set-overriding-suppression-list-integ/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-ses-configuration-set-overriding-suppression-list-integ/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-ses-configuration-set-overriding-suppression-list-integ" + }, + "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "notificationArns": [], + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "ConfigurationSetOverridingSuppressionListSettingsIntegDefaultTestDeployAssert41D23FD8.assets" + ], + "metadata": { + "/ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/tree.json new file mode 100644 index 0000000000000..945f4022ae636 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.js.snapshot/tree.json @@ -0,0 +1,212 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "cdk-ses-configuration-set-overriding-suppression-list-integ": { + "id": "cdk-ses-configuration-set-overriding-suppression-list-integ", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ", + "children": { + "DisableSuppressionList": { + "id": "DisableSuppressionList", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/DisableSuppressionList", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/DisableSuppressionList/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SES::ConfigurationSet", + "aws:cdk:cloudformation:props": { + "suppressionOptions": { + "suppressedReasons": [] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.CfnConfigurationSet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.ConfigurationSet", + "version": "0.0.0" + } + }, + "OverrideSuppressionReasonsToBouncesOnly": { + "id": "OverrideSuppressionReasonsToBouncesOnly", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesOnly", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesOnly/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SES::ConfigurationSet", + "aws:cdk:cloudformation:props": { + "suppressionOptions": { + "suppressedReasons": [ + "BOUNCE" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.CfnConfigurationSet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.ConfigurationSet", + "version": "0.0.0" + } + }, + "OverrideSuppressionReasonsToComplaintsOnly": { + "id": "OverrideSuppressionReasonsToComplaintsOnly", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToComplaintsOnly", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToComplaintsOnly/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SES::ConfigurationSet", + "aws:cdk:cloudformation:props": { + "suppressionOptions": { + "suppressedReasons": [ + "COMPLAINT" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.CfnConfigurationSet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.ConfigurationSet", + "version": "0.0.0" + } + }, + "OverrideSuppressionReasonsToBouncesAndComplaints": { + "id": "OverrideSuppressionReasonsToBouncesAndComplaints", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesAndComplaints", + "children": { + "Resource": { + "id": "Resource", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/OverrideSuppressionReasonsToBouncesAndComplaints/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SES::ConfigurationSet", + "aws:cdk:cloudformation:props": { + "suppressionOptions": { + "suppressedReasons": [ + "BOUNCE", + "COMPLAINT" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.CfnConfigurationSet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ses.ConfigurationSet", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-ses-configuration-set-overriding-suppression-list-integ/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "ConfigurationSetOverridingSuppressionListSettingsInteg": { + "id": "ConfigurationSetOverridingSuppressionListSettingsInteg", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "ConfigurationSetOverridingSuppressionListSettingsInteg/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.4.2" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.ts new file mode 100644 index 0000000000000..56e74e044ead0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ses/test/integ.configuration-set-override-suppression-list-settings.ts @@ -0,0 +1,32 @@ +import { App, Stack, StackProps } from 'aws-cdk-lib'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { Construct } from 'constructs'; +import * as ses from 'aws-cdk-lib/aws-ses'; + +class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + new ses.ConfigurationSet(this, 'DisableSuppressionList', { + disableSuppressionList: true, + }); + + new ses.ConfigurationSet(this, 'OverrideSuppressionReasonsToBouncesOnly', { + suppressionReasons: ses.SuppressionReasons.BOUNCES_ONLY, + }); + + new ses.ConfigurationSet(this, 'OverrideSuppressionReasonsToComplaintsOnly', { + suppressionReasons: ses.SuppressionReasons.COMPLAINTS_ONLY, + }); + + new ses.ConfigurationSet(this, 'OverrideSuppressionReasonsToBouncesAndComplaints', { + suppressionReasons: ses.SuppressionReasons.BOUNCES_AND_COMPLAINTS, + }); + } +} + +const app = new App(); + +new integ.IntegTest(app, 'ConfigurationSetOverridingSuppressionListSettingsInteg', { + testCases: [new TestStack(app, 'cdk-ses-configuration-set-overriding-suppression-list-integ')], +}); diff --git a/packages/aws-cdk-lib/aws-ses/README.md b/packages/aws-cdk-lib/aws-ses/README.md index 15b3fd6d79ebc..b89a098c964c2 100644 --- a/packages/aws-cdk-lib/aws-ses/README.md +++ b/packages/aws-cdk-lib/aws-ses/README.md @@ -140,7 +140,6 @@ declare const myPool: ses.IDedicatedIpPool; new ses.ConfigurationSet(this, 'ConfigurationSet', { customTrackingRedirectDomain: 'track.cdk.dev', - suppressionReasons: ses.SuppressionReasons.COMPLAINTS_ONLY, tlsPolicy: ses.ConfigurationSetTlsPolicy.REQUIRE, dedicatedIpPool: myPool, // Specify maximum delivery time @@ -161,6 +160,42 @@ myConfigurationSet.addEventDestination('ToSns', { }) ``` +### Override account-level suppression list settings + +You can customize account-level suppression list separately for different configuration sets by overriding it +with configuration set-level suppression. + +For details, see [Using configuration set-level suppression to override your account-level suppression list](https://docs.aws.amazon.com/ses/latest/dg/sending-email-suppression-list-config-level.html). + +By default, the configuration set uses your account-level suppression list settings. + +You can disable account-level suppression list by specifying `disableSuppressionList` to true. Email sent with this configuration set will not use any suppression settings at all. + +``` ts +new ses.ConfigurationSet(this, 'ConfigurationSet', { + disableSuppressionList: true, +}); +``` + +You can also override account level settings with configuration set-level suppression enabled. Email sent with this configuration set will only use the suppression conditions you enabled for it (bounces, complaints, or bounces and complaints) - regardless of what your account-level suppression list settings are, it will override them. + +``` ts +// Only bounces will be suppressed. +new ses.ConfigurationSet(this, 'ConfigurationSet', { + suppressionReasons: ses.SuppressionReasons.BOUNCES_ONLY, +}); + +// Only complaints will be suppressed. +new ses.ConfigurationSet(this, 'ConfigurationSet', { + suppressionReasons: ses.SuppressionReasons.COMPLAINTS_ONLY, +}); + +// Both bounces and complaints will be suppressed. +new ses.ConfigurationSet(this, 'ConfigurationSet', { + suppressionReasons: ses.SuppressionReasons.BOUNCES_AND_COMPLAINTS, +}); +``` + ### Email identity In Amazon SES, a verified identity is a domain or email address that you use to send or receive email. Before you @@ -259,4 +294,4 @@ new ses.ConfigurationSet(this, 'ConfigurationSetWithVdmOptions', { optimizedSharedDelivery: true, }, }); -``` \ No newline at end of file +``` diff --git a/packages/aws-cdk-lib/aws-ses/lib/configuration-set.ts b/packages/aws-cdk-lib/aws-ses/lib/configuration-set.ts index 4427f1c490eee..cb45d79b3d887 100644 --- a/packages/aws-cdk-lib/aws-ses/lib/configuration-set.ts +++ b/packages/aws-cdk-lib/aws-ses/lib/configuration-set.ts @@ -66,6 +66,14 @@ export interface ConfigurationSetProps { */ readonly suppressionReasons?: SuppressionReasons; + /** + * If true, account-level suppression list is disabled; email sent with this configuration set + * will not use any suppression settings at all + * + * @default false + */ + readonly disableSuppressionList?: boolean; + /** * The custom subdomain that is used to redirect email recipients to the * Amazon SES event tracking domain @@ -167,6 +175,9 @@ export class ConfigurationSet extends Resource implements IConfigurationSet { physicalName: props.configurationSetName, }); + if (props.disableSuppressionList && props.suppressionReasons) { + throw new Error('When disableSuppressionList is true, suppressionReasons must not be specified.'); + } if (props.maxDeliveryDuration && !Token.isUnresolved(props.maxDeliveryDuration)) { if (props.maxDeliveryDuration.toMilliseconds() < Duration.minutes(5).toMilliseconds()) { throw new Error(`The maximum delivery duration must be greater than or equal to 5 minutes (300_000 milliseconds), got: ${props.maxDeliveryDuration.toMilliseconds()} milliseconds.`); @@ -190,7 +201,7 @@ export class ConfigurationSet extends Resource implements IConfigurationSet { sendingEnabled: props.sendingEnabled, }), suppressionOptions: undefinedIfNoKeys({ - suppressedReasons: renderSuppressedReasons(props.suppressionReasons), + suppressedReasons: props.disableSuppressionList ? [] : renderSuppressedReasons(props.suppressionReasons), }), trackingOptions: undefinedIfNoKeys({ customRedirectDomain: props.customTrackingRedirectDomain, @@ -202,8 +213,7 @@ export class ConfigurationSet extends Resource implements IConfigurationSet { guardianOptions: props.vdmOptions?.optimizedSharedDelivery !== undefined ? { optimizedSharedDelivery: booleanToEnabledDisabled(props.vdmOptions?.optimizedSharedDelivery), } : undefined, - }, - ), + }), }); this.configurationSetName = configurationSet.ref; diff --git a/packages/aws-cdk-lib/aws-ses/test/configuration-set.test.ts b/packages/aws-cdk-lib/aws-ses/test/configuration-set.test.ts index 4ad57366b7182..1221fa303b566 100644 --- a/packages/aws-cdk-lib/aws-ses/test/configuration-set.test.ts +++ b/packages/aws-cdk-lib/aws-ses/test/configuration-set.test.ts @@ -92,6 +92,88 @@ test('configuration set with vdmOptions not configured', () => { }); }); +describe('configuration set with account-level suppression list overrides', () => { + test('disable account-level suppression list', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + disableSuppressionList: true, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: { + SuppressedReasons: [], + }, + }); + }); + + test('throws error with both disableSuppressionList and suppressionReasons are specified', () => { + expect(() => { + new ConfigurationSet(stack, 'ConfigurationSet', { + disableSuppressionList: true, + suppressionReasons: SuppressionReasons.BOUNCES_AND_COMPLAINTS, + }); + }).toThrow('When disableSuppressionList is true, suppressionReasons must not be specified.'); + }); + + test('allows when disableSuppressionList is false and suppressionReasons are specified', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + disableSuppressionList: false, + suppressionReasons: SuppressionReasons.BOUNCES_AND_COMPLAINTS, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: { + SuppressedReasons: ['BOUNCE', 'COMPLAINT'], + }, + }); + }); + + test('enable account-level suppression list explicitly', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + disableSuppressionList: false, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: Match.absent(), + }); + }); + + test('override suppressionReasons to BOUNCES only', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + suppressionReasons: SuppressionReasons.BOUNCES_ONLY, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: { + SuppressedReasons: ['BOUNCE'], + }, + }); + }); + + test('override suppressionReasons to COMPLAINTS only', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + suppressionReasons: SuppressionReasons.COMPLAINTS_ONLY, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: { + SuppressedReasons: ['COMPLAINT'], + }, + }); + }); + + test('override suppressionReasons to BOUNCES and COMPLAINTS', () => { + new ConfigurationSet(stack, 'ConfigurationSet', { + suppressionReasons: SuppressionReasons.BOUNCES_AND_COMPLAINTS, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::SES::ConfigurationSet', { + SuppressionOptions: { + SuppressedReasons: ['BOUNCE', 'COMPLAINT'], + }, + }); + }); +}); + describe('maxDeliveryDuration', () => { test.each([Duration.millis(999), Duration.minutes(4)])('invalid duration less than 5 minutes %s', (maxDeliveryDuration) => { expect(() => {