Skip to main content

rustack_ses_core/
config.rs

1//! SES service configuration.
2
3use std::env;
4
5/// SES service configuration.
6#[derive(Debug, Clone)]
7pub struct SesConfig {
8    /// Skip signature validation (default: true for local dev).
9    pub skip_signature_validation: bool,
10    /// Default AWS region.
11    pub default_region: String,
12    /// Default AWS account ID.
13    pub default_account_id: String,
14    /// Whether to require verified identities for sending.
15    /// When false (default), any source address is accepted.
16    /// When true, source must be verified via `VerifyEmailIdentity`/`VerifyDomainIdentity`.
17    pub require_verified_identity: bool,
18    /// Max sends per 24 hours (for `GetSendQuota`). Default: 200 (sandbox).
19    pub max_24_hour_send: f64,
20    /// Max send rate per second (for `GetSendQuota`). Default: 1.0 (sandbox).
21    pub max_send_rate: f64,
22}
23
24impl SesConfig {
25    /// Create configuration from environment variables.
26    #[must_use]
27    pub fn from_env() -> Self {
28        Self {
29            skip_signature_validation: env_bool("SES_SKIP_SIGNATURE_VALIDATION", true),
30            default_region: env::var("DEFAULT_REGION").unwrap_or_else(|_| "us-east-1".to_owned()),
31            default_account_id: env::var("DEFAULT_ACCOUNT_ID")
32                .unwrap_or_else(|_| "000000000000".to_owned()),
33            require_verified_identity: env_bool("SES_REQUIRE_VERIFIED_IDENTITY", false),
34            max_24_hour_send: env_f64("SES_MAX_24_HOUR_SEND", 200.0),
35            max_send_rate: env_f64("SES_MAX_SEND_RATE", 1.0),
36        }
37    }
38}
39
40impl Default for SesConfig {
41    fn default() -> Self {
42        Self {
43            skip_signature_validation: true,
44            default_region: "us-east-1".to_owned(),
45            default_account_id: "000000000000".to_owned(),
46            require_verified_identity: false,
47            max_24_hour_send: 200.0,
48            max_send_rate: 1.0,
49        }
50    }
51}
52
53fn env_bool(key: &str, default: bool) -> bool {
54    env::var(key).map_or(default, |v| {
55        v.eq_ignore_ascii_case("true") || v.eq_ignore_ascii_case("yes") || v == "1"
56    })
57}
58
59fn env_f64(key: &str, default: f64) -> f64 {
60    env::var(key)
61        .ok()
62        .and_then(|v| v.parse().ok())
63        .unwrap_or(default)
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn test_should_create_default_config() {
72        let config = SesConfig::default();
73        assert!(config.skip_signature_validation);
74        assert_eq!(config.default_region, "us-east-1");
75        assert_eq!(config.default_account_id, "000000000000");
76        assert!(!config.require_verified_identity);
77        assert!((config.max_24_hour_send - 200.0).abs() < f64::EPSILON);
78        assert!((config.max_send_rate - 1.0).abs() < f64::EPSILON);
79    }
80
81    #[test]
82    fn test_should_parse_env_bool_values() {
83        assert!(env_bool("NONEXISTENT_VAR_12345", true));
84        assert!(!env_bool("NONEXISTENT_VAR_12345", false));
85    }
86
87    #[test]
88    fn test_should_parse_env_f64_values() {
89        assert!((env_f64("NONEXISTENT_VAR_12345", 42.0) - 42.0).abs() < f64::EPSILON);
90    }
91}