Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions deltachat-rpc-client/tests/test_multitransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ def test_add_second_address(acf) -> None:


def test_change_address(acf) -> None:
"""Test Alice configuring a second transport and setting it as a primary one."""
"""Test Alice configuring a second transport and removing the first one."""
alice, bob = acf.get_online_accounts(2)

bob_addr = bob.get_config("configured_addr")
bob.create_chat(alice)

alice_chat_bob = alice.create_chat(bob)
Expand All @@ -65,22 +64,14 @@ def test_change_address(acf) -> None:
sender_addr1 = msg1.sender.get_snapshot().address

alice.stop_io()
old_alice_addr = alice.get_config("configured_addr")
old_alice_addr = alice.list_transports()[0]["addr"]
alice_vcard = alice.self_contact.make_vcard()
assert old_alice_addr in alice_vcard
qr = acf.get_account_qr()
alice.add_transport_from_qr(qr)
new_alice_addr = alice.list_transports()[1]["addr"]
with pytest.raises(JsonRpcError):
# Cannot use the address that is not
# configured for any transport.
alice.set_config("configured_addr", bob_addr)

# Load old address so it is cached.
assert alice.get_config("configured_addr") == old_alice_addr
alice.set_config("configured_addr", new_alice_addr)
# Make sure that setting `configured_addr` invalidated the cache.
assert alice.get_config("configured_addr") == new_alice_addr
alice.delete_transport(old_alice_addr)

alice_vcard = alice.self_contact.make_vcard()
assert old_alice_addr not in alice_vcard
Expand Down
21 changes: 7 additions & 14 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ use crate::{constants, stats};
#[strum(serialize_all = "snake_case")]
pub enum Config {
/// Deprecated(2026-04).
/// Use ConfiguredAddr, [`crate::login_param::EnteredLoginParam`],
/// or add_transport{from_qr}()/list_transports() instead.
///
/// Email address, used in the `From:` field.
/// Email address used by the deprecated configure() procedure.
///
/// Use add_transport{from_qr}() to configure new transports,
/// Use list_transports() to learn about configured transports,
/// including their addresses.
Addr,

/// Deprecated(2026-04).
Expand Down Expand Up @@ -195,9 +197,9 @@ pub enum Config {
#[strum(props(default = "0"))]
DeleteDeviceAfter,

/// The address of the transport used for sending.
/// Deprecated(2026-09).
///
/// Device-local, other devices choose their own sending transport.
/// Use ConfiguredLoginParam and list_transports() instead.
ConfiguredAddr,

/// Deprecated(2026-04).
Expand Down Expand Up @@ -487,11 +489,6 @@ impl Config {
| Self::ForceEncryption,
)
}

/// Whether the config option needs an IO scheduler restart to take effect.
pub(crate) fn needs_io_restart(&self) -> bool {
matches!(self, Config::ConfiguredAddr)
}
}

impl Context {
Expand Down Expand Up @@ -670,10 +667,6 @@ impl Context {
pub async fn set_config(&self, key: Config, value: Option<&str>) -> Result<()> {
Self::check_config(key, value)?;

let _pause = match key.needs_io_restart() {
true => self.scheduler.pause(self).await?,
_ => Default::default(),
};
if key == Config::StatsSending {
let old_value = self.get_config(key).await?;
let old_value = bool_from_config(old_value.as_deref());
Expand Down
4 changes: 4 additions & 0 deletions src/ephemeral/ephemeral_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,10 @@ async fn test_ephemeral_msg_offline() -> Result<()> {
check_msg_will_be_deleted(alice, msg.id, &chat, now, now + i64::from(duration) + 1).await?;
assert!(alice.sql.exists(stmt, (msg.id,)).await?);

alice
.assert_warn("No SMTP connection candidates provided")
.await;

Ok(())
}

Expand Down
4 changes: 4 additions & 0 deletions src/message/message_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,10 @@ async fn test_delete_msgs_offline() -> Result<()> {
delete_msgs(alice, &[msg.id]).await?;
assert!(!alice.sql.exists(stmt, (msg.id,)).await?);

alice
.assert_warn("No SMTP connection candidates provided")
.await;

Ok(())
}

Expand Down
41 changes: 29 additions & 12 deletions src/smtp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,36 @@ impl Smtp {
}

self.connectivity.set_connecting(context);
let (_transport_id, lp) = ConfiguredLoginParam::load(context)
.await?
.context("Not configured")?;
let proxy_config = ProxyConfig::load(context).await?;
self.connect(
context,
&lp.smtp,
&lp.smtp_password,
&proxy_config,
&lp.addr,
lp.strict_tls(proxy_config.is_some())?,
)
.await
let transports = ConfiguredLoginParam::load_all(context).await?;

// Try to connect to the newest transport first. If sending is unreliable,
// user can configure a new transport and it will be the one used.
// Conversely, if user just added a new transport and sending got less reliable,
// user can restore old state by removing the just added transport.
for (transport_id, lp) in transports.into_iter().rev() {
info!(context, "Trying to connect to transport {transport_id}.");
match self
.connect(
context,
&lp.smtp,
&lp.smtp_password,
&proxy_config,
&lp.addr,
lp.strict_tls(proxy_config.is_some())?,
)
.await
{
Ok(()) => return Ok(()),
Err(err) => {
warn!(
context,
"Failed to connect to SMTP transport {transport_id}: {err:#}."
);
}
}
}
bail!("Failed to connect to any SMTP server");
}

/// Connect using the provided login params.
Expand Down
Loading