From 252269569a83edd6b90e029c4c9d64a854b947ab Mon Sep 17 00:00:00 2001 From: Neil Martinsen-Burrell Date: Fri, 31 Mar 2023 13:32:03 -0500 Subject: [PATCH] Improve submission confirmation email and test it --- src/registrar/models/domain_application.py | 2 +- .../templates/emails/includes/contact.txt | 4 + .../submission_confirmation.subject.txt | 1 + .../emails/submission_confirmation.txt | 94 +++++++++++++++++- src/registrar/tests/test_emails.py | 97 +++++++++++++++++++ 5 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 src/registrar/templates/emails/includes/contact.txt create mode 100644 src/registrar/templates/emails/submission_confirmation.subject.txt create mode 100644 src/registrar/tests/test_emails.py diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 526e39798..729cdfe8c 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -478,7 +478,7 @@ class DomainApplication(TimeStampedModel): "emails/submission_confirmation.txt", "emails/submission_confirmation_subject.txt", self.submitter.email, - context={"id": self.id, "domain_name": self.requested_domain.name}, + context={"application": self}, ) except EmailSendingError: logger.warning("Failed to send confirmation email", exc_info=True) diff --git a/src/registrar/templates/emails/includes/contact.txt b/src/registrar/templates/emails/includes/contact.txt new file mode 100644 index 000000000..a3c3dd6eb --- /dev/null +++ b/src/registrar/templates/emails/includes/contact.txt @@ -0,0 +1,4 @@ +{{ contact.get_formatted_name }} +{% if contact.title %}{{ contact.title }}{% endif %} +{% if contact.email %}{{ contact.email }}{% endif %} +{% if contact.phone %}{{ contact.phone.as_national }}{% endif %} diff --git a/src/registrar/templates/emails/submission_confirmation.subject.txt b/src/registrar/templates/emails/submission_confirmation.subject.txt new file mode 100644 index 000000000..47e3f70fd --- /dev/null +++ b/src/registrar/templates/emails/submission_confirmation.subject.txt @@ -0,0 +1 @@ +We received your .gov domain request diff --git a/src/registrar/templates/emails/submission_confirmation.txt b/src/registrar/templates/emails/submission_confirmation.txt index f44c2f505..b028e1626 100644 --- a/src/registrar/templates/emails/submission_confirmation.txt +++ b/src/registrar/templates/emails/submission_confirmation.txt @@ -1,4 +1,92 @@ -Thank you for submitting an application for the domain name "{{ domain_name }}". +Hi {{ application.creator.first_name }}. -If you need to make changes to your application, visit -. +We received your .gov domain request. + +DOMAIN REQUESTED: {{ application.requested_domain.name }} +REQUEST RECEIVED ON: {{ application.updated_at|date }} +REQUEST #: {{ application.id }} +STATUS: Received + + +NEED TO MAKE CHANGES? + +If you need to change your request you have to first withdraw it. Once you +withdraw the request you can edit it and submit it again. Changing your request +might add to the wait time. Learn more about withdrawing your request. + + +NEXT STEPS + +- We’ll review your request. This usually takes 20 business days. + +- You can check the status of your request at any time. + + +- We’ll email you with questions or when we complete our review. + + +THANK YOU + +.Gov helps the public identify official, trusted information. Thank you for +requesting a .gov domain. + +---------------------------------------------------------------- + +SUMMARY OF YOUR DOMAIN REQUEST + +Type of organization: +{{ application.get_organization_type_display }} + +Organization name and mailing address: +{{ application.organization_name }} +{{ application.address_line1 }} +{% if application.address_line2 %}{{ application.address_line2 }}{% endif %} +{{ application.city }}, {{ application.state_territory }} +{{ application.zipcode }} +{% if application.urbanization %}{{ application.urbanization }}{% endif %} + +{% if application.type_of_work %} +Type of work: +{{ application.type_of_work }} + +{% endif %} +Authorizing official: +{% include "emails/includes/contact.txt" with contact=application.authorizing_official %} + +{% if application.current_websites.exists %} +Current website for your organization: +{% for site in application.current_websites.all %} +{{ site.website }} +{% endfor %} + +{% endif %} +.gov domain: +{{ application.requested_domain.name }} +{% for site in application.alternative_domains.all %} +{{ site.website }} +{% endfor %} + +Purpose of your domain: +{{ application.purpose }} + +Your contact information: +{% include "emails/includes/contact.txt" with contact=application.submitter %} + +{% if application.other_contacts.all %} +Other employees from your organization: +{% for other in application.other_contacts.all %} +{% include "emails/includes/contact.txt" with contact=other %} +{% endfor %} + +{% endif %} +{% if application.anything_else %} +Anything else we should know? + +{{ application.anything_else }} +{% endif %} + +---------------------------------------------------------------- + +The .gov team +Contact us: +Visit diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py new file mode 100644 index 000000000..edbf5cdf8 --- /dev/null +++ b/src/registrar/tests/test_emails.py @@ -0,0 +1,97 @@ +"""Test our email templates and sending.""" + +from unittest.mock import MagicMock + +from django.contrib.auth import get_user_model +from django.test import TestCase + +from registrar.models import Contact, Domain, Website, DomainApplication + +import boto3_mocking # type: ignore + + +class TestEmails(TestCase): + def _completed_application(self): + """A completed domain application.""" + user = get_user_model().objects.create(username="username") + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(555) 555 5555", + ) + domain, _ = Domain.objects.get_or_create(name="city.gov") + alt, _ = Website.objects.get_or_create(website="city1.gov") + current, _ = Website.objects.get_or_create(website="city.com") + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="testy-admin@town.com", + phone="(555) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(555) 555 5557", + ) + application, _ = DomainApplication.objects.get_or_create( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + anything_else="No", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + requested_domain=domain, + submitter=you, + creator=user, + ) + application.other_contacts.add(other) + application.current_websites.add(current) + application.alternative_domains.add(alt) + + return application + + @boto3_mocking.patching + def test_submission_confirmation(self): + """Submission confirmation email works.""" + application = self._completed_application() + + mock_client_class = MagicMock() + mock_client = mock_client_class.return_value + with boto3_mocking.clients.handler_for("sesv2", mock_client_class): + application.submit() + + # check that an email was sent + self.assertTrue(mock_client.send_email.called) + + # check the call sequence for the email + args, kwargs = mock_client.send_email.call_args + self.assertIn("Content", kwargs) + self.assertIn("Simple", kwargs["Content"]) + self.assertIn("Subject", kwargs["Content"]["Simple"]) + self.assertIn("Body", kwargs["Content"]["Simple"]) + + # check for things in the email content (not an exhaustive list) + body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] + self.assertIn("Type of organization:", body) + self.assertIn("Federal", body) + self.assertIn("Authorizing official:", body) + self.assertIn("Testy Tester", body) + self.assertIn(".gov domain:", body) + self.assertIn("city.gov", body) + self.assertIn("city1.gov", body) + + # check for optional things + self.assertIn("Other employees from your organization:", body) + self.assertIn("Testy2 Tester2", body) + self.assertIn("Current website for your organization:", body) + self.assertIn("city.com", body) + self.assertNotIn("Type of work:", body)