diff --git a/src/context.rs b/src/context.rs index c6d9f81bd..360b82d66 100644 --- a/src/context.rs +++ b/src/context.rs @@ -568,11 +568,9 @@ impl Context { self.scheduler.maybe_network().await; } - /// Returns maximum number of recipients a single email can be sent to. - pub(crate) async fn get_max_smtp_rcpt_to(&self) -> Result { - let Some((transport_id, param)) = ConfiguredLoginParam::load(self).await? else { - bail!("Not configured"); - }; + /// Returns maximum number of recipients a single email can be sent to + /// over the transport `transport_id`, which sends from `addr`. + pub(crate) async fn get_max_smtp_rcpt_to(&self, transport_id: u32, addr: &str) -> Result { let metadata_limit = self .metadata .read() @@ -582,9 +580,7 @@ impl Context { if let Some(limit) = metadata_limit { return Ok(limit); } - if let Some(limit) = - crate::provider::legacy_settings_for_addr(¶m.addr)?.max_smtp_rcpt_to - { + if let Some(limit) = crate::provider::legacy_settings_for_addr(addr)?.max_smtp_rcpt_to { return Ok(limit); } Ok(constants::DEFAULT_MAX_SMTP_RCPT_TO) diff --git a/src/context/context_tests.rs b/src/context/context_tests.rs index db5056e4e..fb955c584 100644 --- a/src/context/context_tests.rs +++ b/src/context/context_tests.rs @@ -5,12 +5,35 @@ use tempfile::tempdir; use super::*; use crate::chat::{Chat, MuteDuration, get_chat_contacts, get_chat_msgs, send_msg, set_muted}; use crate::chatlist::Chatlist; -use crate::constants::Chattype; +use crate::constants::{Chattype, DEFAULT_MAX_SMTP_RCPT_TO}; use crate::message::Message; use crate::receive_imf::receive_imf; use crate::test_utils::{E2EE_INFO_MSGS, TestContext, TestContextManager}; use crate::tools::{SystemTime, create_outgoing_rfc724_mid}; +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_get_max_smtp_rcpt_to() -> Result<()> { + let t = TestContext::new().await; + assert_eq!( + t.get_max_smtp_rcpt_to(2, "alice@example.org").await?, + DEFAULT_MAX_SMTP_RCPT_TO + ); + + for (transport_id, limit) in [(1, 3), (2, 7)] { + t.metadata.write().await.insert( + transport_id, + ServerMetadata { + max_smtp_rcpt_to: Some(limit), + ..Default::default() + }, + ); + } + + assert_eq!(t.get_max_smtp_rcpt_to(2, "alice@example.org").await?, 7); + assert_eq!(t.get_max_smtp_rcpt_to(1, "alice@example.org").await?, 3); + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_wrong_db() -> Result<()> { let tmp = tempfile::tempdir()?; diff --git a/src/smtp.rs b/src/smtp.rs index 285d9a841..f2b4f3c40 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -41,6 +41,9 @@ pub(crate) struct Smtp { /// Email address we are sending from. from: Option, + /// Transport we are connected to. + transport_id: Option, + /// Timestamp of last successful send/receive network interaction /// (eg connect or send succeeded). On initialization and disconnect /// it is set to None. @@ -116,7 +119,10 @@ impl Smtp { ) .await { - Ok(()) => return Ok(()), + Ok(()) => { + self.transport_id = Some(transport_id); + return Ok(()); + } Err(err) => { warn!( context, @@ -466,6 +472,12 @@ pub(crate) async fn send_msg_to_smtp( .context("No From address available, likely not connected")? .to_string(); + let transport_id = smtp.transport_id.context("Not connected")?; + let chunk_size = context + .get_max_smtp_rcpt_to(transport_id, &from_addr) + .await? + .max(1); + let rendered_mail = mimefactory::render_queued_mail(queued_mail, &public_key, &secret_key, from_addr)?; let body = rendered_mail.message; @@ -474,8 +486,6 @@ pub(crate) async fn send_msg_to_smtp( context, "Try number {retries} to send message {msg_id} (entry {rowid}) over SMTP." ); - - let chunk_size = context.get_max_smtp_rcpt_to().await?.max(1); let mut unsent = recipients_list.as_slice(); let status = loop { let unsent_len = u32::try_from(unsent.len()).context("Too many SMTP recipients")?; diff --git a/src/transport.rs b/src/transport.rs index b16151f09..8a15db498 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -11,7 +11,7 @@ use std::fmt; use std::sync::atomic::Ordering; -use anyhow::{Context as _, Result, bail, format_err}; +use anyhow::{Context as _, Result, format_err}; use deltachat_contact_tools::{EmailAddress, addr_normalize}; use rusqlite::OptionalExtension; use serde::{Deserialize, Serialize}; @@ -260,34 +260,6 @@ impl fmt::Display for ConfiguredLoginParam { } impl ConfiguredLoginParam { - /// Load configured account settings from the database. - /// - /// Returns transport ID and configured parameters - /// of the transport currently used for sending. - /// Returns `None` if account is not configured. - pub(crate) async fn load(context: &Context) -> Result> { - let Some(self_addr) = context.get_config(Config::ConfiguredAddr).await? else { - return Ok(None); - }; - - let Some((id, json)) = context - .sql - .query_row_optional( - "SELECT id, configured_param FROM transports WHERE addr=?", - (&self_addr,), - |row| { - let id: u32 = row.get(0)?; - let json: String = row.get(1)?; - Ok((id, json)) - }, - ) - .await? - else { - bail!("Self address {self_addr} doesn't have a corresponding transport"); - }; - Ok(Some((id, Self::from_json(&json)?))) - } - /// Loads configured login parameters for all transports. /// /// Returns a vector of all transport IDs diff --git a/src/transport/transport_tests.rs b/src/transport/transport_tests.rs index dc7e97853..a981c40b6 100644 --- a/src/transport/transport_tests.rs +++ b/src/transport/transport_tests.rs @@ -62,7 +62,7 @@ async fn test_save_load_login_param() -> Result<()> { expected_param ); assert_eq!(t.is_configured().await?, true); - let (_transport_id, loaded) = ConfiguredLoginParam::load(&t).await?.unwrap(); + let (_transport_id, loaded) = ConfiguredLoginParam::load_all(&t).await?.remove(0); assert_eq!(param, loaded); let formatted = format!(" {loaded}"); @@ -75,7 +75,7 @@ async fn test_save_load_login_param() -> Result<()> { // Legacy ConfiguredImapCertificateChecks config is ignored t.set_config(Config::ConfiguredImapCertificateChecks, Some("999")) .await?; - assert!(ConfiguredLoginParam::load(&t).await.is_ok()); + assert!(ConfiguredLoginParam::load_all(&t).await.is_ok()); // Test that we don't panic on unknown ConfiguredImapCertificateChecks values. let wrong_param = expected_param.replace("Strict", "Stricct"); @@ -83,7 +83,7 @@ async fn test_save_load_login_param() -> Result<()> { t.sql .execute("UPDATE transports SET configured_param=?", (wrong_param,)) .await?; - assert!(ConfiguredLoginParam::load(&t).await.is_err()); + assert!(ConfiguredLoginParam::load_all(&t).await.is_err()); Ok(()) }