Files
swift-aws-lambda-events/Sources/AWSLambdaEvents/SES.swift
T
Sébastien Stormacq d18360e636 fix: Add support for DISABLED status in SES verdict enums (#110) (#111)
## Motivation:
AWS SES can return "`DISABLED`" as a valid status value for spam, virus,
DKIM, and SPF verdicts when certain checks are disabled in the SES
configuration. However, the `SESEvent.Receipt.Verdict.Status` enum was
missing this case, causing JSON decoding to fail with a `DecodingError`
when parsing SES events containing `{"status":"DISABLED"}`.

This issue was reported in #110, where users encountered parsing
failures when processing legitimate SES events from AWS that included
disabled verdict checks.

## Modifications:
Added `.disabled = "DISABLED"` case to the
`SESEvent.Receipt.Verdict.Status` enum in
SES.swift
Converted the existing test to a parameterized test using Swift
Testing's `@Test(arguments:)` syntax
Added a new test case (`eventBodyDisabled`) that includes a SES event
with `spamVerdict.status` set to "`DISABLED`"
Updated the test assertion to verify both `.pass` and `.disabled` status
values are handled correctly

## Result:
SES events with verdict statuses set to "`DISABLED`" will now decode
successfully without throwing errors. The library correctly handles all
valid AWS SES verdict status values: `PASS`, `FAIL`, `GRAY`,
`PROCESSING_FAILED`, and `DISABLED`. The parameterized test ensures both
standard and disabled verdict scenarios are validated automatically.
2026-01-29 07:36:21 +00:00

105 lines
3.1 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftAWSLambdaRuntime open source project
//
// Copyright SwiftAWSLambdaRuntime project authors
// Copyright (c)Amazon.com, Inc. or its affiliates.
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
// https://docs.aws.amazon.com/lambda/latest/dg/services-ses.html
public struct SESEvent: Decodable, Sendable {
public struct Record: Decodable, Sendable {
public let eventSource: String
public let eventVersion: String
public let ses: Message
}
public let records: [Record]
public enum CodingKeys: String, CodingKey {
case records = "Records"
}
public struct Message: Decodable, Sendable {
public let mail: Mail
public let receipt: Receipt
}
public struct Mail: Decodable, Sendable {
public let commonHeaders: CommonHeaders
public let destination: [String]
public let headers: [Header]
public let headersTruncated: Bool
public let messageId: String
public let source: String
@ISO8601WithFractionalSecondsCoding public var timestamp: Date
}
public struct CommonHeaders: Decodable, Sendable {
public let bcc: [String]?
public let cc: [String]?
@RFC5322DateTimeCoding public var date: Date
public let from: [String]
public let messageId: String?
public let returnPath: String?
public let subject: String?
public let to: [String]?
}
public struct Header: Decodable, Sendable {
public let name: String
public let value: String
}
public struct Receipt: Decodable, Sendable {
public let action: Action
public let dmarcPolicy: DMARCPolicy?
public let dmarcVerdict: Verdict?
public let dkimVerdict: Verdict
public let processingTimeMillis: Int
public let recipients: [String]
public let spamVerdict: Verdict
public let spfVerdict: Verdict
@ISO8601WithFractionalSecondsCoding public var timestamp: Date
public let virusVerdict: Verdict
}
public struct Action: Decodable, Sendable {
public let functionArn: String
public let invocationType: String
public let type: String
}
public struct Verdict: Decodable, Sendable {
public let status: Status
}
public enum DMARCPolicy: String, Decodable, Sendable {
case none
case quarantine
case reject
}
public enum Status: String, Decodable, Sendable {
case pass = "PASS"
case fail = "FAIL"
case gray = "GRAY"
case disabled = "DISABLED"
case processingFailed = "PROCESSING_FAILED"
}
}