1use std::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
10#[non_exhaustive]
11pub enum SesErrorCode {
12 #[default]
14 AccountSendingPausedException,
15 AlreadyExists,
17 AlreadyExistsException,
19 CannotDeleteException,
21 ConfigurationSetAlreadyExistsException,
23 ConfigurationSetDoesNotExist,
25 ConfigurationSetDoesNotExistException,
27 ConfigurationSetSendingPausedException,
29 EventDestinationAlreadyExistsException,
31 EventDestinationDoesNotExistException,
33 InternalError,
35 InvalidCloudWatchDestinationException,
37 InvalidConfigurationSetException,
39 InvalidFirehoseDestinationException,
41 InvalidLambdaFunctionException,
43 InvalidParameterValue,
45 InvalidPolicyException,
47 InvalidS3ConfigurationException,
49 InvalidSNSDestinationException,
51 InvalidSnsTopicException,
53 InvalidTemplate,
55 InvalidTemplateException,
57 LimitExceeded,
59 LimitExceededException,
61 MailFromDomainNotVerifiedException,
63 MessageRejected,
65 MissingAction,
67 RuleDoesNotExist,
69 RuleDoesNotExistException,
71 RuleSetDoesNotExist,
73 RuleSetDoesNotExistException,
75 TemplateDoesNotExist,
77 TemplateDoesNotExistException,
79}
80
81impl SesErrorCode {
82 #[must_use]
84 pub fn error_type(&self) -> &'static str {
85 self.as_str()
86 }
87
88 #[must_use]
90 pub fn as_str(&self) -> &'static str {
91 match self {
92 Self::AccountSendingPausedException => "AccountSendingPausedException",
93 Self::AlreadyExists => "AlreadyExists",
94 Self::AlreadyExistsException => "AlreadyExistsException",
95 Self::CannotDeleteException => "CannotDeleteException",
96 Self::ConfigurationSetAlreadyExistsException => {
97 "ConfigurationSetAlreadyExistsException"
98 }
99 Self::ConfigurationSetDoesNotExist => "ConfigurationSetDoesNotExist",
100 Self::ConfigurationSetDoesNotExistException => "ConfigurationSetDoesNotExistException",
101 Self::ConfigurationSetSendingPausedException => {
102 "ConfigurationSetSendingPausedException"
103 }
104 Self::EventDestinationAlreadyExistsException => {
105 "EventDestinationAlreadyExistsException"
106 }
107 Self::EventDestinationDoesNotExistException => "EventDestinationDoesNotExistException",
108 Self::InternalError => "InternalError",
109 Self::InvalidCloudWatchDestinationException => "InvalidCloudWatchDestinationException",
110 Self::InvalidConfigurationSetException => "InvalidConfigurationSetException",
111 Self::InvalidFirehoseDestinationException => "InvalidFirehoseDestinationException",
112 Self::InvalidLambdaFunctionException => "InvalidLambdaFunctionException",
113 Self::InvalidParameterValue => "InvalidParameterValue",
114 Self::InvalidPolicyException => "InvalidPolicyException",
115 Self::InvalidS3ConfigurationException => "InvalidS3ConfigurationException",
116 Self::InvalidSNSDestinationException => "InvalidSNSDestinationException",
117 Self::InvalidSnsTopicException => "InvalidSnsTopicException",
118 Self::InvalidTemplate => "InvalidTemplate",
119 Self::InvalidTemplateException => "InvalidTemplateException",
120 Self::LimitExceeded => "LimitExceeded",
121 Self::LimitExceededException => "LimitExceededException",
122 Self::MailFromDomainNotVerifiedException => "MailFromDomainNotVerifiedException",
123 Self::MessageRejected => "MessageRejected",
124 Self::MissingAction => "MissingAction",
125 Self::RuleDoesNotExist => "RuleDoesNotExist",
126 Self::RuleDoesNotExistException => "RuleDoesNotExistException",
127 Self::RuleSetDoesNotExist => "RuleSetDoesNotExist",
128 Self::RuleSetDoesNotExistException => "RuleSetDoesNotExistException",
129 Self::TemplateDoesNotExist => "TemplateDoesNotExist",
130 Self::TemplateDoesNotExistException => "TemplateDoesNotExistException",
131 }
132 }
133
134 #[must_use]
136 pub fn code(&self) -> &'static str {
137 self.as_str()
138 }
139
140 #[must_use]
142 pub fn status_code(&self) -> http::StatusCode {
143 self.default_status_code()
144 }
145
146 #[must_use]
148 pub fn fault(&self) -> &'static str {
149 match self {
150 Self::InternalError => "Receiver",
151 _ => "Sender",
152 }
153 }
154
155 #[must_use]
157 pub fn default_status_code(&self) -> http::StatusCode {
158 match self {
159 Self::AccountSendingPausedException
160 | Self::AlreadyExists
161 | Self::AlreadyExistsException
162 | Self::CannotDeleteException
163 | Self::ConfigurationSetAlreadyExistsException
164 | Self::ConfigurationSetDoesNotExist
165 | Self::ConfigurationSetDoesNotExistException
166 | Self::ConfigurationSetSendingPausedException
167 | Self::EventDestinationAlreadyExistsException
168 | Self::EventDestinationDoesNotExistException
169 | Self::InvalidCloudWatchDestinationException
170 | Self::InvalidConfigurationSetException
171 | Self::InvalidFirehoseDestinationException
172 | Self::InvalidLambdaFunctionException
173 | Self::InvalidParameterValue
174 | Self::InvalidPolicyException
175 | Self::InvalidS3ConfigurationException
176 | Self::InvalidSNSDestinationException
177 | Self::InvalidSnsTopicException
178 | Self::InvalidTemplate
179 | Self::InvalidTemplateException
180 | Self::LimitExceeded
181 | Self::LimitExceededException
182 | Self::MailFromDomainNotVerifiedException
183 | Self::MessageRejected
184 | Self::MissingAction
185 | Self::RuleDoesNotExist
186 | Self::RuleDoesNotExistException
187 | Self::RuleSetDoesNotExist
188 | Self::RuleSetDoesNotExistException
189 | Self::TemplateDoesNotExist
190 | Self::TemplateDoesNotExistException => http::StatusCode::BAD_REQUEST,
191 Self::InternalError => http::StatusCode::INTERNAL_SERVER_ERROR,
192 }
193 }
194}
195
196impl fmt::Display for SesErrorCode {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.write_str(self.as_str())
199 }
200}
201
202#[derive(Debug)]
204pub struct SesError {
205 pub code: SesErrorCode,
207 pub message: String,
209 pub status_code: http::StatusCode,
211 pub source: Option<Box<dyn std::error::Error + Send + Sync>>,
213}
214
215impl fmt::Display for SesError {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(f, "SesError({}): {}", self.code, self.message)
218 }
219}
220
221impl std::error::Error for SesError {
222 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
223 self.source
224 .as_ref()
225 .map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
226 }
227}
228
229impl SesError {
230 #[must_use]
232 pub fn new(code: SesErrorCode) -> Self {
233 Self {
234 status_code: code.default_status_code(),
235 message: code.as_str().to_owned(),
236 code,
237 source: None,
238 }
239 }
240
241 #[must_use]
243 pub fn with_message(code: SesErrorCode, message: impl Into<String>) -> Self {
244 Self {
245 status_code: code.default_status_code(),
246 message: message.into(),
247 code,
248 source: None,
249 }
250 }
251
252 #[must_use]
254 pub fn error_type(&self) -> &'static str {
255 self.code.error_type()
256 }
257
258 #[must_use]
260 pub fn internal_error(message: impl Into<String>) -> Self {
261 Self::with_message(SesErrorCode::InternalError, message)
262 }
263
264 #[must_use]
266 pub fn missing_action() -> Self {
267 Self::with_message(
268 SesErrorCode::MissingAction,
269 "Missing required header: X-Amz-Target",
270 )
271 }
272
273 #[must_use]
275 pub fn not_implemented(operation: &str) -> Self {
276 Self::with_message(
277 SesErrorCode::InternalError,
278 format!("Operation {operation} is not yet implemented"),
279 )
280 }
281
282 #[must_use]
284 pub fn invalid_parameter_value(message: impl Into<String>) -> Self {
285 Self::with_message(SesErrorCode::InvalidParameterValue, message)
286 }
287
288 #[must_use]
290 pub fn invalid_action(action: &str) -> Self {
291 Self::with_message(
292 SesErrorCode::InvalidParameterValue,
293 format!("Unrecognized operation: {action}"),
294 )
295 }
296
297 #[must_use]
299 pub fn message_rejected(message: impl Into<String>) -> Self {
300 Self::with_message(SesErrorCode::MessageRejected, message)
301 }
302
303 #[must_use]
305 pub fn template_does_not_exist(name: &str) -> Self {
306 Self::with_message(
307 SesErrorCode::TemplateDoesNotExist,
308 format!("Template {name} does not exist"),
309 )
310 }
311}
312
313#[macro_export]
322macro_rules! ses_error {
323 ($code:ident) => {
324 $crate::error::SesError::new($crate::error::SesErrorCode::$code)
325 };
326 ($code:ident, $msg:expr) => {
327 $crate::error::SesError::with_message($crate::error::SesErrorCode::$code, $msg)
328 };
329}