send_custom_email: Only put the unsubscribe footer on marketing emails.

This commit is contained in:
Alex Vandiver 2023-08-03 21:22:21 +00:00 committed by Tim Abbott
parent cb42a1b88d
commit 95b0ab31be
5 changed files with 64 additions and 5 deletions

View File

@ -14,7 +14,7 @@
{% block manage_preferences %} {% block manage_preferences %}
{% if remote_server_email %} {% if remote_server_email %}
<p>You are receiving this email to update you about important changes to Zulip's Terms of Service.</p> <p>You are receiving this email to update you about important changes to Zulip's Terms of Service.</p>
{% else %} {% elif unsubscribe_link %}
<p><a href="{{ realm_uri }}/#settings/notifications">{{ _("Manage email preferences") }}</a> | <a href="{{ unsubscribe_link }}">{{ _("Unsubscribe from marketing emails") }}</a></p> <p><a href="{{ realm_uri }}/#settings/notifications">{{ _("Manage email preferences") }}</a> | <a href="{{ unsubscribe_link }}">{{ _("Unsubscribe from marketing emails") }}</a></p>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -27,7 +27,7 @@ from django.utils.timezone import now as timezone_now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django.utils.translation import override as override_language from django.utils.translation import override as override_language
from confirmation.models import generate_key, one_click_unsubscribe_link from confirmation.models import generate_key
from zerver.lib.logging_util import log_to_file from zerver.lib.logging_util import log_to_file
from zerver.models import EMAIL_TYPES, Realm, ScheduledEmail, UserProfile, get_user_profile_by_id from zerver.models import EMAIL_TYPES, Realm, ScheduledEmail, UserProfile, get_user_profile_by_id
from zproject.email_backends import EmailLogBackEnd, get_forward_address from zproject.email_backends import EmailLogBackEnd, get_forward_address
@ -565,7 +565,6 @@ def send_custom_email(
context: Dict[str, Union[List[str], str]] = { context: Dict[str, Union[List[str], str]] = {
"realm_uri": user_profile.realm.uri, "realm_uri": user_profile.realm.uri,
"realm_name": user_profile.realm.name, "realm_name": user_profile.realm.name,
"unsubscribe_link": one_click_unsubscribe_link(user_profile, "marketing"),
} }
if add_context is not None: if add_context is not None:
add_context(context, user_profile) add_context(context, user_profile)

View File

@ -1,9 +1,10 @@
from argparse import ArgumentParser from argparse import ArgumentParser
from typing import Any, List from typing import Any, Callable, Dict, List, Optional, Union
from django.conf import settings from django.conf import settings
from django.db.models import Q, QuerySet from django.db.models import Q, QuerySet
from confirmation.models import one_click_unsubscribe_link
from zerver.lib.management import ZulipBaseCommand from zerver.lib.management import ZulipBaseCommand
from zerver.lib.send_email import send_custom_email from zerver.lib.send_email import send_custom_email
from zerver.models import Realm, UserProfile from zerver.models import Realm, UserProfile
@ -79,6 +80,9 @@ class Command(ZulipBaseCommand):
def handle(self, *args: Any, **options: str) -> None: def handle(self, *args: Any, **options: str) -> None:
target_emails: List[str] = [] target_emails: List[str] = []
users: QuerySet[UserProfile] = UserProfile.objects.none() users: QuerySet[UserProfile] = UserProfile.objects.none()
add_context: Optional[
Callable[[Dict[str, Union[List[str], str]], UserProfile], None]
] = None
if options["entire_server"]: if options["entire_server"]:
users = UserProfile.objects.filter( users = UserProfile.objects.filter(
@ -95,6 +99,13 @@ class Command(ZulipBaseCommand):
enable_marketing_emails=True, enable_marketing_emails=True,
long_term_idle=False, long_term_idle=False,
).distinct("delivery_email") ).distinct("delivery_email")
def add_marketing_unsubscribe(
context: Dict[str, Union[List[str], str]], user: UserProfile
) -> None:
context["unsubscribe_link"] = one_click_unsubscribe_link(user, "marketing")
add_context = add_marketing_unsubscribe
elif options["remote_servers"]: elif options["remote_servers"]:
from zilencer.models import RemoteZulipServer from zilencer.models import RemoteZulipServer
@ -129,7 +140,9 @@ class Command(ZulipBaseCommand):
users = users.exclude( users = users.exclude(
Q(tos_version=None) | Q(tos_version=UserProfile.TOS_VERSION_BEFORE_FIRST_LOGIN) Q(tos_version=None) | Q(tos_version=UserProfile.TOS_VERSION_BEFORE_FIRST_LOGIN)
) )
send_custom_email(users, target_emails=target_emails, options=options) send_custom_email(
users, target_emails=target_emails, options=options, add_context=add_context
)
if options["dry_run"]: if options["dry_run"]:
print("Would send the above email to:") print("Would send the above email to:")

View File

@ -0,0 +1,4 @@
From: TestFrom
Subject: Test subject
Test body with {{ custom }} value.

View File

@ -1,5 +1,6 @@
import tempfile import tempfile
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Dict, List, Union
from unittest.mock import patch from unittest.mock import patch
import ldap import ldap
@ -105,6 +106,48 @@ class TestCustomEmails(ZulipTestCase):
self.assertFalse(msg.reply_to) self.assertFalse(msg.reply_to)
self.assertEqual("Test body", msg.body) self.assertEqual("Test body", msg.body)
def test_send_custom_email_context(self) -> None:
hamlet = self.example_user("hamlet")
markdown_template_path = (
"zerver/tests/fixtures/email/custom_emails/email_base_headers_test.md"
)
send_custom_email(
UserProfile.objects.filter(id=hamlet.id),
options={
"markdown_template_path": markdown_template_path,
"dry_run": False,
},
)
self.assert_length(mail.outbox, 1)
msg = mail.outbox[0]
# We default to not including an unsubscribe link in the headers
self.assertEqual(msg.extra_headers.get("X-Auto-Response-Suppress"), "All")
self.assertIsNone(msg.extra_headers.get("List-Unsubscribe"))
mail.outbox = []
markdown_template_path = (
"zerver/tests/fixtures/email/custom_emails/email_base_headers_custom_test.md"
)
def add_context(context: Dict[str, Union[List[str], str]], user: UserProfile) -> None:
context["unsubscribe_link"] = "some@email"
context["custom"] = str(user.id)
send_custom_email(
UserProfile.objects.filter(id=hamlet.id),
options={
"markdown_template_path": markdown_template_path,
"dry_run": False,
},
add_context=add_context,
)
self.assert_length(mail.outbox, 1)
msg = mail.outbox[0]
self.assertEqual(msg.extra_headers.get("X-Auto-Response-Suppress"), "All")
self.assertEqual(msg.extra_headers.get("List-Unsubscribe"), "<some@email>")
self.assertIn(f"Test body with {hamlet.id} value", msg.body)
def test_send_custom_email_no_argument(self) -> None: def test_send_custom_email_no_argument(self) -> None:
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
from_name = "from_name_test" from_name = "from_name_test"