any_mail/
lib.rs

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/// The Mail Service Types
22///
23/// This exists for the user to able to select the mail service. Good for when you want to parse the mail service from ENV variables.
24#[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/// The Layout for an Email Server
48///
49/// This should be used to create a new email service connection. Do not implement this trait. As the API is not stable.
50#[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}
69/// A Shared Access to the Mail Service. This is clonable and can be sent across threads.
70pub 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    /// Pushes an email to the queue.
78    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}