Skip to main content

lychee_lib/checker/
mail.rs

1use crate::{Status, Uri};
2use std::time::Duration;
3
4#[cfg(feature = "email-check")]
5use mailify_lib::{Client, Config};
6
7/// A utility for checking the validity of email addresses.
8///
9/// `EmailChecker` is responsible for validating email addresses,
10/// optionally performing reachability checks when the appropriate
11/// features are enabled.
12#[derive(Debug, Clone)]
13pub(crate) struct MailChecker {
14    #[cfg(feature = "email-check")]
15    client: Client,
16}
17
18#[cfg(not(feature = "email-check"))]
19impl MailChecker {
20    /// Creates a new `EmailChecker`.
21    pub(crate) const fn new(_timeout: Option<Duration>) -> Self {
22        Self {}
23    }
24
25    /// Ignore the mail check if the `email-check` feature is not enabled.
26    #[allow(
27        clippy::unused_async,
28        reason = "Match the signature of the function with the email-check feature"
29    )]
30    pub(crate) async fn check_mail(&self, _uri: &Uri) -> Status {
31        Status::Excluded
32    }
33}
34
35#[cfg(feature = "email-check")]
36impl MailChecker {
37    /// Creates a new `EmailChecker`.
38    pub(crate) fn new(timeout: Option<Duration>) -> Self {
39        Self {
40            client: Client::new(Config {
41                timeout,
42                ..Default::default()
43            }),
44        }
45    }
46
47    /// Check a mail address, or equivalently a `mailto` URI.
48    ///
49    /// URIs may contain query parameters (e.g. `contact@example.com?subject="Hello"`),
50    /// which are ignored by this check. They are not part of the mail address
51    /// and instead passed to a mail client.
52    pub(crate) async fn check_mail(&self, uri: &Uri) -> Status {
53        self.perform_email_check(uri).await
54    }
55
56    async fn perform_email_check(&self, uri: &Uri) -> Status {
57        use crate::ErrorKind;
58        use http::StatusCode;
59        use mailify_lib::CheckResult;
60
61        let address = uri.url.path().to_string();
62        let result = self.client.check(&address).await;
63
64        match result {
65            CheckResult::Success => Status::Ok(StatusCode::OK),
66            CheckResult::Uncertain(reason) => Status::UnknownMailStatus(reason.to_string()),
67            CheckResult::Failure(reason) => {
68                ErrorKind::UnreachableEmailAddress(uri.clone(), reason.to_string()).into()
69            }
70        }
71    }
72}