Repository navigation
Description
Expected Behaviour
SesModel and the SESEvent data class accept the events SES sends to a Lambda receipt rule action, as described in Contents of notifications for Amazon SES email receiving.
Current Behaviour
Two kinds of real events fail:
receipt.action.invocationTypeonly allowsEvent. The SES docs listRequestResponseandEvent, so a receipt rule that invokes the function synchronously fails with aValidationError.- Every
mail.commonHeadersfield exceptcc,bcc,senderandreplyTois required. The docs say the fields in that object "vary depending on which fields were present in the incoming email". So an email sent only to BCC recipients has noto, an email without a subject has nosubject, and both fail to parse.
The SESEvent data class has the same problem on reads. common_headers.to, get_from, subject, date, message_id, return_path and receipt.action.invocation_type raise KeyError when the field isn't in the event.
The TypeScript parser fixed the same thing in aws-powertools/powertools-lambda-typescript#5772 (issue aws-powertools/powertools-lambda-typescript#5771). Its issue also has a captured receipt event with no invocationType at all. The replyTo part of that fix already landed here in #8525, and the Python model doesn't require dmarcPolicy, so only the two points above are left.
Code snippet
from aws_lambda_powertools.utilities.parser import parse
from aws_lambda_powertools.utilities.parser.models import SesModel
# Lambda action invoked synchronously, for an email sent only to BCC recipients with no subject
event = {
"Records": [
{
"eventSource": "aws:ses",
"eventVersion": "1.0",
"ses": {
"mail": {
"timestamp": "2026-11-03T12:00:00.000Z",
"source": "janedoe@example.com",
"messageId": "o3vrnil0e2ic28trm7dfhrc2v0clambda4nbp0g1x",
"destination": ["johndoe@example.com"],
"headersTruncated": False,
"headers": [],
"commonHeaders": {
"returnPath": "janedoe@example.com",
"from": ["Jane Doe <janedoe@example.com>"],
"date": "Mon, 3 Nov 2026 12:00:00 +0000",
"messageId": "<0123456789example.com>",
},
},
"receipt": {
"timestamp": "2026-11-03T12:00:00.000Z",
"processingTimeMillis": 574,
"recipients": ["johndoe@example.com"],
"spamVerdict": {"status": "PASS"},
"virusVerdict": {"status": "PASS"},
"spfVerdict": {"status": "PASS"},
"dkimVerdict": {"status": "PASS"},
"dmarcVerdict": {"status": "PASS"},
"action": {
"type": "Lambda",
"invocationType": "RequestResponse",
"functionArn": "arn:aws:lambda:us-east-1:123456789012:function:Example",
},
},
},
}
]
}
parse(event=event, model=SesModel)pydantic_core._pydantic_core.ValidationError: 3 validation errors for SesModel
Records.0.ses.mail.commonHeaders.to
Field required [type=missing, input_value={'returnPath': 'janedoe@e...0123456789example.com>'}, input_type=dict]
Records.0.ses.mail.commonHeaders.subject
Field required [type=missing, input_value={'returnPath': 'janedoe@e...0123456789example.com>'}, input_type=dict]
Records.0.ses.receipt.action.invocationType
Input should be 'Event' [type=literal_error, input_value='RequestResponse', input_type=str]
Possible Solution
- allow
RequestResponseininvocationTypeand make it optional - make the
commonHeadersfields optional - in the data class, return
[]for missing list headers andNonefor missing string fields, the wayccanddmarc_policyalready do
I have a PR ready with tests.
Steps to Reproduce
pip install "aws-lambda-powertools[parser]==3.39.0"- Run the snippet above.
Did you run the reproduction yourself?
Yes, I ran it and saw the failure
Powertools for AWS Lambda (Python) version
3.39.0
AWS Lambda function runtime
3.12 (ran locally)
Packaging format used
PyPi
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity