如何让Django密码重置电子邮件漂亮的HTML?

时间:2014-02-15 05:34:26

标签: django

我的Django应用程序目前设置为使用本机注册包来处理用户身份验证和管理。

我在myApp/templates/registration中创建了一些文件,用于发送密码重置令牌,如these docs中所述。

工作正常。除了密码重置电子邮件是一个丑陋的文本怪物。我想使它与我的应用程序发送的所有其他电子邮件的外观和感觉相匹配。 IE:我希望它是HTML并包含图像,样式和链接。我该怎么做?

我按照详细说明here进行了操作。但是,该代码中存在错误,我不知道如何处理:'CustomPasswordResetForm' object has no attribute 'users_cache'

有人能告诉我一个详细的工作示例如何实现这一目标吗?我希望它不是那么难。

11 个答案:

答案 0 :(得分:9)

[从Does Django password_reset support html email templates?交叉发布]

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

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

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

在通常的django contrib auth url路由包含之前,在你的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')),

然后,在您应用的templates/registration文件夹中,使用您想要的任何HTML模板创建password_reset_html_email.html

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

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

html_email_template_name默认设置为None,除了为此案例重写此特定路由之外,似乎没有办法分配其值,如上所述。< / p>

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

答案 1 :(得分:7)

django身份验证的默认帮助程序视图无法发送多部分(HTML)电子邮件,因为基础send_mail方法不支持HTML电子邮件尚未

这将在下一版本中修复,方法是添加html_message标记。

解决此问题的最简单方法是创建自己的自定义密码重置表单,并使用EmailMultiAlternatives发送邮件,从而允许您的HTML在电子邮件客户端中正确呈现。

您可以使用existing form并进行更改:

class HTMLPasswordResetForm(forms.Form):
    email = forms.EmailField(label=_("Email"), max_length=254)

    def save(self, domain_override=None,
             subject_template_name='registration/password_reset_subject.txt',
             email_template_name='registration/password_reset_email.html',
             use_https=False, token_generator=default_token_generator,
             from_email=None, request=None):
        """
        Generates a one-use only link for resetting password and sends to the
        user.
        """
        # from django.core.mail import send_mail
        from django.core.mail import EmailMultiAlternatives
        UserModel = get_user_model()
        email = self.cleaned_data["email"]
        active_users = UserModel._default_manager.filter(
            email__iexact=email, is_active=True)
        for user in active_users:
            # Make sure that no email is sent to a user that actually has
            # a password marked as unusable
            if not user.has_usable_password():
                continue
            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': urlsafe_base64_encode(force_bytes(user.pk)),
                'user': user,
                'token': token_generator.make_token(user),
                'protocol': 'https' if use_https else 'http',
            }
            subject = loader.render_to_string(subject_template_name, c)
            # Email subject *must not* contain newlines
            subject = ''.join(subject.splitlines())
            email = loader.render_to_string(email_template_name, c)

            msg = EmailMessage(subject, email, from_email, [user.email])
            msg.content_subtype = "html"  # Main content is now text/html
            msg.send()

            #send_mail(subject, email, from_email, [user.email])

完成后,请更改password_reset方法调用并传入新的表单类:

password_reset(request, password_reset_form=HTMLPasswordResetForm)

答案 2 :(得分:3)

在django 2.0版中添加我的发现,因为我发现这个问题的其余答案已经过时了。

使用2.0,将URL添加到urls.py文件的正确方法是使用path()

from django.urls import path
from django.contrib.auth import views as auth_views

path('accounts/password_reset/', auth_views.PasswordResetView.as_view(
  html_email_template_name='registration/password_reset_html_email.html'
)),

此处要突出显示的下一个代码段是.as_view()函数。 Django 2.0将auth视图实现为类。您可以在Authentication Views documentation

中详细了解相关信息

然后&#34;转换&#34;使用`.as_view()的视图类,您可以将源代码中定义的任何类属性作为命名参数传递。

传入html_email_template_name(默认为None)会自动发送html电子邮件。

您可以通过以下python路径访问PasswordResetView的源代码:django.contrib.auth.views

在这里,您可以看到可以传递给PasswordResetView和其他身份验证视图的其他类属性。这对于将extra_context传递到django模板也非常有用。

答案 3 :(得分:1)

您是否尝试过编辑此模板? 登记/ password_reset_email.html

您可以将password_reset_email.html文件添加到项目的模板/注册文件夹中,然后添加相关的部分/ HTML以获得一个漂亮的模板。 默认模板为空。

答案 4 :(得分:1)

对于django2.2,请使用此功能在密码重置电子邮件模板中添加自定义电子邮件模板

在urls.py文件中添加以下行

urlpatterns = [
path('password-reset', 
            auth_views.PasswordResetView.as_view(
            template_name='accounts/password_reset.html', 
            html_email_template_name="accounts/email_reset_template.html",
            email_template_name='accounts/password_reset_email.html', 
            subject_template_name="accounts/password_reset_subject.txt",
            ),
             name="password_reset"),

    path('password-reset/done', 
        auth_views.PasswordResetDoneView.as_view(
            template_name='accounts/password_reset_done.html'),
             name="password_reset_done"),

    path('password-reset-complete/', 
        auth_views.PasswordResetCompleteView.as_view(
            template_name='accounts/password_reset_complete.html'),
             name="password_reset_complete"),

    path('password-reset-confirm/<uidb64>/<token>/', 
        auth_views.PasswordResetConfirmView.as_view(
            template_name='accounts/password_reset_confirm.html'),
             name="password_reset_confirm"),

#Add more urls you want
]

添加以上行后,如果您提供html模板名称,则可以从“ password_reset”中省略email_template名称,但是要在通过电子邮件发送的电子邮件中使用模板,您需要html模板,现在选择您自己的html模板 您可以从其他网站访问该文件,然后将该文件放在所有密码重置文件都位于其中的同一文件夹中。

现在重要的部分是在自定义html模板中添加链接以添加此链接,您需要将以下几行添加到自定义html模板中,如下所示:

<a  href="{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}" style=".."> Reset Password </a>

,您可以根据需要将以下行添加到html模板中的任意位置

     {% load i18n %}
{% autoescape off %}  You're receiving this e-mail because you requested a password reset for your Xandar account. {% trans "Thanks for using our site!" %} {% blocktrans %}The {{ site_name }} team{% endblocktrans %} {% endautoescape %} 

如果您仍然有任何疑问,请告诉我

这肯定行得通,我已经在项目中使用了它。

答案 5 :(得分:1)

Django 2

# add this import
from django.contrib.auth import views as auth_view

...

# add this path
path('accounts/password_reset/', auth_views.PasswordResetView.as_view(
    html_email_template_name='registration/password_reset_email.html'
)),
# just before
path('accounts/', include('django.contrib.auth.urls')),

答案 6 :(得分:0)

你必须覆盖默认的html。为此,请转到libs/site-packages/django中的django istallation文件夹,然后从django模板中复制password_reset_email.html并将其粘贴到[templates]/registration/password_reset_email.html中。然后定义您的CSS并编辑默认的html,如果您的HTML代码显示在正文中,请关闭django模板管理器自动转义,但不建议使用。

答案 7 :(得分:0)

您可以执行以下操作。

将两者都添加到password_reset:

html_email_template_name='YOUR TEMPLATE PATH',
email_template_name='YOUR TEMPLATE PATH'

它对我有用(Django 1.11)

答案 8 :(得分:0)

强制电子邮件以HTML格式发送的最简单(也是唯一的方法)是覆盖form_valid方法。

views.py:

class MyPasswordResetView(PasswordResetView):

  # forcing to use HTML email template (param: html_email_template_name)
  def form_valid(self, form):
      opts = {
          'use_https': self.request.is_secure(),
          'token_generator': self.token_generator,
          'from_email': self.from_email,
          'email_template_name': self.email_template_name,
          'subject_template_name': self.subject_template_name,
          'request': self.request,
          'html_email_template_name': 'registration/password_reset_email.html',
          'extra_email_context': self.extra_email_context,
      }
      form.save(**opts)
      return HttpResponseRedirect(self.get_success_url())

urls.py

path('password_reset/', myapp.MyPasswordResetView.as_view(), name='password_reset'),

答案 9 :(得分:0)

1)将password_reset_email.html文件添加到项目“ myApp”中的模板/注册文件夹中。
2)将“ django.contrib.admin”移至INSTALLED_APPS中“ myApp”下方。
https://github.com/macropin/django-registration/issues/50#issuecomment-142637807

不是最好的解决方案,但对我有用!

答案 10 :(得分:0)

我通过更改django.contrib.auth视图文件中的password_reset函数的参数来解决此问题。默认情况下,html_email_template_name为“无”。 如果将其定向到“ registration / password_reset_email.html”文件,则其将使用正确的html发送电子邮件。

def password_reset(request,
               template_name='registration/password_reset_form.html',
               email_template_name='registration/password_reset_email.html',
               subject_template_name='registration/password_reset_subject.txt',
               password_reset_form=PasswordResetForm,
               token_generator=default_token_generator,
               post_reset_redirect=None,
               from_email=None,
               extra_context=None,
              html_email_template_name='registration/password_reset_email.html',
               extra_email_context=None):