rok-mail 0.1.0

Email support for the rok ecosystem — Mailable trait, log/SMTP drivers
Documentation
use std::sync::Arc;

use crate::{MailConfig, MailError, Mailable};

tokio::task_local! {
    pub(crate) static CURRENT_MAIL_CONFIG: Arc<MailConfig>;
}

pub(crate) fn scope_config<F: std::future::Future>(
    config: Arc<MailConfig>,
    f: F,
) -> impl std::future::Future<Output = F::Output> {
    CURRENT_MAIL_CONFIG.scope(config, f)
}

pub struct Mail;

impl Mail {
    /// Send using the config injected by `MailLayer`. Panics at the type level
    /// (returns `Err(MailError::NotConfigured)`) if called outside a request
    /// that has `MailLayer` in its middleware stack.
    pub async fn send(mailable: impl Mailable, to: &str) -> Result<(), MailError> {
        let config = CURRENT_MAIL_CONFIG
            .try_with(|c| c.clone())
            .map_err(|_| MailError::NotConfigured)?;
        Self::dispatch(&mailable, to, &config).await
    }

    /// Send using an explicitly provided config — usable outside of a request
    /// context (e.g. background jobs, CLI commands).
    pub async fn send_with(
        mailable: impl Mailable,
        to: &str,
        config: &MailConfig,
    ) -> Result<(), MailError> {
        Self::dispatch(&mailable, to, config).await
    }

    async fn dispatch(
        mailable: &dyn Mailable,
        to: &str,
        config: &MailConfig,
    ) -> Result<(), MailError> {
        match config.driver.as_str() {
            "log" => crate::drivers::send_log(mailable, to, config).await,
            #[cfg(feature = "smtp")]
            "smtp" => crate::drivers::send_smtp(mailable, to, config).await,
            #[cfg(feature = "postmark")]
            "postmark" => crate::drivers::send_postmark(mailable, to, config).await,
            #[cfg(feature = "resend")]
            "resend" => crate::drivers::send_resend(mailable, to, config).await,
            d => Err(MailError::UnknownDriver(d.to_string())),
        }
    }
}