aws_lambda_events/event/ses/
mod.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3#[cfg(feature = "catch-all-fields")]
4use serde_json::Value;
5
6/// `SimpleEmailEvent` is the outer structure of an event sent via SES.
7#[non_exhaustive]
8#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct SimpleEmailEvent {
11    #[serde(rename = "Records")]
12    pub records: Vec<SimpleEmailRecord>,
13    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
14    /// Enabled with Cargo feature `catch-all-fields`.
15    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
16    #[cfg(feature = "catch-all-fields")]
17    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
18    #[serde(flatten)]
19    pub other: serde_json::Map<String, Value>,
20}
21
22#[non_exhaustive]
23#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct SimpleEmailRecord {
26    #[serde(default)]
27    pub event_version: Option<String>,
28    #[serde(default)]
29    pub event_source: Option<String>,
30    pub ses: SimpleEmailService,
31    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
32    /// Enabled with Cargo feature `catch-all-fields`.
33    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
34    #[cfg(feature = "catch-all-fields")]
35    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
36    #[serde(flatten)]
37    pub other: serde_json::Map<String, Value>,
38}
39
40#[non_exhaustive]
41#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
42#[serde(rename_all = "camelCase")]
43pub struct SimpleEmailService {
44    pub mail: SimpleEmailMessage,
45    pub receipt: SimpleEmailReceipt,
46    pub content: Option<String>,
47    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
48    /// Enabled with Cargo feature `catch-all-fields`.
49    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
50    #[cfg(feature = "catch-all-fields")]
51    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
52    #[serde(flatten)]
53    pub other: serde_json::Map<String, Value>,
54}
55
56#[non_exhaustive]
57#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
58#[serde(rename_all = "camelCase")]
59pub struct SimpleEmailMessage {
60    pub common_headers: SimpleEmailCommonHeaders,
61    #[serde(default)]
62    pub source: Option<String>,
63    pub timestamp: DateTime<Utc>,
64    pub destination: Vec<String>,
65    pub headers: Vec<SimpleEmailHeader>,
66    pub headers_truncated: bool,
67    #[serde(default)]
68    pub message_id: Option<String>,
69    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
70    /// Enabled with Cargo feature `catch-all-fields`.
71    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
72    #[cfg(feature = "catch-all-fields")]
73    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
74    #[serde(flatten)]
75    pub other: serde_json::Map<String, Value>,
76}
77
78#[non_exhaustive]
79#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
80#[serde(rename_all = "camelCase")]
81pub struct SimpleEmailReceipt {
82    pub recipients: Vec<String>,
83    pub timestamp: DateTime<Utc>,
84    pub spam_verdict: SimpleEmailVerdict,
85    pub dkim_verdict: SimpleEmailVerdict,
86    pub dmarc_verdict: SimpleEmailVerdict,
87    #[serde(default)]
88    pub dmarc_policy: Option<String>,
89    pub spf_verdict: SimpleEmailVerdict,
90    pub virus_verdict: SimpleEmailVerdict,
91    pub action: SimpleEmailReceiptAction,
92    pub processing_time_millis: i64,
93    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
94    /// Enabled with Cargo feature `catch-all-fields`.
95    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
96    #[cfg(feature = "catch-all-fields")]
97    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
98    #[serde(flatten)]
99    pub other: serde_json::Map<String, Value>,
100}
101
102#[non_exhaustive]
103#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
104#[serde(rename_all = "camelCase")]
105pub struct SimpleEmailHeader {
106    #[serde(default)]
107    pub name: Option<String>,
108    #[serde(default)]
109    pub value: Option<String>,
110    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
111    /// Enabled with Cargo feature `catch-all-fields`.
112    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
113    #[cfg(feature = "catch-all-fields")]
114    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
115    #[serde(flatten)]
116    pub other: serde_json::Map<String, Value>,
117}
118
119#[non_exhaustive]
120#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
121#[serde(rename_all = "camelCase")]
122pub struct SimpleEmailCommonHeaders {
123    pub from: Vec<String>,
124    pub to: Vec<String>,
125    #[serde(default)]
126    pub return_path: Option<String>,
127    #[serde(default)]
128    pub message_id: Option<String>,
129    #[serde(default)]
130    pub date: Option<String>,
131    #[serde(default)]
132    pub subject: Option<String>,
133    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
134    /// Enabled with Cargo feature `catch-all-fields`.
135    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
136    #[cfg(feature = "catch-all-fields")]
137    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
138    #[serde(flatten)]
139    pub other: serde_json::Map<String, Value>,
140}
141
142/// `SimpleEmailReceiptAction` is a logical union of fields present in all action
143/// Types. For example, the FunctionARN and InvocationType fields are only
144/// present for the Lambda Type, and the BucketName and ObjectKey fields are only
145/// present for the S3 Type.
146#[non_exhaustive]
147#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
148#[serde(rename_all = "camelCase")]
149pub struct SimpleEmailReceiptAction {
150    #[serde(default)]
151    pub type_: Option<String>,
152    pub topic_arn: Option<String>,
153    pub bucket_name: Option<String>,
154    pub object_key: Option<String>,
155    pub smtp_reply_code: Option<String>,
156    pub status_code: Option<String>,
157    pub message: Option<String>,
158    pub sender: Option<String>,
159    pub invocation_type: Option<String>,
160    pub function_arn: Option<String>,
161    pub organization_arn: Option<String>,
162    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
163    /// Enabled with Cargo feature `catch-all-fields`.
164    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
165    #[cfg(feature = "catch-all-fields")]
166    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
167    #[serde(flatten)]
168    pub other: serde_json::Map<String, Value>,
169}
170
171#[non_exhaustive]
172#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
173#[serde(rename_all = "camelCase")]
174pub struct SimpleEmailVerdict {
175    #[serde(default)]
176    pub status: Option<String>,
177    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
178    /// Enabled with Cargo feature `catch-all-fields`.
179    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
180    #[cfg(feature = "catch-all-fields")]
181    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
182    #[serde(flatten)]
183    pub other: serde_json::Map<String, Value>,
184}
185
186pub type SimpleEmailDispositionValue = String;
187
188/// `SimpleEmailDisposition` disposition return for SES to control rule functions
189#[non_exhaustive]
190#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize, Serialize)]
191#[serde(rename_all = "camelCase")]
192pub struct SimpleEmailDisposition {
193    pub disposition: SimpleEmailDispositionValue,
194    /// Catchall to catch any additional fields that were present but not explicitly defined by this struct.
195    /// Enabled with Cargo feature `catch-all-fields`.
196    /// If `catch-all-fields` is disabled, any additional fields that are present will be ignored.
197    #[cfg(feature = "catch-all-fields")]
198    #[cfg_attr(docsrs, doc(cfg(feature = "catch-all-fields")))]
199    #[serde(flatten)]
200    pub other: serde_json::Map<String, Value>,
201}
202
203#[cfg(test)]
204mod test {
205    use super::*;
206
207    #[test]
208    #[cfg(feature = "ses")]
209    fn example_ses_lambda_event() {
210        let data = include_bytes!("../../fixtures/example-ses-lambda-event.json");
211        let parsed: SimpleEmailEvent = serde_json::from_slice(data).unwrap();
212        let output: String = serde_json::to_string(&parsed).unwrap();
213        let reparsed: SimpleEmailEvent = serde_json::from_slice(output.as_bytes()).unwrap();
214        assert_eq!(parsed, reparsed);
215    }
216
217    #[test]
218    #[cfg(feature = "ses")]
219    fn example_ses_s3_event() {
220        let data = include_bytes!("../../fixtures/example-ses-s3-event.json");
221        let parsed: SimpleEmailEvent = serde_json::from_slice(data).unwrap();
222        let output: String = serde_json::to_string(&parsed).unwrap();
223        let reparsed: SimpleEmailEvent = serde_json::from_slice(output.as_bytes()).unwrap();
224        assert_eq!(parsed, reparsed);
225    }
226
227    #[test]
228    #[cfg(feature = "ses")]
229    fn example_ses_sns_event() {
230        let data = include_bytes!("../../fixtures/example-ses-sns-event.json");
231        let parsed: SimpleEmailEvent = serde_json::from_slice(data).unwrap();
232        let output: String = serde_json::to_string(&parsed).unwrap();
233        let reparsed: SimpleEmailEvent = serde_json::from_slice(output.as_bytes()).unwrap();
234        assert_eq!(parsed, reparsed);
235    }
236}