From fdcfafd13db2894e7a14b3b748dcdb7e5568419d Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Wed, 17 Sep 2025 18:53:18 +0000 Subject: [PATCH] send_custom_email: Add a flag for sending release announcements. --- .../zerver/emails/custom_email_base.pre.html | 10 ++-- ...mail_base.pre.manage_preferences_block.txt | 4 ++ .../management/commands/send_custom_email.py | 49 ++++++++++++++++++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/templates/zerver/emails/custom_email_base.pre.html b/templates/zerver/emails/custom_email_base.pre.html index 9eb792aa13..42287231f0 100644 --- a/templates/zerver/emails/custom_email_base.pre.html +++ b/templates/zerver/emails/custom_email_base.pre.html @@ -13,9 +13,13 @@ {% block manage_preferences %} {% if remote_server_email %} -

You are receiving this email to update you about important changes to Zulip's Terms of Service.

- Unsubscribe + {% if released_version %} +

You are receiving this email because you opted into release notifications.

+ {% else %} +

You are receiving this email to update you about important changes to Zulip's Terms of Service.

+ Unsubscribe + {% endif %} {% elif unsubscribe_link %} -

{{ _("Manage email preferences") }} | {{ _("Unsubscribe from marketing emails") }}

+

{{ _("Manage email preferences") }} | {{ _("Unsubscribe from marketing emails") }}

{% endif %} {% endblock %} diff --git a/templates/zerver/emails/custom_email_base.pre.manage_preferences_block.txt b/templates/zerver/emails/custom_email_base.pre.manage_preferences_block.txt index 37d3c97e3a..36b36d95cb 100644 --- a/templates/zerver/emails/custom_email_base.pre.manage_preferences_block.txt +++ b/templates/zerver/emails/custom_email_base.pre.manage_preferences_block.txt @@ -1,9 +1,13 @@ --- {% if remote_server_email %} +{% if released_version %} +You are receiving this email because you opted into release notifications. +{% else %} You are receiving this email to update you about important changes to Zulip's Terms of Service. Unsubscribe: {{ unsubscribe_link }} +{% endif %} {% elif unsubscribe_link %} {{ _("Manage email preferences") }}: diff --git a/zerver/management/commands/send_custom_email.py b/zerver/management/commands/send_custom_email.py index 766d595906..63fa4a0584 100644 --- a/zerver/management/commands/send_custom_email.py +++ b/zerver/management/commands/send_custom_email.py @@ -9,11 +9,12 @@ from typing_extensions import override from confirmation.models import one_click_unsubscribe_link from zerver.lib.management import ZulipBaseCommand -from zerver.lib.send_email import send_custom_email, send_custom_server_email +from zerver.lib.send_email import custom_email_sender, send_custom_email, send_custom_server_email from zerver.models import Realm, UserProfile if settings.ZILENCER_ENABLED: - from zilencer.models import RemoteZulipServer + from corporate.lib.stripe import BILLING_SUPPORT_EMAIL + from zilencer.models import RemoteRealmBillingUser, RemoteServerBillingUser, RemoteZulipServer class Command(ZulipBaseCommand): @@ -41,6 +42,11 @@ class Command(ZulipBaseCommand): action="store_true", help="Send to registered contact email addresses for remote Zulip servers.", ) + targets.add_argument( + "--announce-release", + metavar="VERSION", + help="Announce a major or minor release to remote servers.", + ) targets.add_argument( "--all-sponsored-org-admins", action="store_true", @@ -133,6 +139,45 @@ class Command(ZulipBaseCommand): for server in servers: print(f" {server.contact_email} ({server.hostname})") return + elif options["announce_release"]: + server_users = RemoteServerBillingUser.objects.filter( + is_active=True, + remote_server__deactivated=False, + ) + realm_users = RemoteRealmBillingUser.objects.filter( + is_active=True, + remote_realm__server__deactivated=False, + remote_realm__is_system_bot_realm=False, + remote_realm__registration_deactivated=False, + remote_realm__realm_deactivated=False, + remote_realm__realm_locally_deleted=False, + ) + if options["announce_release"].endswith(".0"): + server_users = server_users.filter(enable_major_release_emails=True) + realm_users = realm_users.filter(enable_major_release_emails=True) + else: + server_users = server_users.filter(enable_maintenance_release_emails=True) + realm_users = realm_users.filter(enable_maintenance_release_emails=True) + # This does an implicit "distinct" + all_emails = server_users.union(realm_users).values_list("email", flat=True) + del options["from_address"] + email_sender = custom_email_sender( + dry_run=dry_run, from_address=BILLING_SUPPORT_EMAIL, **options + ) + + for email in all_emails: + email_sender( + to_email=email, + context={ + "remote_server_email": True, + "released_version": options["announce_release"], + }, + ) + if dry_run: + print("Would send the above email to:") + for email in all_emails: + print(f" {email}") + return if options["entire_server"]: users = UserProfile.objects.filter(