1use std::{borrow::Cow, error::Error, fmt::Debug, sync::Arc};
2pub(crate) mod shared;
3use email_types::Mailbox;
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5use template::EmailBody;
6pub mod email_types;
7#[cfg(feature = "mail-gun")]
8pub mod mail_gun;
9#[cfg(feature = "mail-whale")]
10pub mod mail_whale;
11pub mod no_op;
12#[cfg(feature = "smtp")]
13pub mod smtp;
14pub mod template;
15#[cfg(feature = "tokio")]
16pub(crate) mod tokio_rt;
17
18#[cfg(feature = "tokio")]
19#[doc(inline)]
20pub use tokio_rt::ServiceState;
21#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, Default)]
25pub enum MailServiceTypes {
26 #[cfg(feature = "smtp")]
27 SMTP,
28 #[cfg(feature = "mail-gun")]
29 MailGun,
30 #[cfg(feature = "mail-whale")]
31 MailWhale,
32 #[default]
33 None,
34}
35
36#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
37#[serde(tag = "method", content = "settings")]
38pub enum MailServiceSettings {
39 #[cfg(feature = "smtp")]
40 SMTP(smtp::SMTPServiceSettings),
41 #[cfg(feature = "mail-gun")]
42 MailGun(mail_gun::MailGunSettings),
43 #[cfg(feature = "mail-whale")]
44 MailWhale(mail_whale::MailWhaleSettings),
45 None,
46}
47#[allow(async_fn_in_trait)]
51pub trait MailService {
52 type Settings;
53 type Access: EmailAccess<Settings = Self::Settings, ConnectionState = Self::ConnectionState>;
54 type Error: Error + Send + Sync + 'static;
55 type ConnectionState;
56
57 async fn init(settings: Self::Settings) -> Result<Self::Access, Self::Error>
58 where
59 Self: Sized;
60
61 fn get_state(&self) -> Arc<crate::shared::Mutex<Self::ConnectionState>>;
62
63 fn get_app_state(&self) -> Arc<ServiceState>;
64
65 fn get_settings(&self) -> Arc<Self::Settings>;
66
67 async fn is_connected(&self) -> bool;
68}
69pub trait EmailAccess: Clone + Send + Sync {
71 type Error: Error + Send + Sync + 'static;
72 type Settings: Clone + Serialize + DeserializeOwned;
73 type ConnectionState;
74
75 fn get_settings(&self) -> Arc<Self::Settings>;
76
77 fn send(&self, email: impl Email) -> Result<(), Self::Error>;
79
80 fn get_state(&self) -> Arc<crate::shared::Mutex<Self::ConnectionState>>;
81
82 fn get_app_state(&self) -> Arc<ServiceState>;
83}
84
85pub trait Email: Debug {
86 fn subject(&self) -> Cow<'static, str>;
87
88 fn body(&mut self) -> Option<EmailBody>;
89
90 fn to(&self) -> impl Iterator<Item = &Mailbox> + ExactSizeIterator + '_;
91
92 fn from(&self) -> Option<&Mailbox>;
93
94 fn reply_to(&self) -> Option<&Mailbox> {
95 None
96 }
97}
98pub trait EmailSettingsType: Clone + Serialize + DeserializeOwned {
99 fn from(&self) -> &Mailbox;
100
101 fn reply_to(&self) -> Option<&Mailbox>;
102}
103#[derive(Debug, Clone, PartialEq, Hash)]
104pub struct SimpleEmail {
105 pub subject: &'static str,
106 pub body: Option<EmailBody>,
107 pub to: Mailbox,
108 pub from: Option<Mailbox>,
109}
110
111impl Email for SimpleEmail {
112 fn subject(&self) -> Cow<'static, str> {
113 Cow::Borrowed(self.subject)
114 }
115
116 fn body(&mut self) -> Option<EmailBody> {
117 self.body.take()
118 }
119
120 fn to(&self) -> impl Iterator<Item = &Mailbox> + ExactSizeIterator + '_ {
121 std::iter::once(&self.to)
122 }
123
124 fn from(&self) -> Option<&Mailbox> {
125 self.from.as_ref()
126 }
127}