【问题标题】:Does Django password_reset support html email templates?Django password_reset 是否支持 html 电子邮件模板?
【发布时间】:2011-11-01 11:14:10
【问题描述】:

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

【问题讨论】:

    标签: python django


    【解决方案1】:

    在 Django 3.0+ 中使用图像的 HTML 密码重置电子邮件

    概述

    1. 创建三个模板:
      • password_reset_email.html
      • password_reset_email.txt
      • password_reset_subject.txt
    2. 通过创建子类覆盖django.contrib.auth.forms.PasswordResetForm
    3. 覆盖PasswordResetForm.save() 的参数以指向您的自定义模板。
    4. 如果您想在 HTML 电子邮件中嵌入图像,请覆盖 PasswordResetForm.send_email()
    5. 设置 django.contrib.auth.views.PasswordResetView.form_class 以使用新的 PasswordResetForm 子类。

    1。创建三个模板

    • 在您的 Django 模板目录中,创建一个名为“registration”的子目录。
    • 在“模板/注册”下添加三个模板:
      • password_reset_email.html
      • password_reset_email.txt
      • password_reset_subject.txt
    • HTML 电子邮件模板应该是结构良好的 HTML 文档。请参见下面的示例。
    • “*.txt”模板应该只是一个普通模板(非 HTML)。请参见下面的示例。

    示例password_reset_email.html

    {% autoescape off %}
    <!DOCTYPE html>
    
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1"/>
    
            <title>Password Reset</title>
    
            <style type="text/css">
                
                body {
                    background-color: #ffffff;
                    font-size: 14px;
                    line-height: 16px;
                    font-family: PTSansRegular,Arial,Helvetica,sans-serif;
                    height: 100%;
                    margin: 0;
                    padding: 0;
                    border: 0;
                    outline: 0;
                }
    
                a.button {
                    background-color: #007bff;
                    border-color: #007bff;
                    border-radius: 5px;
                    color: #ffffff;
                    cursor: pointer;
                    display: inline-block;
                    font-size: 15px;
                    line-height: 18px;
                    font-weight: bold;
                    font-family: PTSansRegular,Arial,Helvetica,sans-serif;
                    padding: 7px;
                    text-align: center;
                    text-decoration: none;
                    white-space: nowrap;
                    width: 150px;
                }
    
                .center {
                    text-align: center
                }
    
                .container {
                    min-height: 100%;
                    min-width: 650px;
                    position: relative;
                    width: 100%;
                }
    
                p {
                    text-align:left
                }
    
                table {
                    margin: auto;
                    width:650px;
                }
    
                td {
                    padding-right: 14px;
                    padding-left: 14px;
                }
            </style>
        </head>
    
        <body>
    
        <div class="container">
    
        <!-- BEGIN EMAIL -->
        <table align="center" border="0" cellpadding="0" cellspacing="0">
        <tr>
            <td>
                <p>Hello {{ user.get_username }},</p>
    
                <p>A request has been received to change the password for your account.</p>
    
                <p class="center">
                    <a target="_blank" class="button"
                            href="{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">
                        Reset Password
                    </a>
                </p>
    
                <p>This link can only be used once. If you need to reset your password again, please visit
                <a href="{{ protocol }}://{{domain}}">{{ site_name }}</a> and request another reset.</p>
    
                <p>If you did not make this request, please contact us immediately at
                <a href="mailto: YOUR_SUPPORT_EMAIL">YOUR_SUPPORT_EMAIL</a>.</p>
    
                <p>Sincerely,</p>
                <p>The YOUR_COMPANY_NAME Team</p>
            </td>
        </tr>
        </table>
        <!-- END EMAIL -->
    
        <table class="spacer">
            <tr><td class="spacer">&nbsp;</td></tr>
        </table>
    
        <!-- BEGIN FOOTER -->
        <table align="center">
            <tr>
                <td>
                    <p class="center"><img src="cid:logo" /></p>
                </td>
            </tr>
            <tr>
                <td class="center">YOUR_ADDRESS_AND_OR_COPYRIGHT</td>
            </tr>
        </table>
        <!-- END FOOTER -->
        </div>
    
        </body>
    </html>
    {% endautoescape %}
    

    示例password_reset_email.txt

    {% autoescape off %}
    Hello {{ user.get_username }},
    
    A request has been received to change the password for your account. Click the link below to reset your password.
    
    {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">
    
    This link can only be used once. If you need to reset your password again, please visit
    {{ protocol }}://{{domain}}">{{ site_name }} and request another reset.
    
    If you did not make this request, please contact us immediately at YOUR_SUPPORT_EMAIL.
    
    Sincerely,
    
    The YOUR_COMPANY_NAME Team
    
    
    
    YOUR_COMPANY_NAME
    YOUR_ADDRESS_AND_OR_COPYRIGHT
    {% endautoescape %}
    

    2。覆盖django.contrib.auth.forms.PasswordResetForm

    • 在您的 Django 应用目录中,创建一个名为“forms.py”的模块。
    • 创建django.contrib.auth.forms.PasswordResetForm 的子类并覆盖save() 方法。

    示例:forms.py

    class CustomPasswordResetForm(PasswordResetForm):
        """Override the default Django password-reset form to send the password reset 
        email using both HTML and plain text.
        """
    
        def save(
            self,
            domain_override: Optional[str] = None,
            subject_template_name: str = PASSWORD_RESET_SUBJECT_TEMPLATE,
            email_template_name: str = PASSWORD_RESET_TEXT_TEMPLATE,
            use_https: Optional[bool] = None,
            token_generator: PasswordResetTokenGenerator = default_token_generator,
            from_email: Optional[str] = FROM_EMAIL,
            request: Optional[WSGIRequest] = None,
            html_email_template_name: Optional[str] = PASSWORD_RESET_HTML_TEMPLATE,
            extra_email_context: Optional[Dict[str, str]] = None
        ) -> None:
            """Generate a one-use only link for resetting password and email it to 
            the user.
    
            Args:
                domain_override: Optional; Domain name to use in the email message 
                    template that overrides the actual domain from which the email is 
                    sent. Defaults to None.
                subject_template_name: Optional; Warning: this argument is overridden 
                    by the global variable ``PASSWORD_RESET_SUBJECT_TEMPLATE``.
                email_template_name: Optional; Warning: this argument is overridden by 
                    the global variable ``PASSWORD_RESET_TEXT_TEMPLATE``.
                use_https: Optional; If True, use HTTPS, otherwise use HTTP. Defaults 
                    to False. Note that if the password reset HTTP request is received 
                    via HTTPS, `use_https` will be set to True by the auth view.
                token_generator: Optional; Strategy object used to generate and check 
                    tokens for the password reset mechanism. Defaults to an instance 
                    of ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
                from_email: Optional; Warning: this argument is overridden by the 
                    global variable``FROM_EMAIL``.
                request: Optional; The HttpRequest object. Defaults to None.
                html_email_template_name: Warning: this argument is overridden by the 
                    global variable ``PASSWORD_RESET_HTML_TEMPLATE``.
                extra_email_context: Optional; Key-value pairs to add to the context 
                    dictionary used to render the password reset email templates. 
                        Defaults to None.
            """
            email_template_name = PASSWORD_RESET_TEXT_TEMPLATE
            from_email = FROM_EMAIL
            html_email_template_name = PASSWORD_RESET_HTML_TEMPLATE
            subject_template_name = PASSWORD_RESET_SUBJECT_TEMPLATE
    
            email = self.cleaned_data["email"]
            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
            UserModel = get_user_model()
            email_field_name = UserModel.get_email_field_name()  # type: ignore
    
            for user in self.get_users(email):
                user_email = getattr(user, email_field_name)
                context = {
                    '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',
                    **(extra_email_context or {}),
                }
    
                self.send_mail(
                    subject_template_name = subject_template_name,
                    email_template_name = email_template_name,
                    context = context,
                    from_email = from_email,
                    to_email = user_email,
                    html_email_template_name = html_email_template_name
                )
    
    

    3。覆盖 PasswordResetForm.save() 的参数以指向您的自定义模板。

    • 在“forms.py”模块中,添加如下全局变量:

    示例forms.py

    from typing import Final
    
    
    # Constants for sending password-reset emails.
    LOGO_FILE_PATH: Final[str] = "img/logo.png"
    LOGO_CID_NAME: Final[str] = "logo"
    PASSWORD_RESET_FORM_TEMPLATE: Final[str] = "registration/password_reset_form.html"
    PASSWORD_RESET_HTML_TEMPLATE: Final[str] = "registration/password_reset_email.html"
    PASSWORD_RESET_TEXT_TEMPLATE: Final[str] = "registration/password_reset_email.txt"
    PASSWORD_RESET_SUBJECT_TEMPLATE: Final[str] = "registration/password_reset_subject.txt"
    SUPPORT_EMAIL: Final[str] = "YOUR_SUPPORT_EMAIL_ADDRESS"
    FROM_EMAIL: Final[str] = f"YOUR_COMPANY_NAME Support <{SUPPORT_EMAIL}>"
    

    4。如果您想在 HTML 电子邮件中嵌入图像,请覆盖 PasswordResetForm.send_email()

    示例:forms.py

    def get_as_mime_image(image_file_path: str, cid_name: str) -> MIMEImage:
        """Fetch an image file and return it wrapped in a ``MIMEImage`` object for use 
        in emails.
    
        After the ``MIMEImage`` has been attached to an email, reference the image in 
        the HTML using the Content ID.
    
        Example:
    
        If the CID name is "logo", then the HTML reference would be:
    
        <img src="cid:logo" />
    
        Args:
            image_file_path: The path of the image. The path must be findable by the 
                Django staticfiles app.
            cid_name: The Content-ID name to use within the HTML email body to 
                reference the image.
    
        Raises:
            FileNotFoundError: If the image file cannot be found by the staticfiles app.
    
        Returns:
            MIMEImage: The image wrapped in a ``MIMEImage`` object and the Content ID 
            set to ``cid_name``.
        """
        paths = finders.find(image_file_path)
        if paths is None:
            raise FileNotFoundError(f"{image_file_path} not found in static files")
    
        if isinstance(paths, list):
            final_path = paths[0]
        else:
            final_path = paths
        with open(final_path, 'rb') as f:
            image_data = f.read()
    
        mime_image = MIMEImage(image_data)
        mime_image.add_header("Content-ID", f"<{cid_name}>")
        return mime_image
    
    
    class CustomPasswordResetForm(PasswordResetForm):
        """Override the default Django password-reset form to send the password reset email using both HTML and plain text.
        """
        def send_mail(
            self,
            subject_template_name: str,
            email_template_name: str,
            context: Dict[str, str],
            from_email: Optional[str],
            to_email: str,
            html_email_template_name: Optional[str] = None,
        ) -> None:
            """Send a ``django.core.mail.EmailMultiAlternatives`` to ``to_email``.
    
            This method also attaches the company logo, which can be added to the 
            email HTML template using:
    
            <img src="cid:logo" />
    
            Args:
                subject_template_name: Path of the template to use as the email 
                    subject.
                email_template_name: Path of the template to use for the plain text 
                    email body.
                context: A context dictionary to use when rendering the password reset 
                    email templates.
                from_email: The From email address.
                to_email: The To email address.
                html_email_template_name: Optional; Path of the template to use for 
                    the HTML email body. Defaults to None.
            """
            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=from_email, to=[to_email],
                                                   reply_to=[from_email])
            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.mixed_subtype = "related"
                mime_image = get_as_mime_image(image_file_path=LOGO_FILE_PATH, cid_name=LOGO_CID_NAME)
                email_message.attach(mime_image)  # type: ignore
    
            email_message.send()
    

    5。设置 django.contrib.auth.views.PasswordResetView.form_class 以使用新的 PasswordResetForm 子类。

    Django urls.py 文件

    from django.contrib.auth import views
    
    from your_app.forms import CustomPasswordResetForm
    
    
    views.PasswordResetView.form_class = CustomPasswordResetForm
    
    urlpatterns = [
        path('', home_view, name='home'),
        path('accounts/', include('django.contrib.auth.urls')),
        ...
    ]
    

    完成forms.py

    """Module that overrides the default Django password reset functionality by 
    sending emails containing both plain text as well as HTML along with the company logo.
    """
    
    from email.mime.image import MIMEImage
    from typing import Dict, Final, Optional
    
    from django.contrib.auth import get_user_model
    from django.contrib.auth.forms import PasswordResetForm
    from django.contrib.auth.tokens import default_token_generator, PasswordResetTokenGenerator
    from django.contrib.sites.shortcuts import get_current_site
    from django.contrib.staticfiles import finders
    from django.core.handlers.wsgi import WSGIRequest
    from django.core.mail import EmailMultiAlternatives
    from django.template import loader
    from django.utils.encoding import force_bytes
    from django.utils.http import urlsafe_base64_encode
    
    
    # Constants for sending password-reset emails.
    LOGO_FILE_PATH: Final[str] = "img/logo.png"
    LOGO_CID_NAME: Final[str] = "logo"
    PASSWORD_RESET_FORM_TEMPLATE: Final[str] = "registration/password_reset_form.html"
    PASSWORD_RESET_HTML_TEMPLATE: Final[str] = "registration/password_reset_email.html"
    PASSWORD_RESET_TEXT_TEMPLATE: Final[str] = "registration/password_reset_email.txt"
    PASSWORD_RESET_SUBJECT_TEMPLATE: Final[str] = "registration/password_reset_subject.txt"
    SUPPORT_EMAIL: Final[str] = "YOUR_SUPPORT_EMAIL_ADDRESS"
    FROM_EMAIL: Final[str] = f"YOUR_COMPANY_NAME Support <{SUPPORT_EMAIL}>"
    
    
    def get_as_mime_image(image_file_path: str, cid_name: str) -> MIMEImage:
        """Fetch an image file and return it wrapped in a ``MIMEImage`` object for use 
        in emails.
    
        After the ``MIMEImage`` has been attached to an email, reference the image in 
        the HTML using the Content ID.
    
        Example:
    
        If the CID name is "logo", then the HTML reference would be:
    
        <img src="cid:logo" />
    
        Args:
            image_file_path: The path of the image. The path must be findable by the 
                Django staticfiles app.
            cid_name: The Content-ID name to use within the HTML email body to 
                reference the image.
    
        Raises:
            FileNotFoundError: If the image file cannot be found by the staticfiles app.
    
        Returns:
            MIMEImage: The image wrapped in a ``MIMEImage`` object and the Content ID 
            set to ``cid_name``.
        """
        paths = finders.find(image_file_path)
        if paths is None:
            raise FileNotFoundError(f"{image_file_path} not found in static files")
    
        if isinstance(paths, list):
            final_path = paths[0]
        else:
            final_path = paths
        with open(final_path, 'rb') as f:
            image_data = f.read()
    
        mime_image = MIMEImage(image_data)
        mime_image.add_header("Content-ID", f"<{cid_name}>")
        return mime_image
    
    
    class CustomPasswordResetForm(PasswordResetForm):
        """Override the default Django password-reset form to send the password reset email using both HTML and plain text.
        """
        def send_mail(
            self,
            subject_template_name: str,
            email_template_name: str,
            context: Dict[str, str],
            from_email: Optional[str],
            to_email: str,
            html_email_template_name: Optional[str] = None,
        ) -> None:
            """Send a ``django.core.mail.EmailMultiAlternatives`` to ``to_email``.
    
            This method also attaches the company logo, which can be added to the 
            email HTML template using:
    
            <img src="cid:logo" />
    
            Args:
                subject_template_name: Path of the template to use as the email 
                    subject.
                email_template_name: Path of the template to use for the plain text 
                    email body.
                context: A context dictionary to use when rendering the password reset 
                    email templates.
                from_email: The From email address.
                to_email: The To email address.
                html_email_template_name: Optional; Path of the template to use for 
                    the HTML email body. Defaults to None.
            """
            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=from_email, to=[to_email],
                                                   reply_to=[from_email])
            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.mixed_subtype = "related"
                mime_image = get_as_mime_image(image_file_path=LOGO_FILE_PATH, cid_name=LOGO_CID_NAME)
                email_message.attach(mime_image)  # type: ignore
    
            email_message.send()
    
        def save(
            self,
            domain_override: Optional[str] = None,
            subject_template_name: str = PASSWORD_RESET_SUBJECT_TEMPLATE,
            email_template_name: str = PASSWORD_RESET_TEXT_TEMPLATE,
            use_https: Optional[bool] = None,
            token_generator: PasswordResetTokenGenerator = default_token_generator,
            from_email: Optional[str] = FROM_EMAIL,
            request: Optional[WSGIRequest] = None,
            html_email_template_name: Optional[str] = PASSWORD_RESET_HTML_TEMPLATE,
            extra_email_context: Optional[Dict[str, str]] = None
        ) -> None:
            """Generate a one-use only link for resetting password and email it to 
            the user.
    
            Args:
                domain_override: Optional; Domain name to use in the email message 
                    template that overrides the actual domain from which the email is 
                    sent. Defaults to None.
                subject_template_name: Optional; Warning: this argument is overridden 
                    by the global variable ``PASSWORD_RESET_SUBJECT_TEMPLATE``.
                email_template_name: Optional; Warning: this argument is overridden by 
                    the global variable ``PASSWORD_RESET_TEXT_TEMPLATE``.
                use_https: Optional; If True, use HTTPS, otherwise use HTTP. Defaults 
                    to False. Note that if the password reset HTTP request is received 
                    via HTTPS, `use_https` will be set to True by the auth view.
                token_generator: Optional; Strategy object used to generate and check 
                    tokens for the password reset mechanism. Defaults to an instance 
                    of ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
                from_email: Optional; Warning: this argument is overridden by the 
                    global variable``FROM_EMAIL``.
                request: Optional; The HttpRequest object. Defaults to None.
                html_email_template_name: Warning: this argument is overridden by the 
                    global variable ``PASSWORD_RESET_HTML_TEMPLATE``.
                extra_email_context: Optional; Key-value pairs to add to the context 
                    dictionary used to render the password reset email templates. 
                        Defaults to None.
            """
            email_template_name = PASSWORD_RESET_TEXT_TEMPLATE
            from_email = FROM_EMAIL
            html_email_template_name = PASSWORD_RESET_HTML_TEMPLATE
            subject_template_name = PASSWORD_RESET_SUBJECT_TEMPLATE
    
            email = self.cleaned_data["email"]
            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
            UserModel = get_user_model()
            email_field_name = UserModel.get_email_field_name()  # type: ignore
    
            for user in self.get_users(email):
                user_email = getattr(user, email_field_name)
                context = {
                    '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',
                    **(extra_email_context or {}),
                }
    
                self.send_mail(
                    subject_template_name = subject_template_name,
                    email_template_name = email_template_name,
                    context = context,
                    from_email = from_email,
                    to_email = user_email,
                    html_email_template_name = html_email_template_name
                )
    

    【讨论】:

      【解决方案2】:

      这是对我有用的简单方法。以适合我的方式添加我们的自定义模板路径。

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

      【讨论】:

        【解决方案3】:

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

        然后你可以覆盖所有的表单选项:

        域覆盖 主题模板名称 电子邮件模板名称 使用_https 令牌生成器 from_email 要求 html_email_template_name extra_email_context

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

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

        【讨论】:

          【解决方案4】:

          您可以通过以下方式进行覆盖:

          urls.py

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

          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

          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()
          

          【讨论】:

          • 我收到此错误:/user/password/reset/ 'CustomPasswordResetForm' 对象的 AttributeError 没有属性 'users_cache'。你犯错了吗?我应该使用其他函数而不是 users_cache() 吗?别人做什么。
          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            经过反复试验,我发现了一种在最新版本的 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,除了我上面提到的为这种情况重写此特定路由之外,似乎没有办法分配其值。

            希望这会有所帮助,而无需像其他一些建议的答案那样复制粘贴一堆几乎相同的代码 - 当然,欢迎提供反馈!

            【讨论】:

              【解决方案7】:

              对我来说,这项研究很耗时,但解决方案却相当琐碎。 没有覆盖没有摆弄表单或类似的东西 我正在使用 Django==1.8.6,但至少应该从 django 1.7 开始工作。要在 password_reset 中启用对 html 格式的电子邮件的支持,我所要做的就是从 email_template_name='emails/password_reset_email_html.html 更改重置函数中的电子邮件模板键名

              html_email_template_name='emails/password_reset_email_html.html',

              因此重置函数如下所示:

              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'))
              

              【讨论】:

              • 在 django 项目结构中放置这个的合适位置在哪里?
              【解决方案8】:

              基于 Cem Kozinoglu 解决方案,我建议通过以下方式更改表单并重载 send_mail 而不是保存方法:

              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()
              

              【讨论】:

                【解决方案9】:

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

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

                【讨论】:

                  猜你喜欢
                  • 2020-09-18
                  • 2016-01-08
                  • 1970-01-01
                  • 2016-03-09
                  • 2019-03-27
                  • 2015-05-29
                  • 2011-03-04
                  • 2016-11-04
                  • 1970-01-01
                  相关资源
                  最近更新 更多