mail-list 0.2.6-alpha

Email subscriptions list library. Unicast, narrowcast and broadcast lists
Documentation
use lettre::AsyncSmtpTransport;
use percent_encoding::percent_decode_str;

use crate::{MailListError, MailListResult, Smtps};

#[derive(Debug)]
pub struct SmtpsBuilder;

impl SmtpsBuilder {
    pub fn parse(smtps_uri: &str) -> MailListResult<Smtps> {
        use url::Url;

        let url =
            Url::parse(smtps_uri).or(Err(MailListError::Smtps("Invalid smtps URI".to_string())))?;

        if url.scheme() != "smtps" {
            return Err(MailListError::Smtps("Invalid SMTPs scheme".to_string()));
        };
        let domain = url
            .host_str()
            .ok_or(MailListError::Smtps(
                "Domain not found in SMTPs".to_string(),
            ))?
            .to_string();
        let domain = percent_decode_str(&domain)
            .decode_utf8()
            .or(Err(MailListError::Smtps(
                "Domain is not valid UTF-8".to_string(),
            )))?
            .to_string();

        let ehlo_name = url.path().trim_start_matches('/');
        let ehlo_name = percent_decode_str(ehlo_name)
            .decode_utf8()
            .or(Err(MailListError::Smtps(
                "EHLO name is not valid UTF-8".to_string(),
            )))?
            .to_string();
        let ehlo_name: Option<std::borrow::Cow<'_, str>> = if ehlo_name.is_empty() {
            None
        } else {
            Some(std::borrow::Cow::Owned(ehlo_name))
        };

        #[cfg(feature = "tokio-runtime")]
        let transport = AsyncSmtpTransport::<lettre::Tokio1Executor>::from_url(smtps_uri)
            .map_err(|error| MailListError::Mailer(error.to_string()))?;

        let mailer = if let Some(hello_name) = ehlo_name.as_ref() {
            transport.hello_name(lettre::transport::smtp::extension::ClientId::Domain(
                hello_name.to_string(),
            ))
        } else {
            transport
        };

        let mailer = mailer.build();

        let outcome = Smtps {
            domain: domain.into(),
            ehlo_name,
            mailer,
        };

        Ok(outcome)
    }
}

#[cfg(test)]
mod sanity_checks {
    use crate::SmtpsBuilder;

    #[test]
    fn smtps_builder() {
        let smtps_uri = "smtps://support@example.com:password@smtp.example.com:465/foo.example.com";

        SmtpsBuilder::parse(smtps_uri).unwrap();
    }
}