def test_govuk_banner(show_banner):
    email = HTMLEmailTemplate({'content': 'hello world', 'subject': ''})
    email.govuk_banner = show_banner
    if show_banner:
        assert "GOV.UK" in str(email)
    else:
        assert "GOV.UK" not in str(email)
Beispiel #2
0
def test_complete_html(complete_html, branding_should_be_present, brand_logo,
                       brand_name, brand_colour, content):

    email = str(
        HTMLEmailTemplate(
            {
                'content': 'hello world',
                'subject': ''
            },
            complete_html=complete_html,
            brand_logo=brand_logo,
            brand_name=brand_name,
            brand_colour=brand_colour,
        ))

    if complete_html:
        assert content in email
    else:
        assert content not in email

    if branding_should_be_present:
        assert brand_logo in email
        assert brand_name in email

        if brand_colour:
            assert brand_colour in email
            assert '##' not in email
Beispiel #3
0
def test_URLs_get_escaped(url, expected_html, expected_html_in_template):
    assert notify_email_markdown(url) == (
        '<p style="Margin: 0 0 20px 0; font-size: 19px; line-height: 25px; color: #0B0C0C;">'
        '{}'
        '</p>'
    ).format(expected_html)
    assert expected_html_in_template in str(HTMLEmailTemplate({'content': url, 'subject': ''}))
def test_urls_get_escaped(url, expected_html, expected_html_in_template):
    assert notify_email_markdown(url) == (PARAGRAPH_TEXT).format(expected_html)
    assert expected_html_in_template in str(
        HTMLEmailTemplate({
            'content': url,
            'subject': ''
        }))
Beispiel #5
0
def send_email_to_provider(notification):
    service = notification.service
    if not service.active:
        technical_failure(notification=notification)
        return
    if notification.status == 'created':
        provider = provider_to_use(EMAIL_TYPE, notification.id)
        current_app.logger.debug(
            "Starting sending EMAIL {} to provider at {}".format(notification.id, datetime.utcnow())
        )
        template_dict = dao_get_template_by_id(notification.template_id, notification.template_version).__dict__

        html_email = HTMLEmailTemplate(
            template_dict,
            values=notification.personalisation,
            **get_html_email_options(service)
        )

        plain_text_email = PlainTextEmailTemplate(
            template_dict,
            values=notification.personalisation
        )

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            reference = str(create_uuid())
            notification.billable_units = 0
            notification.reference = reference
            update_notification(notification, provider)
            send_email_response(reference, notification.to)
        else:
            from_address = '"{}" <{}@{}>'.format(service.name, service.email_from,
                                                 current_app.config['NOTIFY_EMAIL_DOMAIN'])

            email_reply_to = notification.reply_to_text

            reference, status = provider.send_email(
                from_address,
                validate_and_format_email_address(notification.to),
                plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=validate_and_format_email_address(email_reply_to) if email_reply_to else None,
            )
            notification.reference = reference
            update_notification(notification, provider, status=status)

        current_app.logger.debug("SENT_MAIL: {} -- {}".format(
            validate_and_format_email_address(notification.to),
            str(plain_text_email))
        )
        current_app.logger.debug(
            "Email {} sent to provider at {}".format(notification.id, notification.sent_at)
        )
        delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000
        statsd_client.timing("email.total-time", delta_milliseconds)
def send_email_to_provider(notification):
    service = notification.service
    if not service.active:
        technical_failure(notification=notification)
        return
    if notification.status == 'created':
        provider = provider_to_use(EMAIL_TYPE)

        template_dict = dao_get_template_by_id(
            notification.template_id, notification.template_version).__dict__

        html_email = HTMLEmailTemplate(template_dict,
                                       values=notification.personalisation,
                                       **get_html_email_options(service))

        plain_text_email = PlainTextEmailTemplate(
            template_dict, values=notification.personalisation)

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = str(create_uuid())
            update_notification_to_sending(notification, provider)
            send_email_response(notification.reference, notification.to)
        else:
            from_address = '"{}" <{}@{}>'.format(
                service.name, service.email_from,
                current_app.config['NOTIFY_EMAIL_DOMAIN'])

            email_reply_to = notification.reply_to_text

            reference = provider.send_email(
                from_address,
                validate_and_format_email_address(notification.to),
                plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=validate_and_format_email_address(
                    email_reply_to) if email_reply_to else None,
            )
            notification.reference = reference
            update_notification_to_sending(notification, provider)

        delta_seconds = (datetime.utcnow() -
                         notification.created_at).total_seconds()

        if notification.key_type == KEY_TYPE_TEST:
            statsd_client.timing("email.test-key.total-time", delta_seconds)
        else:
            statsd_client.timing("email.live-key.total-time", delta_seconds)
            if str(service.id) in current_app.config.get(
                    'HIGH_VOLUME_SERVICE'):
                statsd_client.timing("email.live-key.high-volume.total-time",
                                     delta_seconds)
            else:
                statsd_client.timing(
                    "email.live-key.not-high-volume.total-time", delta_seconds)
Beispiel #7
0
def test_escaping_govuk_in_email_templates():
    template_content = "GOV.UK"
    expected = "GOV.\u200BUK"
    assert unlink_govuk_escaped(template_content) == expected
    template_json = {
        'content': template_content,
        'subject': '',
        'template_type': 'email'
    }
    assert expected in str(PlainTextEmailTemplate(template_json))
    assert expected in str(HTMLEmailTemplate(template_json))
Beispiel #8
0
def test_HTML_template_has_URLs_replaced_with_links():
    assert (
        '<a style="word-wrap: break-word;" href="https://service.example.com/accept_invite/a1b2c3d4">'
        'https://service.example.com/accept_invite/a1b2c3d4'
        '</a>'
    ) in str(HTMLEmailTemplate({'content': (
        'You’ve been invited to a service. Click this link:\n'
        'https://service.example.com/accept_invite/a1b2c3d4\n'
        '\n'
        'Thanks\n'
    ), 'subject': ''}))
def test_brand_banner_shows():
    email = str(HTMLEmailTemplate(
        {'content': 'hello world', 'subject': ''},
        brand_banner=True,
        govuk_banner=False
    ))
    assert (
        '<td width="10" height="10" valign="middle"></td>'
    ) not in email
    assert (
        'role="presentation" width="100%" style="min-width: 100%;width: 100% !important;"'
    ) in email
Beispiel #10
0
def test_escaping_govuk_in_email_templates(template_content, expected):
    assert unlink_govuk_escaped(template_content) == expected
    assert expected in str(
        PlainTextEmailTemplate({
            'content': template_content,
            'subject': ''
        }))
    assert expected in str(
        HTMLEmailTemplate({
            'content': template_content,
            'subject': ''
        }))
def test_brand_data_shows(brand_logo, brand_name, brand_colour):
    email = str(HTMLEmailTemplate(
        {'content': 'hello world', 'subject': ''},
        brand_banner=True,
        govuk_banner=False,
        brand_logo=brand_logo,
        brand_name=brand_name,
        brand_colour=brand_colour
    ))

    assert 'GOV.UK' not in email
    if brand_logo:
        assert brand_logo in email
    if brand_name:
        assert brand_name in email
    if brand_colour:
        assert 'bgcolor="{}"'.format(brand_colour) in email
def email_template():
    return str(
        HTMLEmailTemplate(
            {
                'subject':
                'foo',
                'content':
                ('Lorem Ipsum is simply dummy text of the printing and typesetting '
                 'industry.\n\nLorem Ipsum has been the industry’s standard dummy '
                 'text ever since the 1500s, when an unknown printer took a galley '
                 'of type and scrambled it to make a type specimen book. '
                 '\n\n'
                 '# History'
                 '\n\n'
                 'It has '
                 'survived not only'
                 '\n\n'
                 '* five centuries'
                 '\n'
                 '* but also the leap into electronic typesetting'
                 '\n\n'
                 'It was '
                 'popularised in the 1960s with the release of Letraset sheets '
                 'containing Lorem Ipsum passages, and more recently with desktop '
                 'publishing software like Aldus PageMaker including versions of '
                 'Lorem Ipsum.'
                 '\n\n'
                 '^ It is a long established fact that a reader will be distracted '
                 'by the readable content of a page when looking at its layout.'
                 '\n\n'
                 'The point of using Lorem Ipsum is that it has a more-or-less '
                 'normal distribution of letters, as opposed to using ‘Content '
                 'here, content here’, making it look like readable English.'
                 '\n\n\n'
                 '1. One'
                 '\n'
                 '2. Two'
                 '\n'
                 '10. Three'
                 '\n\n'
                 'This is an example of an email sent using GOV.UK Notify.'
                 '\n\n'
                 'https://www.notifications.service.gov.uk')
            },
            govuk_banner=convert_to_boolean(
                request.args.get('govuk_banner', True))))
def send_email_to_provider(notification):
    service = notification.service
    if not service.active:
        technical_failure(notification=notification)
        return

    # TODO: no else - replace with if statement raising error / logging when not 'created'
    if notification.status == 'created':
        provider = provider_to_use(notification)

        # TODO: remove that code or extract attachment handling to separate method
        # Extract any file objects from the personalization
        file_keys = [
            k for k, v in (notification.personalisation or {}).items()
            if isinstance(v, dict) and 'document' in v
        ]
        attachments = []

        personalisation_data = notification.personalisation.copy()

        for key in file_keys:

            # Check if a MLWR sid exists
            if (current_app.config["MLWR_HOST"]
                    and 'mlwr_sid' in personalisation_data[key]['document']
                    and personalisation_data[key]['document']['mlwr_sid'] !=
                    "false"):

                mlwr_result = check_mlwr(
                    personalisation_data[key]['document']['mlwr_sid'])

                if "state" in mlwr_result and mlwr_result[
                        "state"] == "completed":
                    # Update notification that it contains malware
                    if "submission" in mlwr_result and mlwr_result[
                            "submission"]['max_score'] >= 500:
                        malware_failure(notification=notification)
                        return
                else:
                    # Throw error so celery will retry in sixty seconds
                    raise MalwarePendingException

            try:
                response = requests.get(
                    personalisation_data[key]['document']['direct_file_url'])
                if response.headers['Content-Type'] == 'application/pdf':
                    attachments.append({
                        "name": "{}.pdf".format(key),
                        "data": response.content
                    })
            except Exception:
                current_app.logger.error(
                    "Could not download and attach {}".format(
                        personalisation_data[key]['document']
                        ['direct_file_url']))

            personalisation_data[key] = personalisation_data[key]['document'][
                'url']

        template_dict = dao_get_template_by_id(
            notification.template_id, notification.template_version).__dict__

        html_email = HTMLEmailTemplate(template_dict,
                                       values=personalisation_data,
                                       **get_html_email_options(
                                           notification, provider))

        plain_text_email = PlainTextEmailTemplate(template_dict,
                                                  values=personalisation_data)

        if current_app.config["SCAN_FOR_PII"]:
            contains_pii(notification, str(plain_text_email))

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = str(create_uuid())
            update_notification_to_sending(notification, provider)
            send_email_response(notification.reference, notification.to)
        else:
            email_reply_to = notification.reply_to_text

            reference = provider.send_email(
                source=compute_source_email_address(service, provider),
                to_addresses=validate_and_format_email_address(
                    notification.to),
                subject=plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=validate_and_format_email_address(
                    email_reply_to) if email_reply_to else None,
                attachments=attachments)
            notification.reference = reference
            update_notification_to_sending(notification, provider)
            current_app.logger.info(
                f"Saved provider reference: {reference} for notification id: {notification.id}"
            )

        delta_milliseconds = (datetime.utcnow() -
                              notification.created_at).total_seconds() * 1000
        statsd_client.timing("email.total-time", delta_milliseconds)
Beispiel #14
0
def email_template():
    branding_type = "fip_english"
    branding_style = request.args.get("branding_style", None)

    if (
        branding_style == FieldWithLanguageOptions.ENGLISH_OPTION_VALUE
        or branding_style == FieldWithLanguageOptions.FRENCH_OPTION_VALUE
    ):
        if branding_style == FieldWithLanguageOptions.FRENCH_OPTION_VALUE:
            branding_type = "fip_french"
        branding_style = None

    if branding_style is not None:
        email_branding = email_branding_client.get_email_branding(branding_style)["email_branding"]
        branding_type = email_branding["brand_type"]

    if branding_type == "fip_english":
        brand_text = None
        brand_colour = None
        brand_logo = None
        fip_banner_english = True
        fip_banner_french = False
        logo_with_background_colour = False
        brand_name = None
    elif branding_type == "fip_french":
        brand_text = None
        brand_colour = None
        brand_logo = None
        fip_banner_english = False
        fip_banner_french = True
        logo_with_background_colour = False
        brand_name = None
    else:
        colour = email_branding["colour"]
        brand_text = email_branding["text"]
        brand_colour = colour
        brand_logo = "https://{}/{}".format(get_logo_cdn_domain(), email_branding["logo"]) if email_branding["logo"] else None
        fip_banner_english = branding_type in ["fip_english", "both_english"]
        fip_banner_french = branding_type in ["fip_french", "both_french"]
        logo_with_background_colour = branding_type == "custom_logo_with_background_colour"
        brand_name = email_branding["name"]

    template = {
        "subject": "foo",
        "content": (
            "Lorem Ipsum is simply dummy text of the printing and typesetting "
            "industry.\n\nLorem Ipsum has been the industry’s standard dummy "
            "text ever since the 1500s, when an unknown printer took a galley "
            "of type and scrambled it to make a type specimen book. "
            "\n\n"
            "# History"
            "\n\n"
            "It has "
            "survived not only"
            "\n\n"
            "* five centuries"
            "\n"
            "* but also the leap into electronic typesetting"
            "\n\n"
            "It was "
            "popularised in the 1960s with the release of Letraset sheets "
            "containing Lorem Ipsum passages, and more recently with desktop "
            "publishing software like Aldus PageMaker including versions of "
            "Lorem Ipsum."
            "\n\n"
            "^ It is a long established fact that a reader will be distracted "
            "by the readable content of a page when looking at its layout."
            "\n\n"
            "The point of using Lorem Ipsum is that it has a more-or-less "
            "normal distribution of letters, as opposed to using ‘Content "
            "here, content here’, making it look like readable English."
            "\n\n\n"
            "1. One"
            "\n"
            "2. Two"
            "\n"
            "10. Three"
            "\n\n"
            "This is an example of an email sent using Notification."
            "\n\n"
            "https://www.notifications.service.gov.uk"
        ),
    }

    if not bool(request.args):
        resp = make_response(str(HTMLEmailTemplate(template)))
    else:
        resp = make_response(
            str(
                HTMLEmailTemplate(
                    template,
                    fip_banner_english=fip_banner_english,
                    fip_banner_french=fip_banner_french,
                    brand_text=brand_text,
                    brand_colour=brand_colour,
                    brand_logo=brand_logo,
                    logo_with_background_colour=logo_with_background_colour,
                    brand_name=brand_name,
                )
            )
        )

    resp.headers["X-Frame-Options"] = "SAMEORIGIN"
    return resp
def test_subject_is_cleaned_up(subject, expected):
    assert expected == HTMLEmailTemplate({'content': '', 'subject': subject}).subject
Beispiel #16
0
def email_template():
    branding_type = 'govuk'
    branding_style = request.args.get('branding_style', None)

    if branding_style == FieldWithNoneOption.NONE_OPTION_VALUE:
        branding_style = None

    if branding_style is not None:
        email_branding = email_branding_client.get_email_branding(
            branding_style)['email_branding']
        branding_type = email_branding['brand_type']

    if branding_type == 'govuk':
        brand_text = None
        brand_colour = None
        brand_logo = None
        govuk_banner = True
        brand_banner = False
        brand_name = None
    else:
        colour = email_branding['colour']
        brand_text = email_branding['text']
        brand_colour = colour
        brand_logo = ('https://{}/{}'.format(get_logo_cdn_domain(),
                                             email_branding['logo'])
                      if email_branding['logo'] else None)
        govuk_banner = branding_type in ['govuk', 'both']
        brand_banner = branding_type == 'org_banner'
        brand_name = email_branding['name']

    template = {
        'template_type':
        'email',
        'subject':
        'foo',
        'content':
        ('Lorem Ipsum is simply dummy text of the printing and typesetting '
         'industry.\n\nLorem Ipsum has been the industry’s standard dummy '
         'text ever since the 1500s, when an unknown printer took a galley '
         'of type and scrambled it to make a type specimen book. '
         '\n\n'
         '# History'
         '\n\n'
         'It has '
         'survived not only'
         '\n\n'
         '* five centuries'
         '\n'
         '* but also the leap into electronic typesetting'
         '\n\n'
         'It was '
         'popularised in the 1960s with the release of Letraset sheets '
         'containing Lorem Ipsum passages, and more recently with desktop '
         'publishing software like Aldus PageMaker including versions of '
         'Lorem Ipsum.'
         '\n\n'
         '^ It is a long established fact that a reader will be distracted '
         'by the readable content of a page when looking at its layout.'
         '\n\n'
         'The point of using Lorem Ipsum is that it has a more-or-less '
         'normal distribution of letters, as opposed to using ‘Content '
         'here, content here’, making it look like readable English.'
         '\n\n\n'
         '1. One'
         '\n'
         '2. Two'
         '\n'
         '10. Three'
         '\n\n'
         'This is an example of an email sent using GOV.UK Notify.'
         '\n\n'
         'https://www.notifications.service.gov.uk')
    }

    if not bool(request.args):
        resp = make_response(str(HTMLEmailTemplate(template)))
    else:
        resp = make_response(
            str(
                HTMLEmailTemplate(
                    template,
                    govuk_banner=govuk_banner,
                    brand_text=brand_text,
                    brand_colour=brand_colour,
                    brand_logo=brand_logo,
                    brand_banner=brand_banner,
                    brand_name=brand_name,
                )))

    resp.headers['X-Frame-Options'] = 'SAMEORIGIN'
    return resp
Beispiel #17
0
def send_email_to_provider(notification):
    service = notification.service
    if not service.active:
        technical_failure(notification=notification)
        return
    if notification.status == 'created':
        provider = provider_to_use(EMAIL_TYPE, notification.id)

        # Extract any file objects from the personalization
        file_keys = [
            k for k, v in (notification.personalisation or {}).items() if isinstance(v, dict) and 'document' in v
        ]
        attachments = []

        personalisation_data = notification.personalisation.copy()

        for key in file_keys:

            # Check if a MLWR sid exists
            if (current_app.config["MLWR_HOST"] and
                    'mlwr_sid' in personalisation_data[key]['document'] and
                    personalisation_data[key]['document']['mlwr_sid'] != "false"):

                mlwr_result = check_mlwr(personalisation_data[key]['document']['mlwr_sid'])

                if "state" in mlwr_result and mlwr_result["state"] == "completed":
                    # Update notification that it contains malware
                    if "submission" in mlwr_result and mlwr_result["submission"]['max_score'] >= 500:
                        malware_failure(notification=notification)
                        return
                else:
                    # Throw error so celery will retry in sixty seconds
                    raise MalwarePendingException

            try:
                req = urllib.request.Request(personalisation_data[key]['document']['direct_file_url'])
                with urllib.request.urlopen(req) as response:
                    buffer = response.read()
                    mime_type = magic.from_buffer(buffer, mime=True)
                    if mime_type == 'application/pdf':
                        attachments.append({"name": "{}.pdf".format(key), "data": buffer})
            except Exception:
                current_app.logger.error(
                    "Could not download and attach {}".format(personalisation_data[key]['document']['direct_file_url'])
                )

            personalisation_data[key] = personalisation_data[key]['document']['url']

        template_dict = dao_get_template_by_id(notification.template_id, notification.template_version).__dict__

        html_email = HTMLEmailTemplate(
            template_dict,
            values=personalisation_data,
            **get_html_email_options(service)
        )

        plain_text_email = PlainTextEmailTemplate(
            template_dict,
            values=personalisation_data
        )

        if current_app.config["SCAN_FOR_PII"]:
            contains_pii(notification, str(plain_text_email))

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = str(create_uuid())
            update_notification_to_sending(notification, provider)
            send_email_response(notification.reference, notification.to)
        else:
            if service.sending_domain is None or service.sending_domain.strip() == "":
                sending_domain = current_app.config['NOTIFY_EMAIL_DOMAIN']
            else:
                sending_domain = service.sending_domain

            from_address = '"{}" <{}@{}>'.format(service.name, service.email_from,
                                                 sending_domain)

            email_reply_to = notification.reply_to_text

            reference = provider.send_email(
                from_address,
                validate_and_format_email_address(notification.to),
                plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=validate_and_format_email_address(email_reply_to) if email_reply_to else None,
                attachments=attachments
            )
            notification.reference = reference
            update_notification_to_sending(notification, provider)

        delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000
        statsd_client.timing("email.total-time", delta_milliseconds)
def send_email_to_provider(notification):
    service = notification.service
    if not service.active:
        technical_failure(notification=notification)
        return
    if notification.status == "created":
        provider = provider_to_use(EMAIL_TYPE, notification.id)

        # Extract any file objects from the personalization
        file_keys = [
            k for k, v in (notification.personalisation or {}).items()
            if isinstance(v, dict) and "document" in v
        ]
        attachments = []

        personalisation_data = notification.personalisation.copy()

        for key in file_keys:
            sending_method = personalisation_data[key]["document"].get(
                "sending_method")
            # Check if a MLWR sid exists
            if (current_app.config["MLWR_HOST"]
                    and "mlwr_sid" in personalisation_data[key]["document"]
                    and personalisation_data[key]["document"]["mlwr_sid"] !=
                    "false"):

                mlwr_result = check_mlwr(
                    personalisation_data[key]["document"]["mlwr_sid"])

                if "state" in mlwr_result and mlwr_result[
                        "state"] == "completed":
                    # Update notification that it contains malware
                    if "submission" in mlwr_result and mlwr_result[
                            "submission"]["max_score"] >= 500:
                        malware_failure(notification=notification)
                        return
                else:
                    # Throw error so celery will retry in sixty seconds
                    raise MalwarePendingException

            if sending_method == "attach":
                try:

                    req = urllib.request.Request(
                        personalisation_data[key]["document"]
                        ["direct_file_url"])
                    with urllib.request.urlopen(req) as response:
                        buffer = response.read()
                        filename = personalisation_data[key]["document"].get(
                            "filename")
                        mime_type = personalisation_data[key]["document"].get(
                            "mime_type")
                        attachments.append({
                            "name": filename,
                            "data": buffer,
                            "mime_type": mime_type,
                        })
                except Exception:
                    current_app.logger.error(
                        "Could not download and attach {}".format(
                            personalisation_data[key]["document"]
                            ["direct_file_url"]))
                del personalisation_data[key]
            else:
                personalisation_data[key] = personalisation_data[key][
                    "document"]["url"]

        template_dict = dao_get_template_by_id(
            notification.template_id, notification.template_version).__dict__

        # Local Jinja support - Add USE_LOCAL_JINJA_TEMPLATES=True to .env
        # Add a folder to the project root called 'jinja_templates'
        # with a copy of 'email_template.jinja2' from notification-utils repo
        debug_template_path = (
            os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            if os.environ.get("USE_LOCAL_JINJA_TEMPLATES") == "True" else None)

        html_email = HTMLEmailTemplate(
            template_dict,
            values=personalisation_data,
            jinja_path=debug_template_path,
            **get_html_email_options(service),
        )

        plain_text_email = PlainTextEmailTemplate(template_dict,
                                                  values=personalisation_data)

        if current_app.config["SCAN_FOR_PII"]:
            contains_pii(notification, str(plain_text_email))

        if service.research_mode or notification.key_type == KEY_TYPE_TEST:
            notification.reference = send_email_response(notification.to)
            update_notification_to_sending(notification, provider)
        else:
            if service.sending_domain is None or service.sending_domain.strip(
            ) == "":
                sending_domain = current_app.config["NOTIFY_EMAIL_DOMAIN"]
            else:
                sending_domain = service.sending_domain

            from_address = '"{}" <{}@{}>'.format(service.name,
                                                 service.email_from,
                                                 sending_domain)

            email_reply_to = notification.reply_to_text

            reference = provider.send_email(
                from_address,
                validate_and_format_email_address(notification.to),
                plain_text_email.subject,
                body=str(plain_text_email),
                html_body=str(html_email),
                reply_to_address=validate_and_format_email_address(
                    email_reply_to) if email_reply_to else None,
                attachments=attachments,
            )
            notification.reference = reference
            update_notification_to_sending(notification, provider)

        # Record StatsD stats to compute SLOs
        statsd_client.timing_with_dates("email.total-time",
                                        notification.sent_at,
                                        notification.created_at)
        attachments_category = "with-attachments" if attachments else "no-attachments"
        statsd_key = f"email.{attachments_category}.process_type-{template_dict['process_type']}"
        statsd_client.timing_with_dates(statsd_key, notification.sent_at,
                                        notification.created_at)
        statsd_client.incr(statsd_key)
 ),
 (
     SMSPreviewTemplate(
         {"content": "((content))", "subject": "((subject))"},
     ),
     ['content'],
 ),
 (
     PlainTextEmailTemplate(
         {"content": "((content))", "subject": "((subject))"},
     ),
     ['content', 'subject'],
 ),
 (
     HTMLEmailTemplate(
         {"content": "((content))", "subject": "((subject))"},
     ),
     ['content', 'subject'],
 ),
 (
     EmailPreviewTemplate(
         {"content": "((content))", "subject": "((subject))"},
     ),
     ['content', 'subject'],
 ),
 (
     LetterPreviewTemplate(
         {"content": "((content))", "subject": "((subject))"},
         contact_block='((contact_block))',
     ),
     ['content', 'subject', 'contact_block'],
def test_makes_links_out_of_URLs(url, url_with_entities_replaced):
    link = '<a style="word-wrap: break-word;" href="{}">{}</a>'.format(
        url_with_entities_replaced, url_with_entities_replaced
    )
    assert link in str(HTMLEmailTemplate({'content': url, 'subject': ''}))
    assert link in str(EmailPreviewTemplate({'content': url, 'subject': ''}))
def test_default_template(content):
    assert content in str(HTMLEmailTemplate({'content': 'hello world', 'subject': ''}))
def test_html_email_inserts_body():
    assert 'the &lt;em&gt;quick&lt;/em&gt; brown fox' in str(HTMLEmailTemplate(
        {'content': 'the <em>quick</em> brown fox', 'subject': ''}
    ))