mod common;
use common::{read_line, spawn_mock_server, writeln_crlf, LogCapture};
use smtp_test_tool::outlook_defaults;
use smtp_test_tool::smtp::{self, AuthMech};
use smtp_test_tool::tls::Security;
fn profile_for(addr: std::net::SocketAddr) -> smtp_test_tool::Profile {
let mut p = outlook_defaults();
p.smtp_host = addr.ip().to_string();
p.smtp_port = addr.port();
p.smtp_security = Security::None;
p.imap_enabled = false;
p.pop_enabled = false;
p.user = Some("ops@example.invalid".into());
p.password = Some("hunter2".into());
p.send_test = false;
p.auth_mech = AuthMech::Login;
p.timeout_secs = 3;
p
}
#[test]
fn smtp_auth_failure_5_7_139_triggers_basic_auth_hint() {
let server = spawn_mock_server(|mut r, mut w| {
writeln_crlf(&mut w, "220 mock.example.invalid ESMTP ready");
let _ehlo = read_line(&mut r);
writeln_crlf(&mut w, "250-mock.example.invalid Hello [127.0.0.1]");
writeln_crlf(&mut w, "250-SIZE 157286400");
writeln_crlf(&mut w, "250-AUTH LOGIN PLAIN");
writeln_crlf(&mut w, "250 OK");
let _auth = read_line(&mut r);
writeln_crlf(&mut w, "334 VXNlcm5hbWU6");
let _user = read_line(&mut r);
writeln_crlf(&mut w, "334 UGFzc3dvcmQ6");
let _pass = read_line(&mut r);
writeln_crlf(
&mut w,
"535 5.7.139 Authentication unsuccessful, basic authentication is disabled",
);
let _quit = read_line(&mut r);
writeln_crlf(&mut w, "221 Bye");
});
let logs = LogCapture::install();
let profile = profile_for(server.addr);
let outcome = smtp::run(&profile);
drop(server);
assert!(
matches!(outcome, Ok(false)),
"expected Ok(false) on auth rejection, got {outcome:?}"
);
assert!(
logs.contains("5.7.139"),
"expected the captured log to mention ESC 5.7.139; got lines:\n {}",
logs.lines().join("\n ")
);
assert!(
logs.contains("Conditional Access"),
"expected the 5.7.139 'Conditional Access' hint in the log; got lines:\n {}",
logs.lines().join("\n ")
);
}
#[test]
fn smtp_send_as_denied_5_7_60_surfaces_hint() {
let server = spawn_mock_server(|mut r, mut w| {
writeln_crlf(&mut w, "220 mock.example.invalid ESMTP ready");
let _ehlo = read_line(&mut r);
writeln_crlf(&mut w, "250-mock.example.invalid Hello [127.0.0.1]");
writeln_crlf(&mut w, "250-AUTH LOGIN PLAIN");
writeln_crlf(&mut w, "250 OK");
let _auth = read_line(&mut r);
writeln_crlf(&mut w, "334 VXNlcm5hbWU6");
let _user = read_line(&mut r);
writeln_crlf(&mut w, "334 UGFzc3dvcmQ6");
let _pass = read_line(&mut r);
writeln_crlf(
&mut w,
"550 5.7.60 SMTP; Client does not have permissions to send as this sender",
);
let _quit = read_line(&mut r);
writeln_crlf(&mut w, "221 Bye");
});
let logs = LogCapture::install();
let profile = profile_for(server.addr);
let outcome = smtp::run(&profile);
drop(server);
assert!(matches!(outcome, Ok(false)));
assert!(
logs.contains("5.7.60"),
"expected ESC 5.7.60 in log; got:\n {}",
logs.lines().join("\n ")
);
assert!(
logs.contains("Send As"),
"expected the SendAs hint to mention 'Send As'; got:\n {}",
logs.lines().join("\n ")
);
}
#[test]
fn smtp_dns_failure_is_logged_not_panicked() {
let logs = LogCapture::install();
let mut profile = outlook_defaults();
profile.smtp_host = "127.0.0.1".into();
profile.smtp_port = 1; profile.smtp_security = Security::None;
profile.user = Some("x@example.invalid".into());
profile.password = Some("y".into());
profile.send_test = false;
profile.timeout_secs = 2;
profile.imap_enabled = false;
profile.pop_enabled = false;
let outcome = smtp::run(&profile);
assert!(outcome.is_ok() || outcome.is_err(), "must not panic");
assert!(
!logs.lines().is_empty(),
"expected at least one log line about the connection attempt"
);
}