Open seanadkinson opened 5 months ago
My first pass below. Not sure if I got all the optionals correct, but verified against each of the example events here.
type SESEventNotification =
| SESBounceNotification
| SESComplaintNotification
| SESDeliveryNotification
| SESSendNotification
| SESRejectNotification
| SESOpenNotification
| SESClickNotification
| SESRenderingFailureNotification
| SESDeliveryDelayNotification
| SESSubscriptionNotification;
type SESCommonNotification = {
mail: {
timestamp: string,
messageId: string,
source: string,
sourceArn: string,
sendingAccountId: string,
destination: string[],
headersTruncated: boolean,
headers: { name: string, value: string }[],
commonHeaders: Record<string, string | string[]>,
tags: Record<string, string[]>
}
}
type BounceTypes =
| { bounceType: 'Undetermined', bounceSubType: 'Undetermined' }
| { bounceType: 'Permanent', bounceSubType: 'General' | 'NoEmail' | 'Suppressed' | 'OnAccountSuppressionList' }
| { bounceType: 'Transient', bounceSubType: 'General' | 'MailboxFull' | 'MessageTooLarge' | 'ContentRejected' | 'AttachmentRejected' }
type SESBounceNotification = SESCommonNotification & {
eventType: 'Bounce'
bounce: BounceTypes & {
bouncedRecipients: {
emailAddress: string,
action?: string,
status?: string,
diagnosticCode?: string
}[],
timestamp: string,
feedbackId: string,
reportingMTA?: string
}
}
type SESComplaintNotification = SESCommonNotification & {
eventType: 'Complaint',
complaint: {
complainedRecipients: { emailAddress: string }[],
timestamp: string,
feedbackId: string,
complaintSubType?: string,
userAgent?: string,
complaintFeedbackType?: 'abuse' | 'auth-failure' | 'fraud' | 'not-spam' | 'other' | 'virus',
arrivalDate?: string,
}
}
type SESDeliveryNotification = SESCommonNotification & {
eventType: 'Delivery',
delivery: {
timestamp: string,
processingTimeMillis: number,
recipients: string[],
smtpResponse: string,
reportingMTA?: string,
}
}
type SESSendNotification = SESCommonNotification & {
eventType: 'Send',
send: {}
}
type SESRejectNotification = SESCommonNotification & {
eventType: 'Reject',
reject: {
reason: string
}
}
type SESOpenNotification = SESCommonNotification & {
eventType: 'Open',
open: {
ipAddress: string,
timestamp: string,
userAgent: string,
}
}
type SESClickNotification = SESCommonNotification & {
eventType: 'Click',
click: {
ipAddress: string,
link: string,
linkTags: Record<string, string[]>,
timestamp: string,
userAgent: string,
}
}
type SESRenderingFailureNotification = SESCommonNotification & {
eventType: 'Rendering Failure'
failure: {
templateName: string,
errorMessage: string,
}
}
type SESDeliveryDelayNotification = SESCommonNotification & {
eventType: 'DeliveryDelay',
deliveryDelay: {
delayType: 'InternalFailure' | 'General' | 'MailboxFull' | 'SpamDetected' | 'RecipientServerError' | 'IPFailure' | 'TransientCommunicationFailure' | 'BYOIPHostNameLookupUnavailable' | 'Undetermined' | 'SendingDeferral',
delayedRecipients: { emailAddress: string, status: string, diagnosticCode: string }[],
expirationTime: string,
reportingMTA?: string,
timestamp: string,
}
}
type SESSubscriptionNotification = SESCommonNotification & {
eventType: 'Subscription',
subscription: {
contactList: string,
timestamp: string,
source: string,
newTopicPreferences: TopicPreferences,
oldTopicPreferences: TopicPreferences
}
}
type TopicPreferences = {
unsubscribeAll: boolean,
topicSubscriptionStatus: {
topicName: EmailTopic,
subscriptionStatus: 'OptIn' | 'OptOut'
}[],
topicDefaultSubscriptionStatus: {
topicName: EmailTopic,
subscriptionStatus: 'OptIn' | 'OptOut'
}[]
}
Describe the feature
Please add types for notification events sent by SES. The structure of the events are documented here, but I can't find any typescript types in the SDK that allow me to code against this structure. Perhaps I am just missing them?
Use Case
I'd like to subscribe to these SESv2 Notifications from Node, and use Typescript to ensure I am only accessing supported properties and fields on the notification event objects.
Proposed Solution
Export a new
type
, named something likeSESEventNotification
, which uses a Discriminated Union on theeventType
field to determine the object's structure, similar to how this commenter suggested in the v2 SDKOther Information
No response
Acknowledgements
SDK version used
3.583.0
Environment details (OS name and version, etc.)
Node v20, Typescript v5