smtp: retry immediately if connection is stale

This commit is contained in:
link2xt
2022-01-22 11:56:36 +00:00
parent 05a3c0c89b
commit f7f899f0a4
4 changed files with 52 additions and 9 deletions

View File

@@ -48,6 +48,7 @@
- allow removing quotes on existing drafts (#2950) - allow removing quotes on existing drafts (#2950)
- update provider database (11 Jan 2022) #2959 - update provider database (11 Jan 2022) #2959
- python: allow timeout for internal configure tracker API #2967 - python: allow timeout for internal configure tracker API #2967
- Replace `SendMsgToSmtp` jobs which stored outgoing messages in blobdir with `smtp` SQL table #2939 #2966
### Fixed ### Fixed
- Fix: Make `add_parts()` not early-exit #2879 - Fix: Make `add_parts()` not early-exit #2879

View File

@@ -318,7 +318,7 @@ impl Job {
return Status::RetryLater; return Status::RetryLater;
} }
let status = smtp_send(context, recipients, body, smtp, msg_id, 0).await; let status = smtp_send(context, &recipients, &body, smtp, msg_id, 0).await;
if matches!(status, Status::Finished(Ok(_))) { if matches!(status, Status::Finished(Ok(_))) {
// Remove additional SendMdn jobs we have aggregated into this one. // Remove additional SendMdn jobs we have aggregated into this one.
job_try!(kill_ids(context, &additional_job_ids).await); job_try!(kill_ids(context, &additional_job_ids).await);

View File

@@ -225,10 +225,16 @@ impl Smtp {
} }
} }
/// Tries to send a message.
///
/// Returns Status::Finished if sending the message should not be retried anymore,
/// Status::RetryLater if sending should be postponed and Status::RetryNow if it is suspected that
/// temporary failure is caused by stale connection, in which case a second attempt to send the
/// same message may be done immediately.
pub(crate) async fn smtp_send( pub(crate) async fn smtp_send(
context: &Context, context: &Context,
recipients: Vec<async_smtp::EmailAddress>, recipients: &[async_smtp::EmailAddress],
message: String, message: &str,
smtp: &mut Smtp, smtp: &mut Smtp,
msg_id: MsgId, msg_id: MsgId,
rowid: i64, rowid: i64,
@@ -241,7 +247,7 @@ pub(crate) async fn smtp_send(
smtp.connectivity.set_working(context).await; smtp.connectivity.set_working(context).await;
let send_result = smtp let send_result = smtp
.send(context, recipients, message.into_bytes(), rowid) .send(context, recipients, message.as_bytes(), rowid)
.await; .await;
smtp.last_send_error = send_result.as_ref().err().map(|e| e.to_string()); smtp.last_send_error = send_result.as_ref().err().map(|e| e.to_string());
@@ -362,7 +368,7 @@ pub(crate) async fn send_msg_to_smtp(
.await .await
.context("SMTP connection failure") .context("SMTP connection failure")
{ {
smtp.last_send_error = Some(format!("SMTP connection failure: {:#}", err)); smtp.last_send_error = Some(format!("{:#}", err));
return Err(err); return Err(err);
} }
@@ -392,7 +398,43 @@ pub(crate) async fn send_msg_to_smtp(
) )
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let status = smtp_send(context, recipients_list, body, smtp, msg_id, rowid).await; let status = match smtp_send(
context,
&recipients_list,
body.as_str(),
smtp,
msg_id,
rowid,
)
.await
{
Status::RetryNow => {
// Do a single retry immediately without increasing retry counter in case of stale
// connection.
info!(context, "Doing immediate retry to send message.");
// smtp_send just closed stale SMTP connection, reconnect and try again.
if let Err(err) = smtp
.connect_configured(context)
.await
.context("failed to reopen stale SMTP connection")
{
smtp.last_send_error = Some(format!("{:#}", err));
return Err(err);
}
smtp_send(
context,
&recipients_list,
body.as_str(),
smtp,
msg_id,
rowid,
)
.await
}
status => status,
};
match status { match status {
Status::Finished(res) => { Status::Finished(res) => {
if res.is_ok() { if res.is_ok() {

View File

@@ -28,8 +28,8 @@ impl Smtp {
pub async fn send( pub async fn send(
&mut self, &mut self,
context: &Context, context: &Context,
recipients: Vec<EmailAddress>, recipients: &[EmailAddress],
message: Vec<u8>, message: &[u8],
rowid: i64, rowid: i64,
) -> Result<()> { ) -> Result<()> {
let message_len_bytes = message.len(); let message_len_bytes = message.len();
@@ -53,7 +53,7 @@ impl Smtp {
let mail = SendableEmail::new( let mail = SendableEmail::new(
envelope, envelope,
rowid.to_string(), // only used for internal logging rowid.to_string(), // only used for internal logging
&message, message,
); );
if let Some(ref mut transport) = self.transport { if let Some(ref mut transport) = self.transport {