send_email: Set the Date header according to local enqueue time.

Email clients tend to sort emails by the "Date" header, which is not
when the email was received -- emails can be arbitrarily delayed
during relaying.  Messages without a Date header (as all Zulip
messages previously) have one inserted by the first mailserver they
encounter.  As there are now multiple email-sending queues, we would
like the view of the database, as presented by the emails that are
sent out, to be consistent based on the Date header, which may not be
the same as when the client gets the email in their inbox.

Insert a Date header of when the Zulip system inserted the data into
the local queue, as that encodes when the full information was pulled
from the database.  This also opens the door to multiple workers
servicing the email_senders queue, to limit backlogging during large
notifications, without having to worry about inconsistent delivery
order between those two workers.

Messages which are sent synchronously via `send_email()` get a Date
header of when we attempt to send the message; this is, in practice,
no different from Django's default behaviour of doing so, but makes
the behaviour slightly more consistent.
This commit is contained in:
Alex Vandiver
2025-03-06 16:38:55 +00:00
committed by Tim Abbott
parent 0e152a128f
commit 721fd26442
7 changed files with 24 additions and 3 deletions

View File

@@ -65,7 +65,7 @@ from zerver.lib.remote_server import (
)
from zerver.lib.request import RequestNotes
from zerver.lib.response import json_success
from zerver.lib.send_email import FromAddress
from zerver.lib.send_email import EMAIL_DATE_FORMAT, FromAddress
from zerver.lib.timestamp import timestamp_to_datetime
from zerver.lib.typed_endpoint import (
ApnsAppId,
@@ -1192,6 +1192,7 @@ def update_remote_realm_data_for_server(
"template_prefix": "zerver/emails/internal_billing_notice",
"to_emails": [BILLING_SUPPORT_EMAIL],
"from_address": FromAddress.tokenized_no_reply_address(),
"date": timezone_now().strftime(EMAIL_DATE_FORMAT),
}
for context in new_locally_deleted_remote_realms_on_paid_plan_contexts:
email_dict["context"] = context