Skip to content

use relay's maxsmtprecipients metadata for smtp chunking, to remove another is_chatmail use#8426

Merged
hpk42 merged 1 commit into
mainfrom
hpk/max_smtp_recipient_chunking
Jul 22, 2026
Merged

use relay's maxsmtprecipients metadata for smtp chunking, to remove another is_chatmail use#8426
hpk42 merged 1 commit into
mainfrom
hpk/max_smtp_recipient_chunking

Conversation

@hpk42

@hpk42 hpk42 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Relays since chatmail/relay#960 and released mid may with relay-1.11 set maxsmtprcipients imap metadata to 1000. I manually verified that nine.testrun.org, mailchat.pl and a few others have it set already.

this PR also moves recipient chunking to smtp loop where it belongs because it's transport specific.

@link2xt

link2xt commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Comment here should be adjusted at the same time because it still says that chunks are stored separately:

core/src/receive_imf.rs

Lines 549 to 568 in e2b67d2

// It sometimes happens that a slow server (usually a classical email server)
// receives a message via SMTP,
// but then the connection to the server dies before it sends the OK response.
// In order to handle this case, we delete the SMTP send jobs if we receive our own message via IMAP.
//
// Now, messages with long recipient lists are split into multiple SMTP jobs.
// In this case, we only want to delete the SMTP job that was sent to self
// because this is the only chunk we can be sure was sent out.
let self_addr = context.get_primary_self_addr().await?;
context
.sql
.execute(
"DELETE FROM smtp \
WHERE rfc724_mid=?1 AND (recipients LIKE ?2 OR recipients LIKE ('% ' || ?2))",
(rfc724_mid_orig, &self_addr),
)
.await?;
if !msg_has_pending_smtp_job(context, msg_id).await? {
msg_id.set_delivered(context).await?;
}

The logic is likely not working at all because self-sent message may be missed during prefetch, could likely be removed (see #8366).

Comment thread src/context.rs
@hpk42

hpk42 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

core/src/receive_imf.rs

Lines 549 to 568 in e2b67d2

// It sometimes happens that a slow server (usually a classical email server)
// receives a message via SMTP,
// but then the connection to the server dies before it sends the OK response.
// In order to handle this case, we delete the SMTP send jobs if we receive our own message via IMAP.
//
// Now, messages with long recipient lists are split into multiple SMTP jobs.
// In this case, we only want to delete the SMTP job that was sent to self
// because this is the only chunk we can be sure was sent out.
let self_addr = context.get_primary_self_addr().await?;
context
.sql
.execute(
"DELETE FROM smtp \
WHERE rfc724_mid=?1 AND (recipients LIKE ?2 OR recipients LIKE ('% ' || ?2))",
(rfc724_mid_orig, &self_addr),
)
.await?;
if !msg_has_pending_smtp_job(context, msg_id).await? {
msg_id.set_delivered(context).await?;
}

The logic is likely not working at all because self-sent message may be missed during prefetch, could likely be removed (see #8366).

i fixed the comment. Also tried removing the deletion logic but that makes test_mark_message_as_delivered_only_after_sent_out_fully and test_resend_after_ndn fail, so at least the tests exercise it.

In reality, smtp-lost-ok case should be rare and sending twice is deduplicated at receiver sides. Cleartext usage (where receivers may not deduplicate) does not really matter for this edge case.
But still think the code/test removal is better done in a separate PR.

Comment thread src/calls.rs
/// <https://github.com/deltachat/deltachat-desktop/issues/5447>.
pub async fn ice_servers(context: &Context) -> Result<String> {
if let Some(ref metadata) = *context.metadata.read().await {
if let Some(metadata) = context.metadata.read().await.values().next() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO for the future: this may collect all ICE servers, maybe using multiple TURN servers at once makes the calls more reliable.

Comment thread src/chat.rs
Comment thread src/context.rs Outdated
Comment thread src/imap.rs Outdated

@link2xt link2xt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole METADATA and making the limit configurable seems to be an overkill (also because it's an yet another setting relay operators can tweak arbitrarily), but as far as i understand the real reason is that XCHATMAIL cannot be removed from the outer banner just with the Dovecot configuration. Otherwise a better place for this would be SMTP server banner, Exim even supports some standard way to advertise the recipient limit in its banner IIRC.

Comment thread src/constants.rs Outdated
// Fallback for the maximum number of recipients in SMTP's `RCPT TO:`;
// recipient lists exceeding the limit are sent in chunks.
// Relays advertise their limit via IMAP METADATA
// and in very rare cases the provider db sets `max_smtp_rcpt_to`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will be no provider database with #8437, in practice the only provider is nauta.cu setting this to 20. I'd simply remove the last line of the comment, it's enough to know that this is the default and relays can overwrite it.

Remove is_chatmail flag, and rely on IMAP metadata
advertising the recipients limit (usually 1000),
falling back to 50 (or fewer in some exceptional cases)
just as before when is_chatmail was false.

Also, server metadata is now keyed per transport,
which in the future eases collecting ICE servers
from all relays (instead of just any first relay).
@hpk42
hpk42 force-pushed the hpk/max_smtp_recipient_chunking branch from a7a168d to be4470c Compare July 22, 2026 18:07
@hpk42

hpk42 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

The whole METADATA and making the limit configurable seems to be an overkill (also because it's an yet another setting relay operators can tweak arbitrarily), but as far as i understand the real reason is that XCHATMAIL cannot be removed from the outer banner just with the Dovecot configuration. Otherwise a better place for this would be SMTP server banner, Exim even supports some standard way to advertise the recipient limit in its banner IIRC.

Making metadata per-transport has at least the win that we can collect all ICE servers later (as you noted), and is also conceptually the right thing to do.
Making max recipients configurable for relays can be useful, as increasing number of max recipients (on choice of operator) could be(come) useful for channels.
We already have values that relays advertise via IMAP metadata so adding it there for now i consider the pragmatic choice but i agree that it should conceptually be part of the SMTP chat. If we find something it should be easy enough to adapt then. For now, i was mainly trying to get rid of "is_chatmail" flag.

@hpk42
hpk42 merged commit 0e4574c into main Jul 22, 2026
80 of 83 checks passed
@hpk42
hpk42 deleted the hpk/max_smtp_recipient_chunking branch July 22, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants