1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
extern crate lettre;
#[macro_use]
extern crate log;
extern crate mailchecker;
extern crate native_tls;
extern crate rand;
extern crate serde;
extern crate trust_dns_resolver;
mod mx;
mod smtp;
mod syntax;
mod util;
use futures::future::select_ok;
use lettre::{smtp::SMTP_PORT, EmailAddress};
use mx::{get_mx_lookup, MxDetails, MxError};
use serde::{ser::SerializeMap, Serialize, Serializer};
use smtp::{SmtpDetails, SmtpError};
use std::str::FromStr;
use syntax::{address_syntax, SyntaxDetails, SyntaxError};
#[derive(Debug)]
pub struct SingleEmail {
pub mx: Result<MxDetails, MxError>,
pub smtp: Result<SmtpDetails, SmtpError>,
pub syntax: Result<SyntaxDetails, SyntaxError>,
}
impl Serialize for SingleEmail {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct MyError<E> {
error: E,
}
let mut map = serializer.serialize_map(Some(1))?;
match &self.mx {
Ok(t) => map.serialize_entry("mx", &t)?,
Err(error) => map.serialize_entry("mx", &MyError { error })?,
}
match &self.smtp {
Ok(t) => map.serialize_entry("smtp", &t)?,
Err(error) => map.serialize_entry("smtp", &MyError { error })?,
}
match &self.syntax {
Ok(t) => map.serialize_entry("syntax", &t)?,
Err(error) => map.serialize_entry("syntax", &MyError { error })?,
}
map.end()
}
}
pub async fn email_exists(to_email: &str, from_email: &str) -> SingleEmail {
let from_email = EmailAddress::from_str(from_email).unwrap_or_else(|_| {
EmailAddress::from_str("user@example.org").expect("This is a valid email. qed.")
});
debug!("Checking email '{}'", to_email);
let my_syntax = match address_syntax(to_email) {
Ok(s) => s,
e => {
return SingleEmail {
mx: Err(MxError::Skipped),
smtp: Err(SmtpError::Skipped),
syntax: e,
}
}
};
debug!("Details of the email address: {:?}", my_syntax);
debug!("Getting MX lookup...");
let my_mx = match get_mx_lookup(&my_syntax) {
Ok(m) => m,
e => {
return SingleEmail {
mx: e,
smtp: Err(SmtpError::Skipped),
syntax: Ok(my_syntax),
}
}
};
debug!("Found the following MX hosts {:?}", my_mx);
let futures = my_mx
.lookup
.iter()
.map(|host| {
let fut = smtp::smtp_details(
&from_email,
&my_syntax.address,
host.exchange(),
SMTP_PORT,
my_syntax.domain.as_str(),
);
Box::pin(fut)
})
.collect::<Vec<_>>();
let my_smtp = match select_ok(futures).await {
Ok((details, _)) => Ok(details),
Err(err) => Err(err),
};
SingleEmail {
mx: Ok(my_mx),
smtp: my_smtp,
syntax: Ok(my_syntax),
}
}