16

Relevant part of urls.py for the project:

from django.conf.urls import include, url, patterns
urlpatterns = patterns('',

  # other ones ...

  url(r'^accounts/password/reset/$', 
  'django.contrib.auth.views.password_reset',
 {'post_reset_redirect' : '/accounts/password/reset/done/'}),

  url(r'^accounts/password/reset/done/$', 
  'django.contrib.auth.views.password_reset_done'),

  url(r'^accounts/password/reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', 
  'django.contrib.auth.views.password_reset_confirm',
 {'post_reset_redirect' : '/accounts/password/done/'}),

  url(r'^accounts/password/done/$', 
  'django.contrib.auth.views.password_reset_complete'),

)

And by request, here's the password reset form:

{% extends "site_base.html" %}

{% block title %}Reset Password{% endblock %}

{% block content %}
<p>Please specify your email address to receive instructions for resetting it.</p>

<form action="" method="post">
    <div style="display:none">
        <input type="hidden" value="{{ csrf_token }}" name="csrfmiddlewaretoken">
    </div>
     {{ form.email.errors }}
    <p><label for="id_email">E-mail address:</label> {{ form.email }} <input type="submit" value="Reset password" /></p>
</form>
{% endblock %}

But whenever I navigate to the /accounts/password/reset/ page and fill in email and click enter the page immediately redirects to /accounts/password/reset/done/ and no email is sent.

My relevant settings.py variables:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'XXXXXX' 
EMAIL_PORT = 587

DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER

And I know email works because my registration flow with django-registration-redux works flawlessly.

Any ideas?

7
  • Can you show us a example of your view that is responsible to send email ? Commented May 19, 2015 at 21:52
  • @tanorix as you can see above in urls.py there are the built in ones, so you may see them here: github.com/django/django/blob/master/django/contrib/auth/… Commented May 19, 2015 at 21:56
  • Try switching temporarily to the file backend (or the console backend if you're in your dev environment) -- that should help show if the problem is in the views or the email configuration (I know you say that the emails are working in django-registration-redux, but this might be a worth a try anyway). Commented May 19, 2015 at 22:25
  • What time do you show your adress email ? because as we can see with the url that you show us, in line 154 the function attempt an e-mail so in your urls.py, you must specify the email and template email after ^accounts/password/reset/done/$ Commented May 19, 2015 at 22:32
  • @Alasdair, just tried that no luck. It seems the problem is not trying to send the email, but rather ever even attempting it in the first place, which just doesn't seem to happen Commented May 19, 2015 at 22:46

7 Answers 7

14
+50

I tried to recreate your situation and I faced the following scenarios:

  1. Mail is only sent to active users. Email associated with no user will not get any email(obviously).
  2. I got an error form's save method in line 270 for email = loader.render_to_string(email_template_name, c):

NoReverseMatch at /accounts/password/reset/ Reverse for 'password_reset_confirm' with arguments '()' and keyword arguments '{'token': '42h-4e68c02f920d69a82fbf', 'uidb64': b'Mg'}' not found. 0 pattern(s) tried: []

It seems that your urls.py doesn't contain any url named 'password_reset_confirm'. So you should change your url:

url(r'^accounts/password/reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
  'django.contrib.auth.views.password_reset_confirm',
 {'post_reset_redirect': '/accounts/password/done/'},),

To:

url(r'^accounts/password/reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
  'django.contrib.auth.views.password_reset_confirm',
 {'post_reset_redirect': '/accounts/password/done/'}, name='password_reset_confirm'),

If you have set your email configuration perfectly the you should get emails with no problem. If still you are facing this issue, please use a debugger to check where its getting exceptions.

PS: I have tested with django 1.7.8 and templates resides in: Python34\Lib\site-packages\django\contrib\admin\templates\registration. Urls and views are used as you have written in the question.

Sign up to request clarification or add additional context in comments.

Comments

5

When you POST to ^accounts/password/reset/$ the django.contrib.auth.views.password_reset function is run. This will use the default django.contrib.auth.forms.PasswordResetForm class to validate the email.

You should notice that an email is sent only to the active users matching the provided email, and only if they have a usable password.

Try to use the following function with the Django management shell:

from django.contrib.auth.models import get_user_model

def check_password_reset_cond(email):
     for u in get_user_model().objects.filter(email__iexact=email):
         assert u.is_active
         assert u.has_usable_password()

3 Comments

Yes, those assertions succeed without problem. And in newer versions of Djano you need from django.contrib.auth.models import User instead of get_user_model.
Thanks for calling out the conditions required for a password reset email -- I was trying to write a test of the password reset workflow and didn't know about the has_usable_password check.
Yeah, if you create your users with create_user and don't set a password, they won't reset. Use password = User.objects.make_random_password()
4

Do you have email templates in your templates folder ?

registration/password_reset_email.html
registration/password_reset_subject.txt

1 Comment

Yes, I have all of those.
3

OK, it's most likely something failing in the forms clean method, and you aren't trapping that error. So you just get the redirect without sending the mail, and no clue as to why. Any validation error thrown in clean() will show up in non_field_errors. You need to add in {{form.non_field_errors}} into your page to see them. Try this:

<form method="post">{% csrf_token %}
    {{{form.non_field_errors}}
    {{ form.email.errors }}
<p><label for="id_email">E-mail address:</label> {{ form.email }} <input    type="submit" value="Reset password" /></p>
</form>

Comments

2

I would check spam folder for sure. Because sometimes some email filters treat text emails with links quite harshly.

I recommend take (some IDE with) python debugger and with a help of pdb (python debugger) walk over django.contrib.auth.form.PasswordResetForm.save and django.contrib.auth.views.password_reset to see what does not work.

Comments

1

The answer by domtes solved this for me, but I wanted to put some emphasis on that potential cause:

If the user you're trying to reset has currently (before the reset) an invalid password, Django will just silently not send a reset email!

In my case, I accidentally overwrote the password field in the admin (custom user model + LastPass), and after that the one user just didn't reset anymore.

Comments

0

For mac users, especially if you have iTerm beside your normal Terminal, and probably you have set before your environment variable in .bash_profile, set them again on ~/.zshrc (if you run the Django project with iTerm):

export EMAIL_USER='[email protected]'
export EMAIL_PASS='password'

reload the file ~/.zshrc, source ~/.zshrc, or simply close and open the iTerm again.

Of course, previously, you have turned on the less secure option on your email setting.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.