django-allauth icon indicating copy to clipboard operation
django-allauth copied to clipboard

Override default password reset email

Open chdsbd opened this issue 6 years ago • 12 comments

I'm attempting to override the default password reset email to send an HTML email, but I cannot find documentation on this.

I added my template to templates/account/email/password_reset_key_message.html, but that didn't override the default.

What is the proper and concise way to do this?

Related https://github.com/pennersr/django-allauth/issues/682

chdsbd avatar Aug 23 '17 20:08 chdsbd

@pennersr - I just hit this too and was thinking of putting in a pull request for a possible override in settings. That way, there's no need to subclass the default adapter just for the sake of a single email template swap.

Let me know if that'd be acceptable as a PR.

@chdsbd - Looks like you'll have to override the default adapter's send_confirmation_email method, which in turn feeds the prefix into the render_email method

CC: @StevenFerreira

thongly avatar Sep 13 '17 00:09 thongly

Alternatively, you could do a template override in your local django project template directory, and use the exact same naming convention.

https://docs.djangoproject.com/en/1.11/howto/overriding-templates/#overriding-from-the-project-s-templates-directory

thongly avatar Sep 13 '17 01:09 thongly

I am trying to do this, and it works for the verify confirmation email, but it seems that the reset password email is still using the default templates/registration/password_reset_email.html, and it doesn't hit the render_email function, or any of the email functions in the AccountAdaptor.

I am a bit at a loss. Here is the way I previously changed the default AccountAdapter to send a custom url https://github.com/Tivix/django-rest-auth/issues/389#issuecomment-350487890

Moulde avatar Apr 30 '18 08:04 Moulde

You need to create your own PasswordResetSerializer with a custom save method and override the default in the settings.

Check out this solution here: https://stackoverflow.com/a/52111127/7234587

To make an HTML email simply replace 'email_template_name' with 'html_email_template_name' in the save options. Then use an HTML file instead of a text file.

briandkim93 avatar Aug 31 '18 09:08 briandkim93

If you dont need to use HTML just create a file called password_reset_key_message.txt in templates/account/email and it will work.

https://github.com/pennersr/django-allauth/blob/master/allauth/templates/account/email/password_reset_key_message.txt

volkandkaya avatar Nov 16 '18 11:11 volkandkaya

Two more cents here watch out for the actual reset password URL syntax https://github.com/django/django/blob/master/django/contrib/admin/templates/registration/password_reset_email.html#L6 It may change in the future.

Brunux avatar Jun 22 '19 01:06 Brunux

In case anyone is looking at this, works for me just by changing password_reset_key_message.txt and password_reset_key_subject.txt to have ".html" extensions.

alexjpm avatar Jul 10 '20 14:07 alexjpm

In case anyone is looking at this, works for me just by changing password_reset_key_message.txt and password_reset_key_subject.txt to have ".html" extensions.

I was able to overwrite it by putting password_reset_key_message.html in templates/allauth/account/email/, but However, the protocol and domain uid token data are empty. Is there anything else I should do?

{{ password_reset_url }} will respond, but since we have a separate backend and frontend, we need to override the URL as well.

johnvonneumann7 avatar Aug 08 '21 03:08 johnvonneumann7

In case anyone is looking at this, works for me just by changing password_reset_key_message.txt and password_reset_key_subject.txt to have ".html" extensions.

I was able to overwrite it by putting password_reset_key_message.html in templates/allauth/account/email/, but However, the protocol and domain uid token data are empty. Is there anything else I should do?

{{ password_reset_url }} will respond, but since we have a separate backend and frontend, we need to override the URL as well.

I have this problem also, I was able to change the template of the password_reset_key_message.html but since I have a separate frontend the generated url is incorrect.

aabanaag avatar Oct 14 '21 06:10 aabanaag

@aabanaag I think you would need to override this to include those fields: https://github.com/pennersr/django-allauth/blob/353386216b79f16709e97bb487c0bbbba2bc0c71/allauth/account/forms.py#L552-L557

Because I didn't want to do that I just made formatted my generated URL specifically:

path('api/password/confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),

Then made two new filters:

@register.filter(name="uid_param")
 def uid_param(url):
     return re.match(r"^(.*)/(.*)/(.*)/$", url).group(2)


 @register.filter(name="token_param")
 def token_param(url):
     return re.match(r"^(.*)/(.*)/(.*)/$", url).group(3)

Then used it:

https://example.com/account/forgot-password/?uid={{ password_reset_url | uid_param }}&token={{ password_reset_url | token_param }}

This is a pretty terrible idea, but kept things small.

jeffrafter avatar Nov 16 '21 14:11 jeffrafter

@jeffrafter Where do you place the register.filter code?

joshuakoh1 avatar Mar 10 '22 17:03 joshuakoh1

@joshuakoh1 https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#code-layout

dmwyatt avatar Jun 16 '22 20:06 dmwyatt

users.serializers.CustomPasswordResetSerializer

class CustomAllAuthPasswordResetForm(AllAuthPasswordResetForm):
    def save(self, request, **kwargs):
        current_site = config('FRONTEND_DOMAIN')
        email = self.cleaned_data['email']
        token_generator = kwargs.get('token_generator', default_token_generator)
        for user in self.users:
            temp_key = token_generator.make_token(user)
            # send the password reset email
            path = reverse('password_reset_confirm', args=[user_pk_to_url_str(user), temp_key], )
            # custom url frontend
            url = config('FRONTEND_DOMAIN') + '/auth' + path
            context = {
                'current_site': current_site,
                'user': user,
                'password_reset_url': url,
                'request': request,
            }
            get_adapter(request).send_mail('account/email/password_reset_key', email, context)
        return self.cleaned_data['email']
class CustomPasswordResetSerializer(PasswordResetSerializer):
    @property
    def password_reset_form_class(self):
        return CustomAllAuthPasswordResetForm

settings.py

REST_AUTH = {
    'USE_JWT': True,
    'PASSWORD_RESET_SERIALIZER': 'users.serializers.CustomPasswordResetSerializer',
    'PASSWORD_RESET_USE_SITES_DOMAIN': False,
}

simox11 avatar Mar 02 '23 09:03 simox11

It is not very clear what this ticket is about, one the one hand it is about overriding templates, on the other hand I see people using custom serializers suggesting another package is involved. Closing as it does not clearly pinpoint an issue in allauth.

pennersr avatar Oct 20 '23 17:10 pennersr

It would be pretty handy if the adapter exposed a method like send_password_reset_email (similar to these) that could allow the customization of that email, beyond simply the template.

I realize it's possible to subclass the send_email method and handle it from there, but a specific method would make it easier.

If there's interest I could take a shot at a PR.

jarcoal avatar Dec 20 '23 06:12 jarcoal