mirror of
https://github.com/chatmail/core.git
synced 2026-09-22 13:01:21 +03:00
fix: use max_smtp_rcpt_to chunking for the actual transport we are sending from
removes another `ConfiguredAddr` usage and a bug that the wrong max smtp recipients setting was used.
This commit is contained in:
@@ -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<u32> {
|
||||
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<u32> {
|
||||
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)
|
||||
|
||||
@@ -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()?;
|
||||
|
||||
16
src/smtp.rs
16
src/smtp.rs
@@ -41,6 +41,9 @@ pub(crate) struct Smtp {
|
||||
/// Email address we are sending from.
|
||||
from: Option<EmailAddress>,
|
||||
|
||||
/// Transport we are connected to.
|
||||
transport_id: Option<u32>,
|
||||
|
||||
/// 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")?;
|
||||
|
||||
@@ -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<Option<(u32, Self)>> {
|
||||
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
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user