Skip to content

Commit

Permalink
feat(core): Skip catch-all for known domains
Browse files Browse the repository at this point in the history
  • Loading branch information
amaury1093 committed Oct 6, 2023
1 parent 2b63556 commit af2d200
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 14 deletions.
11 changes: 9 additions & 2 deletions core/src/smtp/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use std::time::Duration;

use trust_dns_proto::rr::Name;

use super::parser;
use super::{gmail::is_gmail, outlook::is_outlook, parser, yahoo::is_yahoo};
use super::{SmtpDetails, SmtpError};
use crate::util::{constants::LOG_TARGET, input_output::CheckEmailInput};

Expand Down Expand Up @@ -220,7 +220,14 @@ async fn email_deliverable(
async fn smtp_is_catch_all(
smtp_transport: &mut SmtpTransport,
domain: &str,
host: &Name,
) -> Result<bool, SmtpError> {
// Skip catch-all check for known providers.
let host = host.to_string();
if is_gmail(&host) || is_outlook(&host) || is_yahoo(&host) {
return Ok(false);
}

// Create a random 15-char alphanumerical string.
let mut rng = SmallRng::from_entropy();
let random_email: String = iter::repeat(())
Expand Down Expand Up @@ -249,7 +256,7 @@ async fn create_smtp_future(
// Ok(SmtpDetails { can_connect_smtp: false, ... }).
let mut smtp_transport = connect_to_host(host, port, input).await?;

let is_catch_all = smtp_is_catch_all(&mut smtp_transport, domain)
let is_catch_all = smtp_is_catch_all(&mut smtp_transport, domain, host)
.await
.unwrap_or(false);
let deliverability = if is_catch_all {
Expand Down
4 changes: 2 additions & 2 deletions core/src/smtp/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

use super::gmail::GmailError;
#[cfg(feature = "headless")]
use super::microsoft::hotmail::HotmailError;
use super::microsoft::microsoft365::Microsoft365Error;
use super::outlook::hotmail::HotmailError;
use super::outlook::microsoft365::Microsoft365Error;
use super::parser;
use super::yahoo::YahooError;
use crate::util::ser_with_display::ser_with_display;
Expand Down
5 changes: 5 additions & 0 deletions core/src/smtp/gmail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ pub async fn check_gmail(
})
}

/// Check if the MX host is from Gmail.
pub fn is_gmail(host: &str) -> bool {
host.to_lowercase().ends_with(".google.com.")
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
3 changes: 0 additions & 3 deletions core/src/smtp/microsoft/mod.rs

This file was deleted.

15 changes: 8 additions & 7 deletions core/src/smtp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod connect;
mod error;
mod gmail;
mod http_api;
mod microsoft;
mod outlook;
mod parser;
mod yahoo;

Expand All @@ -32,6 +32,8 @@ use crate::{util::input_output::CheckEmailInput, LOG_TARGET};
use connect::check_smtp_with_retry;
pub use error::*;

use self::{gmail::is_gmail, outlook::is_outlook, yahoo::is_yahoo};

/// Details that we gathered from connecting to this email via SMTP
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct SmtpDetails {
Expand Down Expand Up @@ -68,19 +70,18 @@ pub async fn check_smtp(
)));
}

// FIXME Is this `contains` too lenient?
if input.yahoo_use_api && host_lowercase.contains("yahoo") {
if input.yahoo_use_api && is_yahoo(&host_lowercase) {
return yahoo::check_yahoo(to_email, input)
.await
.map_err(|err| err.into());
}
if input.gmail_use_api && host_lowercase.ends_with(".google.com.") {
if input.gmail_use_api && is_gmail(&host_lowercase) {
return gmail::check_gmail(to_email, input)
.await
.map_err(|err| err.into());
}
if input.microsoft365_use_api && host_lowercase.ends_with(".mail.protection.outlook.com.") {
match microsoft::microsoft365::check_microsoft365_api(to_email, input).await {
if input.microsoft365_use_api && is_outlook(&host_lowercase) {
match outlook::microsoft365::check_microsoft365_api(to_email, input).await {
Ok(Some(smtp_details)) => return Ok(smtp_details),
// Continue in the event of an error/ambiguous result.
Err(err) => {
Expand Down Expand Up @@ -108,7 +109,7 @@ pub async fn check_smtp(
//
// So it seems that outlook/hotmail addresses end with `olc.protection.outlook.com.`
if host_lowercase.ends_with("olc.protection.outlook.com.") {
return microsoft::hotmail::check_password_recovery(to_email, webdriver)
return outlook::hotmail::check_password_recovery(to_email, webdriver)
.await
.map_err(|err| err.into());
}
Expand Down
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions core/src/smtp/outlook/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[cfg(feature = "headless")]
pub mod hotmail;
pub mod microsoft365;

/// Check if a MX host is from outlook.
pub fn is_outlook(host: &str) -> bool {
host.to_lowercase()
.ends_with(".mail.protection.outlook.com.")
}
8 changes: 8 additions & 0 deletions core/src/smtp/yahoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,11 @@ pub async fn check_yahoo(
..Default::default()
})
}

/// Check if the MX host is from Yahoo.
/// Examples:
/// - mta7.am0.yahoodns.net.
/// - mx-eu.mail.am0.yahoodns.net.
pub fn is_yahoo(host: &str) -> bool {
host.to_lowercase().ends_with(".yahoodns.net.")
}

0 comments on commit af2d200

Please sign in to comment.