Skip to main content

rok_mail/
lib.rs

1mod drivers;
2mod mail;
3
4pub mod config;
5pub mod error;
6pub mod errors;
7pub mod mailable;
8
9#[cfg(feature = "axum")]
10pub mod mail_layer;
11
12#[cfg(feature = "queue")]
13pub mod queue_job;
14
15pub use config::MailConfig;
16pub use error::MailError;
17pub use mail::{global_config, set_global_config, Mail};
18pub use mailable::Mailable;
19
20#[cfg(feature = "markdown")]
21pub use mailable::MarkdownMailable;
22
23#[cfg(feature = "axum")]
24pub use mail_layer::MailLayer;
25
26// ── Tests ─────────────────────────────────────────────────────────────────────
27
28#[cfg(test)]
29mod tests {
30    use crate::{Mail, MailConfig, MailError, Mailable};
31
32    struct Welcome {
33        name: String,
34    }
35
36    impl Mailable for Welcome {
37        fn subject(&self) -> &str {
38            "Welcome!"
39        }
40        fn body(&self) -> String {
41            format!("Hi, {}!", self.name)
42        }
43        fn html_body(&self) -> Option<String> {
44            Some(format!("<p>Hi, <b>{}</b>!</p>", self.name))
45        }
46    }
47
48    fn log_config() -> MailConfig {
49        MailConfig {
50            driver: "log".into(),
51            ..MailConfig::default()
52        }
53    }
54
55    #[test]
56    fn mailable_subject_and_body() {
57        let m = Welcome {
58            name: "Alice".into(),
59        };
60        assert_eq!(m.subject(), "Welcome!");
61        assert!(m.body().contains("Alice"));
62        assert!(m.html_body().unwrap().contains("Alice"));
63    }
64
65    #[test]
66    fn mail_config_defaults() {
67        let c = MailConfig::default();
68        assert_eq!(c.driver, "log");
69        assert_eq!(c.from_address, "noreply@rok-app.com");
70        assert_eq!(c.smtp_port, 587);
71        assert_eq!(c.smtp_encryption, "starttls");
72        assert!(c.postmark_api_key.is_none());
73        assert!(c.resend_api_key.is_none());
74    }
75
76    #[tokio::test]
77    async fn send_with_log_driver_succeeds() {
78        let result = Mail::send_with(
79            Welcome { name: "Bob".into() },
80            "bob@example.com",
81            &log_config(),
82        )
83        .await;
84        assert!(result.is_ok());
85    }
86
87    #[tokio::test]
88    async fn send_with_unknown_driver_returns_error() {
89        let config = MailConfig {
90            driver: "carrier_pigeon".into(),
91            ..MailConfig::default()
92        };
93        let result = Mail::send_with(
94            Welcome {
95                name: "Carol".into(),
96            },
97            "carol@example.com",
98            &config,
99        )
100        .await;
101        assert!(matches!(result, Err(MailError::UnknownDriver(d)) if d == "carrier_pigeon"));
102    }
103
104    #[tokio::test]
105    async fn send_without_layer_returns_not_configured() {
106        let result = Mail::send(
107            Welcome {
108                name: "Dave".into(),
109            },
110            "dave@example.com",
111        )
112        .await;
113        assert!(matches!(result, Err(MailError::NotConfigured)));
114    }
115}