fix: do not require the Message to render MDN

This commit is contained in:
link2xt
2024-06-21 12:23:13 +00:00
parent 92e8b80da8
commit a82eb7def6
10 changed files with 266 additions and 247 deletions

View File

@@ -361,7 +361,7 @@ pub(crate) async fn smtp_send(
recipients: &[async_smtp::EmailAddress],
message: &str,
smtp: &mut Smtp,
msg_id: MsgId,
msg_id: Option<MsgId>,
) -> SendResult {
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
info!(context, "SMTP-sending out mime message:\n{message}");
@@ -489,19 +489,22 @@ pub(crate) async fn smtp_send(
};
if let SendResult::Failure(err) = &status {
// We couldn't send the message, so mark it as failed
match Message::load_from_db(context, msg_id).await {
Ok(mut msg) => {
if let Err(err) = message::set_msg_failed(context, &mut msg, &err.to_string()).await
{
error!(context, "Failed to mark {msg_id} as failed: {err:#}.");
if let Some(msg_id) = msg_id {
// We couldn't send the message, so mark it as failed
match Message::load_from_db(context, msg_id).await {
Ok(mut msg) => {
if let Err(err) =
message::set_msg_failed(context, &mut msg, &err.to_string()).await
{
error!(context, "Failed to mark {msg_id} as failed: {err:#}.");
}
}
Err(err) => {
error!(
context,
"Failed to load {msg_id} to mark it as failed: {err:#}."
);
}
}
Err(err) => {
error!(
context,
"Failed to load {msg_id} to mark it as failed: {err:#}."
);
}
}
}
@@ -577,7 +580,7 @@ pub(crate) async fn send_msg_to_smtp(
)
.collect::<Vec<_>>();
let status = smtp_send(context, &recipients_list, body.as_str(), smtp, msg_id).await;
let status = smtp_send(context, &recipients_list, body.as_str(), smtp, Some(msg_id)).await;
match status {
SendResult::Retry => {}
@@ -706,7 +709,7 @@ pub(crate) async fn send_smtp_messages(context: &Context, connection: &mut Smtp)
Ok(())
}
/// Tries to send MDN for message `msg_id` to `contact_id`.
/// Tries to send MDN for message identified by `rfc724_mdn` to `contact_id`.
///
/// Attempts to aggregate additional MDNs for `contact_id` into sent MDN.
///
@@ -715,9 +718,9 @@ pub(crate) async fn send_smtp_messages(context: &Context, connection: &mut Smtp)
/// points to non-existent message or contact.
///
/// Returns true on success, false on temporary error.
async fn send_mdn_msg_id(
async fn send_mdn_rfc724_mid(
context: &Context,
msg_id: MsgId,
rfc724_mid: &str,
contact_id: ContactId,
smtp: &mut Smtp,
) -> Result<bool> {
@@ -727,26 +730,30 @@ async fn send_mdn_msg_id(
}
// Try to aggregate additional MDNs into this MDN.
let (additional_msg_ids, additional_rfc724_mids): (Vec<MsgId>, Vec<String>) = context
let additional_rfc724_mids: Vec<String> = context
.sql
.query_map(
"SELECT msg_id, rfc724_mid
"SELECT rfc724_mid
FROM smtp_mdns
WHERE from_id=? AND msg_id!=?",
(contact_id, msg_id),
WHERE from_id=? AND rfc724_mid!=?",
(contact_id, &rfc724_mid),
|row| {
let msg_id: MsgId = row.get(0)?;
let rfc724_mid: String = row.get(1)?;
Ok((msg_id, rfc724_mid))
let rfc724_mid: String = row.get(0)?;
Ok(rfc724_mid)
},
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
)
.await?
.into_iter()
.unzip();
.collect();
let msg = Message::load_from_db(context, msg_id).await?;
let mimefactory = MimeFactory::from_mdn(context, &msg, additional_rfc724_mids).await?;
let mimefactory = MimeFactory::from_mdn(
context,
contact_id,
rfc724_mid.to_string(),
additional_rfc724_mids.clone(),
)
.await?;
let rendered_msg = mimefactory.render(context).await?;
let body = rendered_msg.message;
@@ -755,21 +762,21 @@ async fn send_mdn_msg_id(
.map_err(|err| format_err!("invalid recipient: {} {:?}", addr, err))?;
let recipients = vec![recipient];
match smtp_send(context, &recipients, &body, smtp, msg_id).await {
match smtp_send(context, &recipients, &body, smtp, None).await {
SendResult::Success => {
info!(context, "Successfully sent MDN for {msg_id}.");
info!(context, "Successfully sent MDN for {rfc724_mid}.");
context
.sql
.execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,))
.execute("DELETE FROM smtp_mdns WHERE rfc724_mid = ?", (rfc724_mid,))
.await?;
if !additional_msg_ids.is_empty() {
if !additional_rfc724_mids.is_empty() {
let q = format!(
"DELETE FROM smtp_mdns WHERE msg_id IN({})",
sql::repeat_vars(additional_msg_ids.len())
"DELETE FROM smtp_mdns WHERE rfc724_mid IN({})",
sql::repeat_vars(additional_rfc724_mids.len())
);
context
.sql
.execute(&q, rusqlite::params_from_iter(additional_msg_ids))
.execute(&q, rusqlite::params_from_iter(additional_rfc724_mids))
.await?;
}
Ok(true)
@@ -777,7 +784,7 @@ async fn send_mdn_msg_id(
SendResult::Retry => {
info!(
context,
"Temporary SMTP failure while sending an MDN for {msg_id}."
"Temporary SMTP failure while sending an MDN for {rfc724_mid}."
);
Ok(false)
}
@@ -802,40 +809,40 @@ async fn send_mdn(context: &Context, smtp: &mut Smtp) -> Result<bool> {
let Some(msg_row) = context
.sql
.query_row_optional(
"SELECT msg_id, from_id FROM smtp_mdns ORDER BY retries LIMIT 1",
"SELECT rfc724_mid, from_id FROM smtp_mdns ORDER BY retries LIMIT 1",
[],
|row| {
let msg_id: MsgId = row.get(0)?;
let rfc724_mid: String = row.get(0)?;
let from_id: ContactId = row.get(1)?;
Ok((msg_id, from_id))
Ok((rfc724_mid, from_id))
},
)
.await?
else {
return Ok(false);
};
let (msg_id, contact_id) = msg_row;
let (rfc724_mid, contact_id) = msg_row;
context
.sql
.execute(
"UPDATE smtp_mdns SET retries=retries+1 WHERE msg_id=?",
(msg_id,),
"UPDATE smtp_mdns SET retries=retries+1 WHERE rfc724_mid=?",
(rfc724_mid.clone(),),
)
.await
.context("Failed to update MDN retries count")?;
match send_mdn_msg_id(context, msg_id, contact_id, smtp).await {
match send_mdn_rfc724_mid(context, &rfc724_mid, contact_id, smtp).await {
Err(err) => {
// If there is an error, for example there is no message corresponding to the msg_id in the
// database, do not try to send this MDN again.
warn!(
context,
"Error sending MDN for {msg_id}, removing it: {err:#}."
"Error sending MDN for {rfc724_mid}, removing it: {err:#}."
);
context
.sql
.execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,))
.execute("DELETE FROM smtp_mdns WHERE rfc724_mid = ?", (rfc724_mid,))
.await?;
Err(err)
}