diff --git a/deltachat-rpc-client/tests/test_multitransport.py b/deltachat-rpc-client/tests/test_multitransport.py index b37c40e41..8c2372c6e 100644 --- a/deltachat-rpc-client/tests/test_multitransport.py +++ b/deltachat-rpc-client/tests/test_multitransport.py @@ -389,3 +389,14 @@ def test_background_fetch_no_duplicates(acf, direct_imap, dc): dc.background_fetch(300) assert len(messages_with_text(alice_chat, "hello")) == 1 + + +def test_multitransport_mdn(acf): + """Test sending an MDN right after configuring two transports.""" + alice, bob = acf.get_online_accounts(2) + alice.add_transport_from_qr(acf.get_account_qr()) + alice.bring_online() + alice.create_chat(bob) + bob_msg = bob.create_chat(alice).send_text("Hello!") + alice.wait_for_incoming_msg().mark_seen() + assert bob.wait_for_event(EventType.MSG_READ).msg_id == bob_msg.id diff --git a/src/mimefactory.rs b/src/mimefactory.rs index ae79fc908..82f9823fa 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -447,6 +447,7 @@ pub(crate) fn render_queued_mail( } /// Renders queued mail with the current sending address. +#[cfg(test)] pub(crate) async fn render_queued_mail_with_context( queued_mail: QueuedMail, context: &Context, @@ -1319,13 +1320,16 @@ impl MimeFactory { /// /// Used for MDNs because they are fully rendered and sent in one go, /// rather than first creating a [`QueuedMail`] and sending it later. - pub async fn render(self, context: &Context) -> Result { + pub async fn render(self, context: &Context, from_addr: &str) -> Result { // Does not matter, we are not going to return the QueuedMail. let bcc_self = false; + let public_key = key::load_self_public_key(context).await?; + let secret_key = key::load_self_secret_key(context).await?; let (queued_mail, _side_effects) = Box::pin(self.into_queued_mail(context, bcc_self)).await?; - let rendered_mail = render_queued_mail_with_context(queued_mail, context).await?; + let rendered_mail = + render_queued_mail(queued_mail, &public_key, &secret_key, from_addr.to_string())?; Ok(rendered_mail) } diff --git a/src/mimefactory/mimefactory_tests.rs b/src/mimefactory/mimefactory_tests.rs index 70a7b4415..3e1b58469 100644 --- a/src/mimefactory/mimefactory_tests.rs +++ b/src/mimefactory/mimefactory_tests.rs @@ -307,7 +307,8 @@ async fn test_mdn_create_encrypted() -> Result<()> { let mimefactory = MimeFactory::from_mdn(&bob, rcvd.from_id, rcvd.rfc724_mid.clone(), vec![]).await?; assert!(!mimefactory.will_be_encrypted()); - let rendered_msg = mimefactory.render(&bob).await?; + let bob_addr = bob.get_primary_self_addr().await?; + let rendered_msg = mimefactory.render(&bob, &bob_addr).await?; assert!(!rendered_msg.message.contains("Bob Examplenet")); assert!(!rendered_msg.message.contains("Alice Exampleorg")); @@ -320,7 +321,8 @@ async fn test_mdn_create_encrypted() -> Result<()> { let mimefactory = MimeFactory::from_mdn(&bob, rcvd.from_id, rcvd.rfc724_mid, vec![]).await?; assert!(mimefactory.will_be_encrypted()); - let rendered_msg = mimefactory.render(&bob).await?; + let bob_addr = bob.get_primary_self_addr().await?; + let rendered_msg = mimefactory.render(&bob, &bob_addr).await?; assert!(!rendered_msg.message.contains("Bob Examplenet")); assert!(!rendered_msg.message.contains("Alice Exampleorg")); @@ -363,7 +365,8 @@ async fn test_mdn_autocrypt_throttle() -> Result<()> { rcvd: &Message, ) -> Result { let mf = MimeFactory::from_mdn(bob, rcvd.from_id, rcvd.rfc724_mid.clone(), vec![]).await?; - let rendered_msg = mf.render(bob).await?; + let addr = bob.get_primary_self_addr().await?; + let rendered_msg = mf.render(bob, &addr).await?; let mime = MimeMessage::from_bytes(alice, rendered_msg.message.as_bytes()).await?; Ok(mime.autocrypt_fingerprint.is_some()) } @@ -644,7 +647,8 @@ async fn test_render_reply() { let recipients = mimefactory.recipients(); assert_eq!(recipients, vec!["charlie@example.net"]); - let rendered_msg = mimefactory.render(t).await.unwrap(); + let addr = t.get_primary_self_addr().await.unwrap(); + let rendered_msg = mimefactory.render(t, &addr).await.unwrap(); let mail = mailparse::parse_mail(rendered_msg.message.as_bytes()).unwrap(); assert_eq!( diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index 5f7eaa32e..a711f7974 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -2733,7 +2733,8 @@ async fn test_read_receipts_dont_create_chats() -> Result<()> { vec![], ) .await?; - let rendered_mdn = mdn_mimefactory.render(&bob).await?; + let bob_addr = bob.get_primary_self_addr().await?; + let rendered_mdn = mdn_mimefactory.render(&bob, &bob_addr).await?; let mdn_body = rendered_mdn.message; // Alice receives the read receipt. @@ -2768,7 +2769,8 @@ async fn test_read_receipts_dont_unmark_bots() -> Result<()> { vec![], ) .await?; - let rendered_mdn = mdn_mimefactory.render(bob).await?; + let bob_addr = bob.get_primary_self_addr().await?; + let rendered_mdn = mdn_mimefactory.render(bob, &bob_addr).await?; let mdn_body = rendered_mdn.message; // Alice receives the read receipt. diff --git a/src/smtp.rs b/src/smtp.rs index f2b4f3c40..23c68e9bd 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -218,15 +218,6 @@ pub(crate) async fn smtp_send( smtp.connectivity.set_working(context); - if let Err(err) = smtp - .connect_configured(context) - .await - .context("Failed to open SMTP connection") - { - smtp.last_send_error = Some(format!("{err:#}")); - return SendResult::Retry; - } - let send_result = smtp.send(context, recipients, message.as_bytes()).await; smtp.last_send_error = send_result.as_ref().err().map(|e| e.to_string()); @@ -703,7 +694,12 @@ async fn send_mdn_rfc724_mid( } else { mimefactory.recipients() }; - let rendered_msg = Box::pin(mimefactory.render(context)).await?; + let from = smtp + .from + .as_ref() + .context("No From address, not connected")? + .to_string(); + let rendered_msg = Box::pin(mimefactory.render(context, &from)).await?; let body = rendered_msg.message; if context.get_config_bool(Config::BccSelf).await? { @@ -772,6 +768,19 @@ async fn send_mdn(context: &Context, smtp: &mut Smtp) -> Result { }; let (rfc724_mid, contact_id) = msg_row; + // Connect SMTP after checking that we have an MDN to send, + // but before increasing MDN retry counter. + // If we don't have an MDN, no need to connect. + // If we are offline and cannot connect, it is not a failure of an MDN. + if let Err(err) = smtp + .connect_configured(context) + .await + .context("SMTP connection failure while preparing to send MDNs") + { + smtp.last_send_error = Some(format!("{err:#}")); + return Err(err); + } + context .sql .execute(