-
Notifications
You must be signed in to change notification settings - Fork 4k
/
Copy pathconfiguration-set-event-destination.ts
282 lines (250 loc) · 8.88 KB
/
configuration-set-event-destination.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
import { Construct } from 'constructs';
import { IConfigurationSet } from './configuration-set';
import { CfnConfigurationSetEventDestination } from './ses.generated';
import * as iam from '../../aws-iam';
import * as sns from '../../aws-sns';
import { Aws, IResource, Resource } from '../../core';
import { addConstructMetadata } from '../../core/lib/metadata-resource';
/**
* A configuration set event destination
*/
export interface IConfigurationSetEventDestination extends IResource {
/**
* The ID of the configuration set event destination
*
* @attribute
*/
readonly configurationSetEventDestinationId: string;
}
/**
* Options for a configuration set event destination
*/
export interface ConfigurationSetEventDestinationOptions {
/**
* A name for the configuration set event destination
*
* @default - a CloudFormation generated name
*/
readonly configurationSetEventDestinationName?: string;
/**
* Whether Amazon SES publishes events to this destination
*
* @default true
*/
readonly enabled?: boolean;
/**
* The event destination
*/
readonly destination: EventDestination;
/**
* The type of email sending events to publish to the event destination
*
* @default - send all event types
*/
readonly events?: EmailSendingEvent[];
}
/**
* An event destination
*/
export abstract class EventDestination {
/**
* Use a SNS topic as event destination
*/
public static snsTopic(topic: sns.ITopic): EventDestination {
return { topic };
}
/**
* Use CloudWatch dimensions as event destination
*/
public static cloudWatchDimensions(dimensions: CloudWatchDimension[]): EventDestination {
return { dimensions };
}
/**
* A SNS topic to use as event destination
*
* @default - do not send events to a SNS topic
*/
public abstract readonly topic?: sns.ITopic;
/**
* A list of CloudWatch dimensions upon which to categorize your emails
*
* @default - do not send events to CloudWatch
*/
public abstract readonly dimensions?: CloudWatchDimension[];
}
/**
* Properties for a configuration set event destination
*/
export interface ConfigurationSetEventDestinationProps extends ConfigurationSetEventDestinationOptions {
/**
* The configuration set that contains the event destination.
*/
readonly configurationSet: IConfigurationSet;
}
/**
* Email sending event
*/
export enum EmailSendingEvent {
/**
* The send request was successful and SES will attempt to deliver the message
* to the recipient's mail server. (If account-level or global suppression is
* being used, SES will still count it as a send, but delivery is suppressed.)
*/
SEND = 'send',
/**
* SES accepted the email, but determined that it contained a virus and didn’t
* attempt to deliver it to the recipient’s mail server.
*/
REJECT = 'reject',
/**
* (Hard bounce) The recipient's mail server permanently rejected the email.
* (Soft bounces are only included when SES fails to deliver the email after
* retrying for a period of time.)
*/
BOUNCE = 'bounce',
/**
* The email was successfully delivered to the recipient’s mail server, but the
* recipient marked it as spam.
*/
COMPLAINT = 'complaint',
/**
* SES successfully delivered the email to the recipient's mail server.
*/
DELIVERY = 'delivery',
/**
* The recipient received the message and opened it in their email client.
*/
OPEN = 'open',
/**
* The recipient clicked one or more links in the email.
*/
CLICK = 'click',
/**
* The email wasn't sent because of a template rendering issue. This event type
* can occur when template data is missing, or when there is a mismatch between
* template parameters and data. (This event type only occurs when you send email
* using the `SendTemplatedEmail` or `SendBulkTemplatedEmail` API operations.)
*/
RENDERING_FAILURE = 'renderingFailure',
/**
* The email couldn't be delivered to the recipient’s mail server because a temporary
* issue occurred. Delivery delays can occur, for example, when the recipient's inbox
* is full, or when the receiving email server experiences a transient issue.
*/
DELIVERY_DELAY = 'deliveryDelay',
/**
* The email was successfully delivered, but the recipient updated their subscription
* preferences by clicking on an unsubscribe link as part of your subscription management.
*/
SUBSCRIPTION = 'subscription',
}
/**
* A CloudWatch dimension upon which to categorize your emails
*/
export interface CloudWatchDimension {
/**
* The place where Amazon SES finds the value of a dimension to publish to
* Amazon CloudWatch.
*/
readonly source: CloudWatchDimensionSource;
/**
* The name of an Amazon CloudWatch dimension associated with an email sending metric.
*/
readonly name: string;
/**
* The default value of the dimension that is published to Amazon CloudWatch
* if you do not provide the value of the dimension when you send an email.
*/
readonly defaultValue: string;
}
/**
* Source for CloudWatch dimension
*/
export enum CloudWatchDimensionSource {
/**
* Amazon SES retrieves the dimension name and value from a header in the email.
*
* Note: You can't use any of the following email headers as the Dimension Name:
* `Received`, `To`, `From`, `DKIM-Signature`, `CC`, `message-id`, or `Return-Path`.
*/
EMAIL_HEADER = 'emailHeader',
/**
* Amazon SES retrieves the dimension name and value from a tag that you specified in a link.
*
* @see https://docs.aws.amazon.com/ses/latest/dg/faqs-metrics.html#sending-metric-faqs-clicks-q5
*/
LINK_TAG = 'linkTag',
/**
* Amazon SES retrieves the dimension name and value from a tag that you specify by using the
* `X-SES-MESSAGE-TAGS` header or the Tags API parameter.
*
* You can also use the Message Tag value source to create dimensions based on Amazon SES auto-tags.
* To use an auto-tag, type the complete name of the auto-tag as the Dimension Name. For example,
* to create a dimension based on the configuration set auto-tag, use `ses:configuration-set` for the
* Dimension Name, and the name of the configuration set for the Default Value.
*
* @see https://docs.aws.amazon.com/ses/latest/dg/event-publishing-send-email.html
* @see https://docs.aws.amazon.com/ses/latest/dg/monitor-using-event-publishing.html#event-publishing-how-works
*/
MESSAGE_TAG = 'messageTag',
}
/**
* A configuration set event destination
*/
export class ConfigurationSetEventDestination extends Resource implements IConfigurationSetEventDestination {
/**
* Use an existing configuration set
*/
public static fromConfigurationSetEventDestinationId(
scope: Construct,
id: string,
configurationSetEventDestinationId: string): IConfigurationSetEventDestination {
class Import extends Resource implements IConfigurationSetEventDestination {
public readonly configurationSetEventDestinationId = configurationSetEventDestinationId;
}
return new Import(scope, id);
}
public readonly configurationSetEventDestinationId: string;
constructor(scope: Construct, id: string, props: ConfigurationSetEventDestinationProps) {
super(scope, id, {
physicalName: props.configurationSetEventDestinationName,
});
// Enhanced CDK Analytics Telemetry
addConstructMetadata(this, props);
const configurationSet = new CfnConfigurationSetEventDestination(this, 'Resource', {
configurationSetName: props.configurationSet.configurationSetName,
eventDestination: {
name: this.physicalName,
enabled: props.enabled ?? true,
matchingEventTypes: props.events ?? Object.values(EmailSendingEvent),
snsDestination: props.destination.topic ? { topicArn: props.destination.topic.topicArn } : undefined,
cloudWatchDestination: props.destination.dimensions
? {
dimensionConfigurations: props.destination.dimensions.map(dimension => ({
dimensionValueSource: dimension.source,
dimensionName: dimension.name,
defaultDimensionValue: dimension.defaultValue,
})),
}
: undefined,
},
});
this.configurationSetEventDestinationId = configurationSet.attrId;
if (props.destination.topic) {
const result = props.destination.topic.addToResourcePolicy(new iam.PolicyStatement({
actions: ['sns:Publish'],
resources: [props.destination.topic.topicArn],
principals: [new iam.ServicePrincipal('ses.amazonaws.com')],
conditions: {
StringEquals: {
'AWS:SourceAccount': this.env.account,
'AWS:SourceArn': `arn:${Aws.PARTITION}:ses:${this.env.region}:${this.env.account}:configuration-set/${props.configurationSet.configurationSetName}`,
},
},
}));
if (result.policyDependable) {
this.node.addDependency(result.policyDependable);
}
}
}
}