Django password_reset是否支持HTML电子邮件模板?

时间:2022-08-13 19:21:35

It seems to me django only supports plain text messages for password reset emails out of the box. How can I use html templates for this purpose?

在我看来,django只支持纯文本消息,用于开箱即用的密码重置电子邮件。我怎样才能将html模板用于此目的?

8 个解决方案

#1


6  

Here is how you can do the override:

urls.py

urls.py

url(r'^user/password/reset/$', 
    'YOUR_APP.views.password_reset', 
    {'post_reset_redirect' : '/#/login?resetemail=true'},
    name="password_reset"),

views.py

views.py

from django.contrib.auth.views import password_reset as django_password_reset
from YOUR_APP.forms import CustomPasswordResetForm

def password_reset(*args, **kwargs):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    kwargs['password_reset_form'] = CustomPasswordResetForm
    return django_password_reset(*args, **kwargs)

form.py

form.py

from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.tokens import default_token_generator

class CustomPasswordResetForm(PasswordResetForm):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator, request=None, email_subject_name='registration/password_reset_subject.txt', **kwargs):
        from django.core.mail import EmailMultiAlternatives
        from django.utils.html import strip_tags
        from django.template.loader import render_to_string
        from django.contrib.sites.models import get_current_site
        from django.utils.http import int_to_base36

        for user in self.users_cache:
            if not domain_override:
                current_site = get_current_site(request)
                site_name = current_site.name
                domain = current_site.domain
            else:
                 site_name = domain = domain_override

            c = {
                'email': user.email,
                'domain': domain,
                'site_name': site_name,
                'uid': int_to_base36(user.id),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': use_https and 'https' or 'http',
            }
            render = render_to_string(email_template_name, c)
            render_subject = render_to_string(email_subject_name, c)

            msg = EmailMultiAlternatives(render_subject, strip_tags(render), None, [user.email])
            msg.attach_alternative(render, "text/html")
            msg.send()

#2


5  

You can override save method of django.contrib.auth.forms.PasswordResetForm and pass new form as an argument to password_reset view.

您可以覆盖django.contrib.auth.forms.PasswordResetForm的save方法,并将新表单作为参数传递给password_reset视图。

#3


0  

After some amount of trial and error, I discovered a much, much more terse way to supply a custom templated password reset email in the latest version of Django (1.8).

经过一些试验和错误后,我发现了一种更简洁的方式来在最新版本的Django(1.8)中提供自定义模板化密码重置电子邮件。

In your project/urls.py, add these imports:

在您的project / urls.py中,添加以下导入:

from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse_lazy

And add the following route in your urlpatterns before the usual django contrib auth url route inclusion:

并在通常的django contrib auth url route包含之前在urlpatterns中添加以下路由:

url(r'^accounts/password/reset/$',
  auth_views.password_reset,
  {
    'post_reset_redirect': reverse_lazy('auth_password_reset_done'),
    'html_email_template_name': 'registration/password_reset_html_email.html'
  },
  name='auth_password_reset'),


url('^', include('django.contrib.auth.urls')),

And then, in your app's templates/registration folder, create the password_reset_html_email.html with whatever HTML template you want.

然后,在您的应用程序的模板/注册文件夹中,使用您想要的任何HTML模板创建password_reset_html_email.html。

The reason this seemed necessary lay in the source for django/contrib/auth/views.py, which has the view function the original URL route is mapped to:

这似乎是必要的原因在于django / contrib / auth / views.py的源代码,它具有原始URL路由映射到的view函数:

147 def password_reset(request, is_admin_site=False,
148                    template_name='registration/password_reset_form.html',
149                    email_template_name='registration/password_reset_email.html',
150                    subject_template_name='registration/password_reset_subject.txt',
151                    password_reset_form=PasswordResetForm,
152                    token_generator=default_token_generator,
153                    post_reset_redirect=None,
154                    from_email=None,
155                    current_app=None,
156                    extra_context=None,
157                    html_email_template_name=None):
158

The html_email_template_name is set to None as default, and there didn't seem to be a way to assign its value, aside from rewriting this specific route for this case as I mentioned above.

默认情况下,html_email_template_name设置为None,除了为此情况重写此特定路由之外,似乎没有办法分配其值,如上所述。

Hopefully this helps without needing to copy-paste a bunch of nearly-identical code like some of the other answers suggested - feedback is welcome, of course!

希望这有助于无需复制粘贴一堆几乎完全相同的代码,如建议的其他一些答案 - 当然欢迎反馈!

#4


0  

For me the research was time consuming but the solution rather trivial. No overrides no fiddling with forms or anything like that am using Django==1.8.6 but should work from at least django 1.7 onward. To enable support for html formatted emails in password_reset all I had to do is change the email template key name in reset function from email_template_name='emails/password_reset_email_html.html

对我来说,研究耗费时间,但解决方案相当微不足道。没有覆盖没有摆弄表格或类似的东西使用Django == 1.8.6,但至少应该从django 1.7开始工作。要在password_reset中启用对html格式的电子邮件的支持,我所要做的就是从email_template_name ='emails / password_reset_email_html.html更改重置功能中的电子邮件模板密钥名称

to

html_email_template_name='emails/password_reset_email_html.html',

html_email_template_name = '电子邮件/ password_reset_email_html.html',

thus the reset function would look as such:

因此重置功能看起来像这样:

def reset(request):
# Wrap the built-in password reset view and pass it the arguments
# like the template name, email template name, subject template name
# and the url to redirect after the password reset is initiated.
return password_reset(request, template_name='profile/reset.html',
    html_email_template_name='emails/password_reset_email_html.html',
    subject_template_name='emails/reset_subject.txt',
    post_reset_redirect=reverse('success'))

#5


0  

Based on Cem Kozinoglu solution I would suggest to change the form and overload send_mail instead of save method in the following way:

根据Cem Kozinoglu解决方案,我建议更改表单并以下列方式重载send_mail而不是save方法:

class CustomPasswordResetForm(PasswordResetForm):

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
            Sends a django.core.mail.EmailMultiAlternatives to `to_email`.
        """
        subject = loader.render_to_string(subject_template_name, context)
        # Email subject *must not* contain newlines
        subject = ''.join(subject.splitlines())
        body = loader.render_to_string(email_template_name, context)

        email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
        # New line introduce
        email_message.attach_alternative(body, 'text/html')

        if html_email_template_name is not None:
            html_email = loader.render_to_string(html_email_template_name, context)
            email_message.attach_alternative(html_email, 'text/html')

        email_message.send()

#6


0  

You can use PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

您可以使用PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

Then you can override all the form options:

然后,您可以覆盖所有表单选项:

domain_override subject_template_name email_template_name use_https token_generator from_email request html_email_template_name extra_email_context

domain_override subject_template_name email_template_name use_https token_generator from_email request html_email_template_name extra_email_context

in my case i just override 2 props

在我的情况下,我只是覆盖2道具

class CustomPasswordResetSerializer(PasswordResetSerializer):

    def get_email_options(self):
        return {
            'domain_override': 'anydomain.com',
            'html_email_template_name': 'your_temp/password_reset_email.html',
        }

#7


0  

Here is the simple approach worked for me. Add our custom template path in such a way worked for me.

这是为我工作的简单方法。以这样的方式添加我们的自定义模板路径。

path('users/password/reset/', password_reset, {'html_email_template_name': 'registration/password_reset_email.html'},name='password_reset'),

path('users / password / reset /',password_reset,{'html_email_template_name':'registration / password_reset_email.html'},name ='password_reset'),

#8


0  

After overwriting the PasswordResetForm and adding this line of code after email_message initialization I solve my problem:

在覆盖PasswordResetForm并在email_message初始化后添加这行代码后,我解决了我的问题:

email_message.attach_alternative(body, 'text/html')

#1


6  

Here is how you can do the override:

urls.py

urls.py

url(r'^user/password/reset/$', 
    'YOUR_APP.views.password_reset', 
    {'post_reset_redirect' : '/#/login?resetemail=true'},
    name="password_reset"),

views.py

views.py

from django.contrib.auth.views import password_reset as django_password_reset
from YOUR_APP.forms import CustomPasswordResetForm

def password_reset(*args, **kwargs):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    kwargs['password_reset_form'] = CustomPasswordResetForm
    return django_password_reset(*args, **kwargs)

form.py

form.py

from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.tokens import default_token_generator

class CustomPasswordResetForm(PasswordResetForm):
    """
        Overriding the Email Password Resert Forms Save to be able to send HTML email
    """
    def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator, request=None, email_subject_name='registration/password_reset_subject.txt', **kwargs):
        from django.core.mail import EmailMultiAlternatives
        from django.utils.html import strip_tags
        from django.template.loader import render_to_string
        from django.contrib.sites.models import get_current_site
        from django.utils.http import int_to_base36

        for user in self.users_cache:
            if not domain_override:
                current_site = get_current_site(request)
                site_name = current_site.name
                domain = current_site.domain
            else:
                 site_name = domain = domain_override

            c = {
                'email': user.email,
                'domain': domain,
                'site_name': site_name,
                'uid': int_to_base36(user.id),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': use_https and 'https' or 'http',
            }
            render = render_to_string(email_template_name, c)
            render_subject = render_to_string(email_subject_name, c)

            msg = EmailMultiAlternatives(render_subject, strip_tags(render), None, [user.email])
            msg.attach_alternative(render, "text/html")
            msg.send()

#2


5  

You can override save method of django.contrib.auth.forms.PasswordResetForm and pass new form as an argument to password_reset view.

您可以覆盖django.contrib.auth.forms.PasswordResetForm的save方法,并将新表单作为参数传递给password_reset视图。

#3


0  

After some amount of trial and error, I discovered a much, much more terse way to supply a custom templated password reset email in the latest version of Django (1.8).

经过一些试验和错误后,我发现了一种更简洁的方式来在最新版本的Django(1.8)中提供自定义模板化密码重置电子邮件。

In your project/urls.py, add these imports:

在您的project / urls.py中,添加以下导入:

from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse_lazy

And add the following route in your urlpatterns before the usual django contrib auth url route inclusion:

并在通常的django contrib auth url route包含之前在urlpatterns中添加以下路由:

url(r'^accounts/password/reset/$',
  auth_views.password_reset,
  {
    'post_reset_redirect': reverse_lazy('auth_password_reset_done'),
    'html_email_template_name': 'registration/password_reset_html_email.html'
  },
  name='auth_password_reset'),


url('^', include('django.contrib.auth.urls')),

And then, in your app's templates/registration folder, create the password_reset_html_email.html with whatever HTML template you want.

然后,在您的应用程序的模板/注册文件夹中,使用您想要的任何HTML模板创建password_reset_html_email.html。

The reason this seemed necessary lay in the source for django/contrib/auth/views.py, which has the view function the original URL route is mapped to:

这似乎是必要的原因在于django / contrib / auth / views.py的源代码,它具有原始URL路由映射到的view函数:

147 def password_reset(request, is_admin_site=False,
148                    template_name='registration/password_reset_form.html',
149                    email_template_name='registration/password_reset_email.html',
150                    subject_template_name='registration/password_reset_subject.txt',
151                    password_reset_form=PasswordResetForm,
152                    token_generator=default_token_generator,
153                    post_reset_redirect=None,
154                    from_email=None,
155                    current_app=None,
156                    extra_context=None,
157                    html_email_template_name=None):
158

The html_email_template_name is set to None as default, and there didn't seem to be a way to assign its value, aside from rewriting this specific route for this case as I mentioned above.

默认情况下,html_email_template_name设置为None,除了为此情况重写此特定路由之外,似乎没有办法分配其值,如上所述。

Hopefully this helps without needing to copy-paste a bunch of nearly-identical code like some of the other answers suggested - feedback is welcome, of course!

希望这有助于无需复制粘贴一堆几乎完全相同的代码,如建议的其他一些答案 - 当然欢迎反馈!

#4


0  

For me the research was time consuming but the solution rather trivial. No overrides no fiddling with forms or anything like that am using Django==1.8.6 but should work from at least django 1.7 onward. To enable support for html formatted emails in password_reset all I had to do is change the email template key name in reset function from email_template_name='emails/password_reset_email_html.html

对我来说,研究耗费时间,但解决方案相当微不足道。没有覆盖没有摆弄表格或类似的东西使用Django == 1.8.6,但至少应该从django 1.7开始工作。要在password_reset中启用对html格式的电子邮件的支持,我所要做的就是从email_template_name ='emails / password_reset_email_html.html更改重置功能中的电子邮件模板密钥名称

to

html_email_template_name='emails/password_reset_email_html.html',

html_email_template_name = '电子邮件/ password_reset_email_html.html',

thus the reset function would look as such:

因此重置功能看起来像这样:

def reset(request):
# Wrap the built-in password reset view and pass it the arguments
# like the template name, email template name, subject template name
# and the url to redirect after the password reset is initiated.
return password_reset(request, template_name='profile/reset.html',
    html_email_template_name='emails/password_reset_email_html.html',
    subject_template_name='emails/reset_subject.txt',
    post_reset_redirect=reverse('success'))

#5


0  

Based on Cem Kozinoglu solution I would suggest to change the form and overload send_mail instead of save method in the following way:

根据Cem Kozinoglu解决方案,我建议更改表单并以下列方式重载send_mail而不是save方法:

class CustomPasswordResetForm(PasswordResetForm):

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
            Sends a django.core.mail.EmailMultiAlternatives to `to_email`.
        """
        subject = loader.render_to_string(subject_template_name, context)
        # Email subject *must not* contain newlines
        subject = ''.join(subject.splitlines())
        body = loader.render_to_string(email_template_name, context)

        email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
        # New line introduce
        email_message.attach_alternative(body, 'text/html')

        if html_email_template_name is not None:
            html_email = loader.render_to_string(html_email_template_name, context)
            email_message.attach_alternative(html_email, 'text/html')

        email_message.send()

#6


0  

You can use PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

您可以使用PasswordResetSerializer http://django-rest-auth.readthedocs.io/en/latest/configuration.html

Then you can override all the form options:

然后,您可以覆盖所有表单选项:

domain_override subject_template_name email_template_name use_https token_generator from_email request html_email_template_name extra_email_context

domain_override subject_template_name email_template_name use_https token_generator from_email request html_email_template_name extra_email_context

in my case i just override 2 props

在我的情况下,我只是覆盖2道具

class CustomPasswordResetSerializer(PasswordResetSerializer):

    def get_email_options(self):
        return {
            'domain_override': 'anydomain.com',
            'html_email_template_name': 'your_temp/password_reset_email.html',
        }

#7


0  

Here is the simple approach worked for me. Add our custom template path in such a way worked for me.

这是为我工作的简单方法。以这样的方式添加我们的自定义模板路径。

path('users/password/reset/', password_reset, {'html_email_template_name': 'registration/password_reset_email.html'},name='password_reset'),

path('users / password / reset /',password_reset,{'html_email_template_name':'registration / password_reset_email.html'},name ='password_reset'),

#8


0  

After overwriting the PasswordResetForm and adding this line of code after email_message initialization I solve my problem:

在覆盖PasswordResetForm并在email_message初始化后添加这行代码后,我解决了我的问题:

email_message.attach_alternative(body, 'text/html')