Repository: cisagov/manage.get.gov

Issue:
Add a way to turn off email sending in non-production environments
### Issue description

Email sending should always be on by default, however, there are times when we are running through tests in shared envirornments where users may perform activites which will result in unnecessary email sending. This is especially the case when a fixture user's email is the creator on a domain request and another user approves the  domain request. The risk of sending an accidental email to a coworker would be nice to avoid. 

We will also be providing a way to do and export from stable and into a test environment but we don't want emails accidentally sending to real users.

Thus in all non-production settings we should have the ability to turn sending emails on and off

### Acceptance criteria

- [ ] create an environment variable or feature flag for turning 
- [ ] add a few lines to documentation (readmes in the developer folder) to let other devs know how to turn this on/off and see if it's on (be brief)
- [ ] ensure this cannot be on in production (you can just check your feature flag/env variable along side our IS_PRODUCTION variable)

### Additional context

Pro of using feature flag is that a user just needs to check django admin to see if it's on and can use that to flip it on and off. This is pretty convenient on sandboxes that are shared as otherwise you would have to check what environment variables are turned on for that sandbox which is a slightly slower process. The choice is up to the developer here.

### Links to other issues

_No response_


Discussion:

Resolving patch:
diff --git a/src/registrar/admin.py b/src/registrar/admin.py
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -2308,6 +2308,8 @@ def user_group(self, obj):
 
 
 class WaffleFlagAdmin(FlagAdmin):
+    """Custom admin implementation of django-waffle's Flag class"""
+
     class Meta:
         """Contains meta information about this class"""
 
@@ -2341,6 +2343,6 @@ class Meta:
 # Register our custom waffle implementations
 admin.site.register(models.WaffleFlag, WaffleFlagAdmin)
 
-# Unregister Sample and Switch from the waffle library
-admin.site.unregister(Sample)
+# Unregister Switch and Sample from the waffle library
 admin.site.unregister(Switch)
+admin.site.unregister(Sample)
diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py
--- a/src/registrar/config/settings.py
+++ b/src/registrar/config/settings.py
@@ -326,7 +326,7 @@
 # endregion
 
 # region: Waffle feature flags-----------------------------------------------------------###
-# If Waffle encounters a reference to a flag that is not in the database, should Waffle create the flag?
+# If Waffle encounters a reference to a flag that is not in the database, create the flag automagically.
 WAFFLE_CREATE_MISSING_FLAGS = True
 
 # The model that will be used to keep track of flags. Extends AbstractUserFlag.
diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py
--- a/src/registrar/utility/email.py
+++ b/src/registrar/utility/email.py
@@ -8,6 +8,7 @@
 from email.mime.application import MIMEApplication
 from email.mime.multipart import MIMEMultipart
 from email.mime.text import MIMEText
+from waffle import flag_is_active
 
 
 logger = logging.getLogger(__name__)
@@ -35,6 +36,11 @@ def send_templated_email(
 
     Raises EmailSendingError if SES client could not be accessed
     """
+
+    if flag_is_active(None, "disable_email_sending") and not settings.IS_PRODUCTION:  # type: ignore
+        message = "Could not send email. Email sending is disabled due to flag 'disable_email_sending'."
+        raise EmailSendingError(message)
+
     template = get_template(template_name)
     email_body = template.render(context=context)
 


Test patch:
diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py
--- a/src/registrar/tests/test_emails.py
+++ b/src/registrar/tests/test_emails.py
@@ -3,10 +3,12 @@
 from unittest.mock import MagicMock
 
 from django.test import TestCase
+from waffle.testutils import override_flag
+from registrar.utility import email
+from registrar.utility.email import send_templated_email
 from .common import completed_domain_request, less_console_noise
 
 from datetime import datetime
-from registrar.utility import email
 import boto3_mocking  # type: ignore
 
 
@@ -15,6 +17,24 @@ def setUp(self):
         self.mock_client_class = MagicMock()
         self.mock_client = self.mock_client_class.return_value
 
+    @boto3_mocking.patching
+    @override_flag("disable_email_sending", active=True)
+    def test_disable_email_flag(self):
+        """Test if the 'disable_email_sending' stops emails from being sent"""
+        with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
+            expected_message = "Email sending is disabled due to"
+            with self.assertRaisesRegex(email.EmailSendingError, expected_message):
+                send_templated_email(
+                    "test content",
+                    "test subject",
+                    "doesnotexist@igorville.com",
+                    context={"domain_request": self},
+                    bcc_address=None,
+                )
+
+        # Assert that an email wasn't sent
+        self.assertFalse(self.mock_client.send_email.called)
+
     @boto3_mocking.patching
     def test_submission_confirmation(self):
         """Submission confirmation email works."""