Fallback to plain-text when STARTTLS is optional

This commit is contained in:
mdecimus 2023-08-25 20:05:41 +02:00
parent 5da7e40147
commit 426c073b25
9 changed files with 36 additions and 4 deletions

View file

@ -632,6 +632,7 @@ impl<T: AsyncWrite + AsyncRead + IsTls + Unpin> Session<T> {
expires,
status: queue::Status::Scheduled,
domain: rcpt.domain,
disable_tls: false,
changed: false,
});
}

View file

@ -187,6 +187,7 @@ impl DeliveryAttempt {
};
// Prepare TLS strategy
let mut disable_tls = false;
let mut tls_strategy = TlsStrategy {
mta_sts: *queue_config.tls.mta_sts.eval(&envelope).await,
..Default::default()
@ -668,7 +669,7 @@ impl DeliveryAttempt {
};
// Try starting TLS
if tls_strategy.try_start_tls() {
if tls_strategy.try_start_tls() && !domain.disable_tls {
smtp_client.timeout =
*queue_config.timeout.tls.eval(&envelope).await;
match try_start_tls(
@ -821,18 +822,29 @@ impl DeliveryAttempt {
})
.await;
}
last_status = Status::from_tls_error(envelope.mx, error);
last_status = if tls_strategy.is_tls_required()
|| (self.message.flags & MAIL_REQUIRETLS) != 0
|| mta_sts_policy.is_some()
|| dane_policy.is_some()
{
Status::from_tls_error(envelope.mx, error)
} else {
disable_tls = true;
Status::from_tls_error(envelope.mx, error)
.into_temporary()
};
continue 'next_host;
}
}
} else {
// TLS has been disabled in the configuration file
// TLS has been disabled
tracing::info!(
parent: &span,
context = "tls",
event = "disabled",
mx = envelope.mx,
reason = "TLS is disabled for this host",
reason = if domain.disable_tls {"TLS is disabled for this host"} else {"TLS is unavailable for this host, falling back to plain-text."},
);
self.message
@ -893,6 +905,7 @@ impl DeliveryAttempt {
};
// Update status for the current domain and continue with the next one
domain.disable_tls = disable_tls;
domain
.set_status(delivery_result, queue_config.retry.eval(&envelope).await);
continue 'next_domain;

View file

@ -525,6 +525,17 @@ impl<T, E> Status<T, E> {
}
}
pub fn into_temporary(self) -> Self {
match self {
Status::PermanentFailure(err) => Status::TemporaryFailure(err),
other => other,
}
}
pub fn is_permanent(&self) -> bool {
matches!(self, Status::PermanentFailure(_))
}
fn write_dsn_action(&self, dsn: &mut String) {
dsn.push_str("Action: ");
dsn.push_str(match self {

View file

@ -102,6 +102,7 @@ pub struct Domain {
pub notify: Schedule<u32>,
pub expires: Instant,
pub status: Status<(), Error>,
pub disable_tls: bool,
pub changed: bool,
}

View file

@ -211,6 +211,7 @@ impl Message {
retry: Schedule::now(),
notify: Schedule::now(),
status: Status::Scheduled,
disable_tls: false,
changed: false,
});
}

View file

@ -215,6 +215,7 @@ impl Message {
notify: Schedule::later(expires + Duration::from_secs(10)),
expires: Instant::now() + expires,
status: Status::Scheduled,
disable_tls: false,
changed: false,
});
idx

View file

@ -91,6 +91,7 @@ async fn generate_dsn() {
entity: "mx.domain.org".to_string(),
details: "Connection timeout".to_string(),
})),
disable_tls: false,
changed: false,
}],
flags: 0,

View file

@ -152,6 +152,7 @@ fn domain(domain: &str, retry: u64, notify: u64, expires: u64) -> Domain {
notify: Schedule::later(Duration::from_secs(notify)),
expires: Instant::now() + Duration::from_secs(expires),
status: Status::Scheduled,
disable_tls: false,
changed: false,
}
}

View file

@ -79,6 +79,7 @@ async fn queue_serialize() {
notify: Schedule::now(),
expires: Instant::now() + Duration::from_secs(10),
status: Status::Scheduled,
disable_tls: false,
changed: false,
},
Domain {
@ -87,6 +88,7 @@ async fn queue_serialize() {
notify: Schedule::now(),
expires: Instant::now() + Duration::from_secs(10),
status: Status::Scheduled,
disable_tls: false,
changed: false,
},
],