email/sendmail/
mod.rs

1pub mod config;
2mod error;
3
4use std::sync::Arc;
5
6use async_trait::async_trait;
7use tracing::info;
8
9use self::config::SendmailConfig;
10#[doc(inline)]
11pub use self::error::{Error, Result};
12use crate::{
13    account::config::AccountConfig,
14    backend::{
15        context::{BackendContext, BackendContextBuilder},
16        feature::{BackendFeature, CheckUp},
17    },
18    message::send::{sendmail::SendSendmailMessage, SendMessage},
19    AnyResult,
20};
21
22#[derive(Clone, Debug, Default, Eq, PartialEq)]
23pub struct SendmailContext {
24    pub account_config: Arc<AccountConfig>,
25    pub sendmail_config: Arc<SendmailConfig>,
26}
27
28impl SendmailContext {
29    pub fn new(account_config: Arc<AccountConfig>, sendmail_config: Arc<SendmailConfig>) -> Self {
30        Self {
31            account_config,
32            sendmail_config,
33        }
34    }
35}
36
37pub type SendmailContextSync = SendmailContext;
38
39impl BackendContext for SendmailContextSync {}
40
41#[derive(Clone, Debug, Default, Eq, PartialEq)]
42pub struct SendmailContextBuilder {
43    /// The account configuration.
44    pub account_config: Arc<AccountConfig>,
45
46    /// The sendmail configuration.
47    pub sendmail_config: Arc<SendmailConfig>,
48}
49
50impl SendmailContextBuilder {
51    pub fn new(account_config: Arc<AccountConfig>, sendmail_config: Arc<SendmailConfig>) -> Self {
52        Self {
53            account_config,
54            sendmail_config,
55        }
56    }
57}
58
59#[async_trait]
60impl BackendContextBuilder for SendmailContextBuilder {
61    type Context = SendmailContextSync;
62
63    fn check_up(&self) -> Option<BackendFeature<Self::Context, dyn CheckUp>> {
64        Some(Arc::new(CheckUpSendmail::some_new_boxed))
65    }
66
67    fn send_message(&self) -> Option<BackendFeature<Self::Context, dyn SendMessage>> {
68        Some(Arc::new(SendSendmailMessage::some_new_boxed))
69    }
70
71    /// Build an SENDMAIL sync session.
72    ///
73    /// The SENDMAIL session is created at this moment. If the session
74    /// cannot be created using the OAuth 2.0 authentication, the
75    /// access token is refreshed first then a new session is created.
76    async fn build(self) -> AnyResult<Self::Context> {
77        info!("building new sendmail context");
78
79        Ok(SendmailContextSync {
80            account_config: self.account_config,
81            sendmail_config: self.sendmail_config,
82        })
83    }
84}
85
86#[derive(Clone)]
87pub struct CheckUpSendmail {
88    pub ctx: SendmailContextSync,
89}
90
91impl CheckUpSendmail {
92    pub fn new(ctx: &SendmailContext) -> Self {
93        Self { ctx: ctx.clone() }
94    }
95
96    pub fn new_boxed(ctx: &SendmailContext) -> Box<dyn CheckUp> {
97        Box::new(Self::new(ctx))
98    }
99
100    pub fn some_new_boxed(ctx: &SendmailContext) -> Option<Box<dyn CheckUp>> {
101        Some(Self::new_boxed(ctx))
102    }
103}
104
105#[async_trait]
106impl CheckUp for CheckUpSendmail {
107    async fn check_up(&self) -> AnyResult<()> {
108        self.ctx
109            .sendmail_config
110            .cmd()
111            .run()
112            .await
113            .map_err(Error::ExecuteCommandError)?;
114        Ok(())
115    }
116}