Skip to content

Commit

Permalink
Resolved issue #22: Sending HTML emails
Browse files Browse the repository at this point in the history
  • Loading branch information
apragacz committed Jun 14, 2018
1 parent 5b2e0c3 commit ce8cbe4
Show file tree
Hide file tree
Showing 14 changed files with 454 additions and 44 deletions.
4 changes: 2 additions & 2 deletions rest_registration/api/views/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
api_view_serializer_class_getter
)
from rest_registration.exceptions import BadRequest
from rest_registration.notifications import send_verification
from rest_registration.notifications import send_verification_notification
from rest_registration.settings import registration_settings
from rest_registration.utils import (
get_ok_response,
Expand Down Expand Up @@ -65,7 +65,7 @@ def register(request):
}, request=request)
template_config = (
registration_settings.REGISTER_VERIFICATION_EMAIL_TEMPLATES)
send_verification(user, signer, template_config)
send_verification_notification(user, signer, template_config)

return Response(user_data, status=status.HTTP_201_CREATED)

Expand Down
5 changes: 3 additions & 2 deletions rest_registration/api/views/register_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from rest_framework.permissions import IsAuthenticated

from rest_registration.decorators import api_view_serializer_class
from rest_registration.notifications import send_verification
from rest_registration.notifications import send_verification_notification
from rest_registration.settings import registration_settings
from rest_registration.utils import (
get_ok_response,
Expand Down Expand Up @@ -53,7 +53,8 @@ def register_email(request):
'user_id': user.pk,
'email': email,
}, request=request)
send_verification(user, signer, template_config, email=email)
send_verification_notification(
user, signer, template_config, email=email)
else:
email_field = get_user_setting('EMAIL_FIELD')
setattr(user, email_field, email)
Expand Down
4 changes: 2 additions & 2 deletions rest_registration/api/views/reset_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from rest_registration.decorators import api_view_serializer_class
from rest_registration.exceptions import UserNotFound
from rest_registration.notifications import send_verification
from rest_registration.notifications import send_verification_notification
from rest_registration.settings import registration_settings
from rest_registration.utils import (
get_ok_response,
Expand Down Expand Up @@ -65,7 +65,7 @@ def send_reset_password_link(request):

template_config = (
registration_settings.RESET_PASSWORD_VERIFICATION_EMAIL_TEMPLATES)
send_verification(user, signer, template_config)
send_verification_notification(user, signer, template_config)

return get_ok_response('Reset link sent')

Expand Down
6 changes: 5 additions & 1 deletion rest_registration/notifications/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
from .email import send_verification # noqa
from .email import ( # noqa: F401
create_verification_notification,
send_notification,
send_verification_notification,
)
201 changes: 186 additions & 15 deletions rest_registration/notifications/email.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,200 @@
from django.core.mail.message import EmailMessage
from django.template.loader import get_template
from collections import namedtuple

from django.core.exceptions import ImproperlyConfigured
from django.core.mail.message import EmailMultiAlternatives
from django.template.exceptions import TemplateDoesNotExist
from django.template.loader import get_template, render_to_string

from rest_registration.settings import registration_settings
from rest_registration.utils import get_user_setting
from rest_registration.utils import (
get_user_setting,
strip_tags_preserving_urls
)

EmailTemplateConfig = namedtuple('EmailTemplateConfig', (
'subject_template_name',
'text_body_template_name',
'html_body_template_name',
))


def send_verification_notification(
user, params_signer, template_config_data, email=None):
notification = create_verification_notification(
user, params_signer, template_config_data, email=email)
send_notification(notification)

def send_verification(user, params_signer, template_config, email=None):

def create_verification_notification(
user, params_signer, template_config_data, email=None):
if email is None:
email_field = get_user_setting('EMAIL_FIELD')
email = getattr(user, email_field)
body_template = get_template(template_config['body'])
subject_template = get_template(template_config['subject'])

from_email = registration_settings.VERIFICATION_FROM_EMAIL
reply_to_email = (registration_settings.VERIFICATION_REPLY_TO_EMAIL or
from_email)
ctx = {
context = {
'user': user,
'email': email,
'verification_url': params_signer.get_url(),
}
subject = subject_template.render(ctx).strip()
body = body_template.render(ctx)

email_msg = EmailMessage(
subject, body,
from_email, [email], reply_to=[reply_to_email],
)
email_msg.send()
template_config = parse_template_config(template_config_data)

subject = render_to_string(
template_config.subject_template_name, context=context).strip()
text_body = convert_html_to_text(
render_to_string(
template_config.text_body_template_name, context=context))

email_msg = EmailMultiAlternatives(
subject, text_body, from_email, [email], reply_to=[reply_to_email])

if template_config.html_body_template_name:
html_body = render_to_string(
template_config.html_body_template_name, context=context)
email_msg.attach_alternative(html_body, 'text/html')

return email_msg


def parse_template_config(template_config_data):
"""
>>> from tests import doctest_utils
>>> parse_template_config({}) # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ImproperlyConfigured
>>> parse_template_config({
... 'subject': 'blah',
... }) # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ImproperlyConfigured
>>> parse_template_config({
... 'subject': 'blah',
... 'body': 'blah',
... }) # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ImproperlyConfigured
>>> doctest_utils.equals(
... parse_template_config({
... 'subject': 'rest_registration/register/subject.txt',
... 'html_body': 'rest_registration/register/body.html',
... 'text_body': 'rest_registration/register/body.txt',
... }),
... EmailTemplateConfig(
... 'rest_registration/register/subject.txt',
... 'rest_registration/register/body.txt',
... 'rest_registration/register/body.html'))
OK
>>> doctest_utils.equals(
... parse_template_config({
... 'subject': 'rest_registration/register/subject.txt',
... 'html_body': 'rest_registration/register/body.html',
... }),
... EmailTemplateConfig(
... 'rest_registration/register/subject.txt',
... 'rest_registration/register/body.html',
... 'rest_registration/register/body.html'))
OK
>>> doctest_utils.equals(
... parse_template_config({
... 'subject': 'rest_registration/register/subject.txt',
... 'text_body': 'rest_registration/register/body.txt',
... }),
... EmailTemplateConfig(
... 'rest_registration/register/subject.txt',
... 'rest_registration/register/body.txt', None))
OK
>>> doctest_utils.equals(
... parse_template_config({
... 'subject': 'rest_registration/register/subject.txt',
... 'body': 'rest_registration/register/body.txt',
... }),
... EmailTemplateConfig(
... 'rest_registration/register/subject.txt',
... 'rest_registration/register/body.txt', None))
OK
>>> doctest_utils.equals(
... parse_template_config({
... 'subject': 'rest_registration/register/subject.txt',
... 'body': 'rest_registration/register/body.html',
... 'is_html': True,
... }),
... EmailTemplateConfig(
... 'rest_registration/register/subject.txt',
... 'rest_registration/register/body.html',
... 'rest_registration/register/body.html'))
OK
"""
try:
subject_template_name = template_config_data['subject']
except KeyError:
raise ImproperlyConfigured("No 'subject' key found")
body_template_name = template_config_data.get('body')
text_body_template_name = template_config_data.get('text_body')
html_body_template_name = template_config_data.get('html_body')
is_html_body = template_config_data.get('is_html')

if html_body_template_name and text_body_template_name:
config = EmailTemplateConfig(
subject_template_name=subject_template_name,
text_body_template_name=text_body_template_name,
html_body_template_name=html_body_template_name,
)
elif html_body_template_name:
config = EmailTemplateConfig(
subject_template_name=subject_template_name,
text_body_template_name=html_body_template_name,
html_body_template_name=html_body_template_name,
)
elif text_body_template_name:
config = EmailTemplateConfig(
subject_template_name=subject_template_name,
text_body_template_name=text_body_template_name,
html_body_template_name=None,
)
elif body_template_name:
if is_html_body:
config = EmailTemplateConfig(
subject_template_name=subject_template_name,
text_body_template_name=body_template_name,
html_body_template_name=body_template_name,
)
else:
config = EmailTemplateConfig(
subject_template_name=subject_template_name,
text_body_template_name=body_template_name,
html_body_template_name=None,
)
else:
raise ImproperlyConfigured(
'Could not parse template config data: {template_config_data}'.format( # noqa: E501
template_config_data=template_config_data))

_validate_template_name_existence(config.subject_template_name)
_validate_template_name_existence(config.text_body_template_name)

if config.html_body_template_name:
_validate_template_name_existence(config.html_body_template_name)

return config


def _validate_template_name_existence(template_name):
try:
get_template(template_name)
except TemplateDoesNotExist:
raise ImproperlyConfigured(
'Template {template_name!r} does not exists'.format(
template_name=template_name))


def convert_html_to_text(html):
return strip_tags_preserving_urls(html)


def send_notification(notification):
notification.send()
13 changes: 13 additions & 0 deletions rest_registration/templates/rest_registration/register/body.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Please verify your account</title>
</head>
<body>
<p>
Please verify your account by clicking
<a href="{{ verification_url | safe }}">here</a>.
</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Please verify new e-mail</title>
</head>
<body>
<p>
You can verify the email {{ email }} by clicking
<a href="{{ verification_url | safe }}">here</a>.
</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
E-mail verification link was sent
Please verify new e-mail
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Reset password link was sent</title>
</head>
<body>
<p>
You can reset your password by clicking
<a href="{{ verification_url | safe }}">here</a>.
</p>
</body>
</html>

0 comments on commit ce8cbe4

Please sign in to comment.