Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email HTML templates #1673

Merged
merged 35 commits into from
Feb 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0926346
Add premailer to requirements
mad-anne Jan 24, 2018
904a935
Add custom template backend for emails
mad-anne Jan 24, 2018
1caf265
Add base HTML for email templates
mad-anne Jan 24, 2018
1836869
Add styles to emails
mad-anne Jan 24, 2018
363126a
Add HTML template for order confirmation e-mail
mad-anne Jan 24, 2018
ff510b8
Add note confirmation HTML e-mail
mad-anne Jan 24, 2018
8e4d957
Fix sending order confirmation e-mails asynchronously
mad-anne Jan 29, 2018
4c45cdb
Improve text e-mail about order confirmation
mad-anne Jan 29, 2018
8c7b002
Conditionally display order's shipping_address in e-mails
mad-anne Jan 29, 2018
b7b31e6
Add HTML template for payment confirmation e-mail
mad-anne Jan 29, 2018
3024170
Dashboard staff HTML e-mail templates
mad-anne Jan 29, 2018
b04dfc6
Add MJML to package.json
mad-anne Jan 30, 2018
6f4e49a
Remove CustomTemplateBackend with premailer
mad-anne Jan 30, 2018
f21c76c
Add shared MJML footer and header
mad-anne Jan 30, 2018
e97ee2e
Use MJML for order confirmation e-mail
mad-anne Jan 30, 2018
02ee5b7
Remove simple HTML templates for order confirmation
mad-anne Jan 30, 2018
7dcf42b
Fix calculating subtotal in e-mails
mad-anne Jan 30, 2018
a252ee9
Remove green color from e-mails' header
mad-anne Jan 30, 2018
8869209
Use MJML for note confirmation e-mail
mad-anne Jan 30, 2018
66f7d7a
Use MJML for payment confirmation e-mail
mad-anne Jan 30, 2018
831085a
Use MJML for promote customer to staff confirmation e-mail
mad-anne Jan 30, 2018
047ae8b
Use MJML for promote customer to staff set up password e-mail
mad-anne Jan 30, 2018
7ce7b84
Remove unused statics
mad-anne Jan 30, 2018
011a58e
Fix failing e-mail tests
mad-anne Jan 30, 2018
ab23677
Remove redundant space
mad-anne Feb 1, 2018
702947c
Remove precompiled templates from repository
mad-anne Feb 1, 2018
6a9d1d1
Add script for compiling e-mails
mad-anne Feb 1, 2018
d173177
Add compiling e-mails installation step to docs
mad-anne Feb 1, 2018
8d8ef3d
Add link to dashboard in promote customer e-mail
mad-anne Feb 1, 2018
6f63449
Use conditionally https in e-mail templates
mad-anne Feb 1, 2018
8ad8156
Add trimmed flag to translations
mad-anne Feb 1, 2018
7d0a29a
Add MJML template for password reset
mad-anne Feb 1, 2018
57cc454
Use templated mail in password reset view
mad-anne Feb 1, 2018
fd6ea4f
Remove unused PasswordSetUpForm
mad-anne Feb 1, 2018
bee6a90
Build e-mails in travis and circle
mad-anne Feb 1, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ dist/
/static/
/saleor/static/assets/
webpack-bundle.json
/templates/templated_email/html/compiled/
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ install:
- nvm install 8
- npm i
- npm run build-assets --production
- npm run build-emails
script:
- tox
env:
Expand Down
1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ machine:
dependencies:
pre:
- npm install
- npm run build-emails
- pip install -U pip
- pip install -r requirements.txt
override:
Expand Down
5 changes: 5 additions & 0 deletions docs/gettingstarted/installation-linux.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ Installation

$ npm run build-assets

#. Compile e-mails:

.. code-block:: bash

$ npm run build-emails

#. Start the development server:

Expand Down
5 changes: 5 additions & 0 deletions docs/gettingstarted/installation-macos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ Installation

$ npm run build-assets

#. Compile e-mails:

.. code-block:: bash

$ npm run build-emails

#. Start the development server:

Expand Down
5 changes: 5 additions & 0 deletions docs/gettingstarted/installation-windows.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ All commands need to be performed in either PowerShell or a Command Shell.

npm run build-assets

#. Compile e-mails:

.. code-block:: powershell

$ npm run build-emails

#. Start the development server:

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"eslint-plugin-standard": "^3.0.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"mjml": "^3.3.5",
"node-sass": "^4.7.2",
"postcss": "^6.0.11",
"postcss-loader": "^2.0.6",
Expand Down Expand Up @@ -88,6 +89,7 @@
"scripts": {
"build-assets": "node ./node_modules/webpack/bin/webpack.js -p --progress",
"heroku-postbuild": "npm run build-assets",
"start": "UV_THREADPOOL_SIZE=8 node ./node_modules/webpack/bin/webpack.js -d --watch --progress"
"start": "UV_THREADPOOL_SIZE=8 node ./node_modules/webpack/bin/webpack.js -d --watch --progress",
"build-emails": "mkdir -p templates/templated_email/html/compiled/ && find templates -name \"*.mjml\" -not -path \"templates/templated_email/html/source/*partials/*\" -not -path \"templates/templated_email/html/source/*shared/*\" -exec ./node_modules/.bin/mjml -l skip {} -o templates/templated_email/html/compiled/ \\;"
}
}
20 changes: 14 additions & 6 deletions saleor/dashboard/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@
from django.conf import settings
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import Site
from django.urls import reverse
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from templated_email import send_templated_mail

from ..core.utils import build_absolute_uri


@shared_task
def send_set_password_email(staff):
site = Site.objects.get_current()
ctx = {'protocol': 'http',
'domain': site.domain,
'site_name': site.name,
'uid': urlsafe_base64_encode(force_bytes(staff.pk)).decode(),
'token': default_token_generator.make_token(staff)}
ctx = {
'protocol': 'https' if settings.ENABLE_SSL else 'http',
'domain': site.domain,
'site_name': site.name,
'uid': urlsafe_base64_encode(force_bytes(staff.pk)).decode(),
'token': default_token_generator.make_token(staff)}
send_templated_mail(
template_name='dashboard/staff/set_password',
from_email=settings.DEFAULT_FROM_EMAIL,
Expand All @@ -25,7 +29,11 @@ def send_set_password_email(staff):
@shared_task
def send_promote_customer_to_staff_email(staff):
site = Site.objects.get_current()
ctx = {'domain': site.domain, 'site_name': site.name}
ctx = {
'protocol': 'https' if settings.ENABLE_SSL else 'http',
'domain': site.domain,
'url': build_absolute_uri(reverse('dashboard:index')),
'site_name': site.name}
send_templated_mail(
template_name='dashboard/staff/promote_customer',
from_email=settings.DEFAULT_FROM_EMAIL,
Expand Down
18 changes: 13 additions & 5 deletions saleor/order/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,27 @@
CONFIRM_NOTE_TEMPLATE = 'order/note/confirm_note'


def _send_confirmation(email, url, template):
def _send_confirmation(email, url, template, context=None):
site = Site.objects.get_current()
ctx = {
'protocol': 'https' if settings.ENABLE_SSL else 'http',
'site_name': site.name,
'domain': site.domain,
'url': url}
if context:
ctx.update(context)
send_templated_mail(
from_email=settings.ORDER_FROM_EMAIL,
recipient_list=[email],
context={'site_name': site.name,
'url': url},
context=ctx,
template_name=template)


@shared_task
def send_order_confirmation(email, url):
_send_confirmation(email, url, CONFIRM_ORDER_TEMPLATE)
def send_order_confirmation(email, url, order_pk):
from .models import Order
order = Order.objects.get(pk=order_pk)
_send_confirmation(email, url, CONFIRM_ORDER_TEMPLATE, {'order': order})


@shared_task
Expand Down
2 changes: 1 addition & 1 deletion saleor/order/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def send_confirmation_email(self):
email = self.get_user_current_email()
payment_url = build_absolute_uri(
reverse('order:details', kwargs={'token': self.token}))
emails.send_order_confirmation.delay(email, payment_url)
emails.send_order_confirmation.delay(email, payment_url, self.pk)

def get_last_payment_status(self):
last_payment = self.payments.last()
Expand Down
12 changes: 5 additions & 7 deletions saleor/registration/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django import forms
from django.contrib.auth import forms as django_forms
from django.http.request import HttpRequest
from django.urls import reverse
from django.utils.translation import pgettext, pgettext_lazy
from templated_email import send_templated_mail

from ..core.utils import build_absolute_uri
from ..userprofile.models import User


Expand Down Expand Up @@ -48,10 +48,8 @@ def save(self, request=None, commit=True):
return user


class PasswordSetUpForm(django_forms.PasswordResetForm):
"""
PasswordSetUpForm that overrides sending emails to use templated email.
Allows setting password for new users that have no usable password.
class PasswordResetForm(django_forms.PasswordResetForm):
"""PasswordResetForm that overrides sending emails to use templated email.
"""

def get_users(self, email):
Expand All @@ -61,11 +59,11 @@ def get_users(self, email):
def send_mail(
self, subject_template_name, email_template_name, context,
from_email, to_email, html_email_template_name=None):
reset_url = HttpRequest.build_absolute_uri(
reset_url = build_absolute_uri(
reverse(
'account_reset_password_confirm',
kwargs={'uidb64': context['uid'], 'token': context['token']}))
context['reset_url'] = reset_url
send_templated_mail(
'account/password_set', from_email=from_email,
'account/password_reset', from_email=from_email,
recipient_list=[to_email], context=context)
13 changes: 5 additions & 8 deletions saleor/registration/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
from django.utils.translation import ugettext_lazy as _

from ..cart.utils import find_and_assign_anonymous_cart
from .forms import LoginForm, PasswordSetUpForm, SignupForm
from .forms import LoginForm, PasswordResetForm, SignupForm


@find_and_assign_anonymous_cart()
def login(request):
kwargs = {
'template_name': 'account/login.html', 'authentication_form': LoginForm}
'template_name': 'account/login.html',
'authentication_form': LoginForm}
return django_views.LoginView.as_view(**kwargs)(request, **kwargs)


Expand Down Expand Up @@ -46,15 +47,13 @@ def password_reset(request):
kwargs = {
'template_name': 'account/password_reset.html',
'success_url': reverse_lazy('account_reset_password_done'),
'email_template_name': 'account/email/password_reset_message.txt',
'subject_template_name': 'account/email/password_reset_subject.txt'}
'form_class': PasswordResetForm}
return django_views.PasswordResetView.as_view(**kwargs)(request, **kwargs)


class PasswordResetConfirm(django_views.PasswordResetConfirmView):
template_name = 'account/password_reset_from_key.html'
success_url = reverse_lazy('account_reset_password_complete')
set_password_form = PasswordSetUpForm
token = None
uidb64 = None

Expand All @@ -63,8 +62,6 @@ def password_reset_confirm(request, uidb64=None, token=None):
kwargs = {
'template_name': 'account/password_reset_from_key.html',
'success_url': reverse_lazy('account_reset_password_complete'),
'set_password_form': 'PasswordSetUpForm',
'token': token,
'uidb64': uidb64}
return PasswordResetConfirm.as_view(**kwargs)(
request, **kwargs)
return PasswordResetConfirm.as_view(**kwargs)(request, **kwargs)
9 changes: 0 additions & 9 deletions templates/account/email/password_reset_message.txt

This file was deleted.

4 changes: 0 additions & 4 deletions templates/account/email/password_reset_subject.txt

This file was deleted.

27 changes: 27 additions & 0 deletions templates/templated_email/account/password_reset.email
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% load i18n %}

{% block subject %}
{% trans "Password reset e-mail" context "Password reset e-mail subject" %}
{% endblock %}

{% block plain %}
{% blocktrans context "Password reset e-mail text" %}
Hi!

You're receiving this e-mail because you or someone else has requested a password for your user account at {{ domain }}.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.
{% endblocktrans %}

{{ protocol}}://{{ domain }}{% url 'account_reset_password_confirm' uidb64=uid token=token %}

This is an automatically generated email, please do not reply.

{% blocktrans context "Password reset e-mail text" %}
Sincerely,
{{ site_name }}
{% endblocktrans %}
{% endblock %}

{% block html %}
{% include 'templated_email/html/compiled/password_reset.html' %}
{% endblock %}
13 changes: 10 additions & 3 deletions templates/templated_email/dashboard/staff/promote_customer.email
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
{% block subject %}{% blocktrans %}Hello from {{ site_name }}!{% endblocktrans %}{% endblock %}

{% block plain %}
{% blocktrans %}You're receiving this e-mail because you have been promoted to staff member at {{ domain }}.{% endblocktrans %}
{% blocktrans context "Promote customer to staff member confirmation e-mail text" %}
Hi!

{% blocktrans %}Thank you for using {{ site_name }}!
{{ domain }}
You're receiving this e-mail because you have been promoted to staff member at {{ domain }}.{% endblocktrans %}

{% blocktrans context "Promote customer to staff member confirmation e-mail text" %}
This is an automatically generated email, please do not reply.
{% endblocktrans %}
{% endblock %}

{% block html %}
{% include 'templated_email/html/compiled/promote_customer.html' %}
{% endblock %}
18 changes: 13 additions & 5 deletions templates/templated_email/dashboard/staff/set_password.email
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
{% load i18n %}
{% block subject %}{% blocktrans %}Hello from {{ site_name }}!{% endblocktrans %}{% endblock %}
{% block subject %}{% blocktrans context "Set password for staff member e-mail title" %}Hello from {{ site_name }}!{% endblocktrans %}{% endblock %}

{% block plain %}
{% blocktrans %}You're receiving this e-mail because you have to set password for your staff member account at {{ domain }}.
Click the link below to reset your password.{% endblocktrans %}
{% blocktrans context "Set password for staff member e-mail text" %}
Hi!

You're receiving this e-mail because you have to set password for your staff member account at {{ domain }}.
Click the link below to reset your password.
{% endblocktrans %}

{{ protocol}}://{{ domain }}{% url 'account_reset_password_confirm' uidb64=uid token=token %}

{% blocktrans %}Thank you for using {{ site_name }}!
{{ domain }}
{% blocktrans context "Set password for staff member e-mail text" %}
This is an automatically generated email, please do not reply.
{% endblocktrans %}
{% endblock %}

{% block html %}
{% include 'templated_email/html/compiled/set_password.html' %}
{% endblock %}
36 changes: 36 additions & 0 deletions templates/templated_email/html/source/account/password_reset.mjml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<mjml>
<mj-head>
<mj-include path="../shared/styles" />
</mj-head>
<mj-body>
<mj-container>
<mj-section css-class="no-display">
<mj-column>
<mj-text>
{% load i18n %}
</mj-text>
</mj-column>
</mj-section>
<mj-include path="../shared/header" />
<mj-section>
<mj-column>
<mj-text font-size="16px">
{% trans "Hi!" context "Password reset e-mail text" %}
</mj-text>
<mj-text>
{% blocktrans trimmed context "Password reset e-mail text" %}
You're receiving this e-mail because you or someone else has requested a password for your user account at {{ domain }}.<br/>
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.
{% endblocktrans %}
</mj-text>
<mj-text>
<a href="{{ protocol}}://{{ domain }}{% url 'account_reset_password_confirm' uidb64=uid token=token %}">
{{ protocol}}://{{ domain }}{% url 'account_reset_password_confirm' uidb64=uid token=token %}
</a>
</mj-text>
</mj-column>
</mj-section>
<mj-include path="../shared/footer" />
</mj-container>
</mj-body>
</mjml>