help with sending password resets

I’m using django’s built-in auth system, and I’m using Sendgrid for my email backend. Users can create a new account and they get emailed a token for registration/authorization. However, I don’t seem to be getting emails when I user tries to reset a password. It’s possible that the user’s email server is blocking emails (I’ll look into that, but that could take days before I get response).

I looked at the django code and went to django/contrib/auth and then views.py and eventually found that password reset is sent with:

class PasswordResetForm(forms.Form):
    email = forms.EmailField(
        label=_("Email"),
        max_length=254,
        widget=forms.EmailInput(attrs={'autocomplete': 'email'})
    )

    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        """
        Send 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])
        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()

So I opened a django shell and tried this:

>>> from django.core.mail import EmailMultiAlternatives
>>> email_message = EmailMultiAlternatives(
...     'test subject 2',
...     'Here is the body.',
...     'doug@myemail.com',
...     ['emailaddress@learn.vsb.bc.ca'],
... )
>>> email_message.send()

This mail was successfully sent and received at my intended email address. So it seems that the emails should be sent ok. Other than chasing down email blocking issues at learn.vsb.bc.ca, is there anything else I should be looking at? Again, I’m using the stock django auth password reset functionality, I haven’t touched any of the code for this.

Is this running from your local machine or a server that you’ve deployed this to?

Your Django shell session, is that being done on the same system as your deployed app?

Is there anything in the server logs showing an issue with sending the email?

Thank you for your reply.
It happens on local and deployed server, no errors showing. My users are restricted to this particular domain, but I modified the code to accommodate another domain. I tested a password reset with this other account and domain and the reset email was delivered. I think this is a problem with the recipient’s email server blocking my emails. Maybe there is something in the email message that is triggering a filter on the recipient’s email server. I bet if I remove the reset link the email message, the reset will be delivered. That will be my next test to try.

There are lots of reasons why mail servers reject incoming mail. The best way to find out what is happening is to look at mail server logs. If you can’t do that, the most common problems I find (apart from spam filters, which is what you seem to suspect) is a failure to comply with DMARC settings for the sender’s domain.

Effectively this means that if the host you send from is not including in the domain’s allowed sending hosts (ie the from email address is not sent from an allowed host for that domain), then a receiving mail server may reject it. The easiest way around this is to relay the mail through a DMARC compliant mail server, rather than try to send the mail directly from your web server.

I’m really stuck on this one. The recipient email server (our school board) has whitelisted my domain. I can send emails to a student email address manually in the shell using send_mail. I can do a password reset if the user email address is gmail or something like that. But if I try to do an email password reset with a student’s email address, the email is not delivered.

EDIT…

I’ve been working on this for a week and I finally came across this post: smtp - Django: reset-password not sending email - Stack Overflow I don’t know how I missed it before. It says that a password reset only works for if the user has_usable_password. My students do not have a password yet.

Student objects are created when they are added to a classroom, and a corresponding user is created for each Student object. Is it reasonable to set the same unguessable password for each student user when they are created, and then the students can do a password reset?

For example, I can add the one line to my view as shown below:

# make sure the student not already been added
if not Student.objects.filter(email=email_address).exists():

	# create a new user
	if not User.objects.filter(username=email_add).first():
		user = User.objects.create_user(
			email_address, #username and email address are the same
			email_address,
			last_name=last,
			first_name=first,
			is_student=True,
			password = '340jsfj;l&#n2nfKHD29kjhaJD93*Djla25l32'  # new line
		)
    # create a student instance and attach to above user
	new_student = Student(
		user=CustomUser.objects.get(
			username=email_address),
		student_last=last,
		student_first=first,
		student_number=sn,
		nickname=nick,
		fullname=full,
		email=email_add
	)
	new_student.save()

Thanks

1 Like