Repository: zulip/zulip

Issue:
Add a setting to disable sender names in email notifications
When sending email notifications we currently, when relevant, put a user's name in the From header of the email message. E.g. if I trigger an invitation email to someone, my name will be put in the From header. For some organizations this can be undesirable, because some phishing detection systems (Google's Advanced phishing and malware protection system is the case we've run into) can mark such messages as suspicious - due to the fact that the name of the company's employee is indicated as the sender, even though the email is coming from an unrelated domain.

We should add an organizaton-level setting `Disable sender names in email notifications` that would disable this behavior and instead use a fixed, generic string in the From field - `Zulip` or `Zulip notifications` are the two ideas that popped up.


Discussion:
Hello @zulip/server-development, @zulip/server-settings members, this issue was labeled with the "area: emails", "area: settings (admin/org)" labels, so you may want to check it out!

<!-- areaLabelAddition -->
@zulipbot claim
Hello @tushar912, you claimed this issue to work on it, but this issue and any referenced pull requests haven't been updated for 10 days. Are you still working on this issue?

If so, please update this issue by leaving a comment on this issue to let me know that you're still working on it. Otherwise, I'll automatically remove you from this issue in 4 days.

If you've decided to work on something else, simply comment `@zulipbot abandon` so that someone else can claim it and continue from where you left off.

Thank you for your valuable contributions to Zulip!

<!-- inactiveWarning -->
@sahil839 this might be a good project for you to pick up -- we've been seeing this issue an increasing amount of late.
Okay, will start working on this along with other issues.
@zulipbot claim

Resolving patch:
diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py
--- a/zerver/lib/actions.py
+++ b/zerver/lib/actions.py
@@ -6480,11 +6480,9 @@ def do_send_confirmation_email(invitee: PreregistrationUser, referrer: UserProfi
         "activate_url": activation_url,
         "referrer_realm_name": referrer.realm.name,
     }
-    from_name = f"{referrer.full_name} (via Zulip)"
     send_email(
         "zerver/emails/invitation",
         to_emails=[invitee.email],
-        from_name=from_name,
         from_address=FromAddress.tokenized_no_reply_address(),
         language=referrer.realm.default_language,
         context=context,


Test patch:
diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py
--- a/zerver/tests/test_signup.py
+++ b/zerver/tests/test_signup.py
@@ -928,9 +928,7 @@ def test_zulip_default_context_does_not_load_inline_previews(self) -> None:
 
 
 class InviteUserBase(ZulipTestCase):
-    def check_sent_emails(
-        self, correct_recipients: List[str], custom_from_name: Optional[str] = None
-    ) -> None:
+    def check_sent_emails(self, correct_recipients: List[str]) -> None:
         from django.core.mail import outbox
 
         self.assert_length(outbox, len(correct_recipients))
@@ -939,8 +937,7 @@ def check_sent_emails(
         if len(outbox) == 0:
             return
 
-        if custom_from_name is not None:
-            self.assertIn(custom_from_name, self.email_display_from(outbox[0]))
+        self.assertIn("Zulip", self.email_display_from(outbox[0]))
 
         self.assertEqual(self.email_envelope_from(outbox[0]), settings.NOREPLY_EMAIL_ADDRESS)
         self.assertRegex(
@@ -987,7 +984,7 @@ def test_successful_invite_user(self) -> None:
         invitee = "alice-test@zulip.com"
         self.assert_json_success(self.invite(invitee, ["Denmark"]))
         self.assertTrue(find_key_by_email(invitee))
-        self.check_sent_emails([invitee], custom_from_name="Hamlet")
+        self.check_sent_emails([invitee])
 
     def test_newbie_restrictions(self) -> None:
         user_profile = self.example_user("hamlet")
@@ -1274,7 +1271,7 @@ def test_successful_invite_user_with_name(self) -> None:
         invitee = f"Alice Test <{email}>"
         self.assert_json_success(self.invite(invitee, ["Denmark"]))
         self.assertTrue(find_key_by_email(email))
-        self.check_sent_emails([email], custom_from_name="Hamlet")
+        self.check_sent_emails([email])
 
     def test_successful_invite_user_with_name_and_normal_one(self) -> None:
         """
@@ -1288,7 +1285,7 @@ def test_successful_invite_user_with_name_and_normal_one(self) -> None:
         self.assert_json_success(self.invite(invitee, ["Denmark"]))
         self.assertTrue(find_key_by_email(email))
         self.assertTrue(find_key_by_email(email2))
-        self.check_sent_emails([email, email2], custom_from_name="Hamlet")
+        self.check_sent_emails([email, email2])
 
     def test_can_invite_others_to_realm(self) -> None:
         def validation_func(user_profile: UserProfile) -> bool:
@@ -2230,7 +2227,7 @@ def test_successful_resend_invitation(self) -> None:
         prereg_user = PreregistrationUser.objects.get(email=invitee)
 
         # Verify and then clear from the outbox the original invite email
-        self.check_sent_emails([invitee], custom_from_name="Zulip")
+        self.check_sent_emails([invitee])
         from django.core.mail import outbox
 
         outbox.pop()
@@ -2261,7 +2258,7 @@ def test_successful_resend_invitation(self) -> None:
         error_result = self.client_post("/json/invites/" + str(9999) + "/resend")
         self.assert_json_error(error_result, "No such invitation")
 
-        self.check_sent_emails([invitee], custom_from_name="Zulip")
+        self.check_sent_emails([invitee])
 
     def test_successful_member_resend_invitation(self) -> None:
         """A POST call from member a account to /json/invites/<ID>/resend
@@ -2278,7 +2275,7 @@ def test_successful_member_resend_invitation(self) -> None:
         prereg_user = PreregistrationUser.objects.get(email=invitee)
 
         # Verify and then clear from the outbox the original invite email
-        self.check_sent_emails([invitee], custom_from_name="Zulip")
+        self.check_sent_emails([invitee])
         from django.core.mail import outbox
 
         outbox.pop()
@@ -2309,7 +2306,7 @@ def test_successful_member_resend_invitation(self) -> None:
         error_result = self.client_post("/json/invites/" + str(9999) + "/resend")
         self.assert_json_error(error_result, "No such invitation")
 
-        self.check_sent_emails([invitee], custom_from_name="Zulip")
+        self.check_sent_emails([invitee])
 
         self.logout()
         self.login("othello")
@@ -2329,7 +2326,7 @@ def test_resend_owner_invitation(self) -> None:
                 invitee, ["Denmark"], invite_as=PreregistrationUser.INVITE_AS["REALM_OWNER"]
             )
         )
-        self.check_sent_emails([invitee], custom_from_name="Zulip")
+        self.check_sent_emails([invitee])
         scheduledemail_filter = ScheduledEmail.objects.filter(
             address__iexact=invitee, type=ScheduledEmail.INVITATION_REMINDER
         )