fix!: Download outgoing messages only from Sentbox and if SentboxWatch is set (#7169)

Download outgoing messages only from Inbox and Mvbox (and Sent -- until `Config::SentboxWatch` is
dropped) to ensure they are sorted correctly with incoming messages. This way we actually do
server-side sorting. Otherwise it's possible that outgoing replies from other devices appear before
incoming messages. Users should CC/BCC/To themselves to see sent messages in Delta Chat.
This commit is contained in:
iequidoo
2025-09-04 06:32:37 -03:00
parent e14265ec5d
commit d957600df7
6 changed files with 48 additions and 12 deletions

View File

@@ -846,6 +846,7 @@ def test_dont_show_emails(acfactory, lp):
ac1.direct_imap.create_folder("Sent")
ac1.direct_imap.create_folder("Spam")
ac1.direct_imap.create_folder("Junk")
ac1.set_config("sentbox_watch", "1")
acfactory.bring_accounts_online()
ac1.stop_io()
@@ -955,7 +956,10 @@ def test_dont_show_emails(acfactory, lp):
msg = ac1._evtracker.wait_next_messages_changed()
# Wait until each folder was scanned, this is necessary for this test to test what it should test:
# Wait until each folder was scanned, this is necessary for this test to test what it should
# test. Need to wait two times because of "sentbox_watch" set (the same event is emitted for
# Sentbox currently).
ac1._evtracker.wait_idle_inbox_ready()
ac1._evtracker.wait_idle_inbox_ready()
assert msg.text == "subj message in Sent"

View File

@@ -35,7 +35,7 @@ pub enum EventType {
/// Emitted when an IMAP message has been moved
ImapMessageMoved(String),
/// Emitted before going into IDLE on the Inbox folder.
/// Emitted before going into IDLE on any folder.
ImapInboxIdle,
/// Emitted when an new file in the $BLOBDIR was created

View File

@@ -665,18 +665,15 @@ impl Imap {
// message, move it to the movebox and then download the second message before
// downloading the first one, if downloading from inbox before moving is allowed.
if folder == target
// Never download messages directly from the spam folder.
// If the sender is known, the message will be moved to the Inbox or Mvbox
// and then we download the message from there.
// Also see `spam_target_folder_cfg()`.
&& folder_meaning != FolderMeaning::Spam
&& prefetch_should_download(
context,
folder_meaning,
&headers,
&message_id,
fetch_response.flags(),
)
.await.context("prefetch_should_download")?
.await
.context("prefetch_should_download")?
{
match download_limit {
Some(download_limit) => uids_fetch.push((
@@ -2244,10 +2241,34 @@ async fn prefetch_get_chat(
/// Determines whether the message should be downloaded based on prefetched headers.
pub(crate) async fn prefetch_should_download(
context: &Context,
folder_meaning: FolderMeaning,
headers: &[mailparse::MailHeader<'_>],
message_id: &str,
mut flags: impl Iterator<Item = Flag<'_>>,
) -> Result<bool> {
// Never download messages directly from the spam folder.
// If the sender is known, the message will be moved to the Inbox or Mvbox
// and then we download the message from there.
// Also see `spam_target_folder_cfg()`.
if folder_meaning == FolderMeaning::Spam {
return Ok(false);
}
// Download outgoing messages only from Inbox and Mvbox (and Sent -- until
// `Config::SentboxWatch` is dropped) to ensure they are sorted correctly with incoming
// messages. This way we actually do server-side sorting. Otherwise it's possible that outgoing
// replies from other devices appear before incoming messages. Users should CC/BCC/To themselves
// to see sent messages in Delta Chat.
if matches!(
folder_meaning,
FolderMeaning::Inbox | FolderMeaning::Mvbox | FolderMeaning::Sent
) {
} else if let Some(from) = mimeparser::get_from(headers) {
if context.is_self_addr(&from.addr).await? {
return Ok(false);
}
}
if message::rfc724_mid_exists(context, message_id)
.await?
.is_some()

View File

@@ -71,10 +71,14 @@ impl Imap {
_ => folder_meaning,
};
// Scan folders for incoming messages. As for outgoing ones, users should CC/BCC/To
// themselves so that Delta Chat sees such messages in Inbox.
//
// Don't scan folders that are watched anyway
if !watched_folders.contains(&folder.name().to_string())
&& folder_meaning != FolderMeaning::Drafts
&& folder_meaning != FolderMeaning::Trash
&& folder_meaning != FolderMeaning::Sent
{
self.fetch_move_delete(context, session, folder.name(), folder_meaning)
.await

View File

@@ -12,7 +12,7 @@ use crate::chatlist::Chatlist;
use crate::constants::DC_GCL_FOR_FORWARDING;
use crate::contact;
use crate::download::MIN_DOWNLOAD_LIMIT;
use crate::imap::prefetch_should_download;
use crate::imap::{FolderMeaning, prefetch_should_download};
use crate::imex::{ImexMode, imex};
use crate::securejoin::get_securejoin_qr;
use crate::test_utils::{
@@ -672,9 +672,15 @@ async fn test_parse_ndn(
// Check that the ndn would be downloaded:
let headers = mailparse::parse_mail(raw_ndn).unwrap().headers;
assert!(
prefetch_should_download(&t, &headers, "some-other-message-id", std::iter::empty(),)
.await
.unwrap()
prefetch_should_download(
&t,
FolderMeaning::Inbox,
&headers,
"some-other-message-id",
std::iter::empty(),
)
.await
.unwrap()
);
receive_imf(&t, raw_ndn, false).await.unwrap();

View File

@@ -661,6 +661,7 @@ async fn fetch_idle(
connection.connectivity.set_idle(ctx);
// Maybe we'll remove watching other folders soon, so use this event for all folders for now.
ctx.emit_event(EventType::ImapInboxIdle);
if !session.can_idle() {