Repository: oppia/oppia

Issue:
Dummy mail button in admin page
**Is your feature request related to a problem? Please describe.**
There was an issue with the August release where mails weren't being sent from the production server and currently in our testing process, there is no path where we check whether mails are working. 
**Describe the solution you'd like**
To mitigate such instances, this issue aims at adding a 'Send Dummy Mail' button to the admin page (Config or Jobs tab, as Activites tab is not available in prod), that can be used to send mails in the test server.
Dummy mail button in admin page
**Is your feature request related to a problem? Please describe.**
There was an issue with the August release where mails weren't being sent from the production server and currently in our testing process, there is no path where we check whether mails are working. 
**Describe the solution you'd like**
To mitigate such instances, this issue aims at adding a 'Send Dummy Mail' button to the admin page (Config or Jobs tab, as Activites tab is not available in prod), that can be used to send mails in the test server.


Discussion:
@aks681 Can I take up this issue?
Yup, go for it!
@aks681  Should the button do the work of compose in Gmail, like opening a model and then write the to,sub, content and then a send button which calls the backend to send the mail.
And is there an existing mail sending program in oppia to which I can refer or call to
@aks681 Can I take up this issue?
Yup, go for it!
@aks681  Should the button do the work of compose in Gmail, like opening a model and then write the to,sub, content and then a send button which calls the backend to send the mail.
And is there an existing mail sending program in oppia to which I can refer or call to

Resolving patch:
diff --git a/core/controllers/admin.py b/core/controllers/admin.py
--- a/core/controllers/admin.py
+++ b/core/controllers/admin.py
@@ -28,6 +28,7 @@
 from core.domain import collection_services
 from core.domain import config_domain
 from core.domain import config_services
+from core.domain import email_manager
 from core.domain import exp_domain
 from core.domain import exp_fetchers
 from core.domain import exp_services
@@ -632,3 +633,16 @@ def get(self):
             'data': extracted_answers
         }
         self.render_json(response)
+
+
+class SendDummyMailToAdminHandler(base.BaseHandler):
+    """This function handles sending test emails."""
+
+    @acl_decorators.can_access_admin_page
+    def post(self):
+        username = self.username
+        if feconf.CAN_SEND_EMAILS:
+            email_manager.send_dummy_mail_to_admin(username)
+            self.render_json({})
+        else:
+            raise self.InvalidInputException('This app cannot send emails.')
diff --git a/core/domain/email_manager.py b/core/domain/email_manager.py
--- a/core/domain/email_manager.py
+++ b/core/domain/email_manager.py
@@ -370,6 +370,23 @@ def send_job_failure_email(job_id):
             mail_body.replace('\n', '<br/>'))
 
 
+def send_dummy_mail_to_admin(username):
+    """Send an email from the specified email address to admin.
+
+    Args:
+        username: str. Username of the sender.
+    """
+
+    email_body = 'This is a test mail from %s.' % (username)
+    email_subject = 'Test Mail'
+    system_name_email = '%s <%s>' % (
+        feconf.SYSTEM_EMAIL_NAME, feconf.SYSTEM_EMAIL_ADDRESS)
+
+    email_services.send_mail(
+        system_name_email, feconf.ADMIN_EMAIL_ADDRESS, email_subject,
+        email_body, email_body.replace('\n', '<br/>'), bcc_admin=False)
+
+
 def send_mail_to_admin(email_subject, email_body):
     """Send an email to the admin email address.
 
diff --git a/main.py b/main.py
--- a/main.py
+++ b/main.py
@@ -698,6 +698,8 @@ def ui_access_wrapper(self, *args, **kwargs):
         collection_editor.ExplorationMetadataSearchHandler),
     get_redirect_route(
         r'/explorationdataextractionhandler', admin.DataExtractionQueryHandler),
+    get_redirect_route(
+        r'/sendDummyMailToAdminHandler', admin.SendDummyMailToAdminHandler),
     get_redirect_route(r'/frontend_errors', FrontendErrorHandler),
     get_redirect_route(r'/logout', base.LogoutPage),
 


Test patch:
diff --git a/core/controllers/admin_test.py b/core/controllers/admin_test.py
--- a/core/controllers/admin_test.py
+++ b/core/controllers/admin_test.py
@@ -1047,3 +1047,28 @@ def test_clear_search_index(self):
         self.assertEqual(result_explorations, [])
         result_collections = search_services.search_collections('Welcome', 2)[0]
         self.assertEqual(result_collections, [])
+
+
+class SendDummyMailTest(test_utils.GenericTestBase):
+    """"Tests for sending test mails to admin."""
+
+    def setUp(self):
+        super(SendDummyMailTest, self).setUp()
+        self.signup(self.ADMIN_EMAIL, self.ADMIN_USERNAME)
+
+    def test_send_dummy_mail(self):
+        self.login(self.ADMIN_EMAIL, is_super_admin=True)
+        csrf_token = self.get_new_csrf_token()
+
+        with self.swap(feconf, 'CAN_SEND_EMAILS', True):
+            generated_response = self.post_json(
+                '/sendDummyMailToAdminHandler', payload={},
+                csrf_token=csrf_token, expected_status_int=200)
+            self.assertEqual(generated_response, {})
+
+        with self.swap(feconf, 'CAN_SEND_EMAILS', False):
+            generated_response = self.post_json(
+                '/sendDummyMailToAdminHandler', payload={},
+                csrf_token=csrf_token, expected_status_int=400)
+            self.assertEqual(
+                generated_response['error'], 'This app cannot send emails.')
diff --git a/core/domain/email_manager_test.py b/core/domain/email_manager_test.py
--- a/core/domain/email_manager_test.py
+++ b/core/domain/email_manager_test.py
@@ -114,6 +114,44 @@ def test_email_to_admin_is_sent_correctly(self):
             self.assertIn('Dummy Body', messages[0].html.decode())
 
 
+class DummyMailTest(test_utils.GenericTestBase):
+    """Test that emails are correctly sent to the testing email id."""
+
+    def test_sending_emails(self):
+        dummy_system_name = 'DUMMY_SYSTEM_NAME'
+        dummy_system_address = 'dummy@system.com'
+        dummy_receiver_address = 'admin@system.com'
+
+        send_email_ctx = self.swap(feconf, 'CAN_SEND_EMAILS', True)
+        system_name_ctx = self.swap(
+            feconf, 'SYSTEM_EMAIL_NAME', dummy_system_name)
+        system_email_ctx = self.swap(
+            feconf, 'SYSTEM_EMAIL_ADDRESS', dummy_system_address)
+        admin_email_ctx = self.swap(
+            feconf, 'ADMIN_EMAIL_ADDRESS', dummy_receiver_address)
+
+        with send_email_ctx, system_name_ctx, system_email_ctx, admin_email_ctx:
+            # Make sure there are no emails already sent.
+            messages = self.mail_stub.get_sent_messages(
+                to=dummy_receiver_address)
+            self.assertEqual(len(messages), 0)
+
+            # Send an email.
+            email_manager.send_dummy_mail_to_admin(dummy_system_name)
+
+            # Make sure emails are sent.
+            messages = self.mail_stub.get_sent_messages(
+                to=dummy_receiver_address)
+            self.assertEqual(len(messages), 1)
+            self.assertEqual(
+                messages[0].sender, 'DUMMY_SYSTEM_NAME <dummy@system.com>')
+            self.assertEqual(messages[0].to, dummy_receiver_address)
+            self.assertEqual(
+                messages[0].subject.decode(), 'Test Mail')
+            self.assertIn('This is a test mail from DUMMY_SYSTEM_NAME',
+                          messages[0].html.decode())
+
+
 class EmailRightsTest(test_utils.GenericTestBase):
     """Test that only certain users can send certain types of emails."""