Opened 5 years ago

Closed 2 years ago

#17431 closed New feature (fixed)

Allow PasswordResetForm subclasses full control over email message to send

Reported by: Ethan Jucovy Owned by: jorgecarleitao
Component: contrib.auth Version: master
Severity: Normal Keywords:
Cc: timograham@…, jorgecarleitao Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The django.contrib.auth.forms.PasswordResetForm has logic to:

  1. Validate that an active user exists with the email address provided
  2. Generate an unguessable URL for the given user to reset his password using a timestamped token
  3. Construct an email with a link to that URL
  4. Send that email to the given user's email address

The .save() method of the form class is responsible for three of these four tasks. The .save() method includes parameters for overriding the subject, body, and From: address of the email to be sent. However, it's sometimes necessary to have more control over the email that will be sent. These use cases could include:

  1. BCC'ing a site administrator with a copy of the email sent
  2. Setting a custom Reply-To like "password-reset-help@…" that is distinct from the message's From: address
  3. Setting a text/html MIME type for the message, or using an EmailMultiAlternatives object to attach both text and HTML versions of the message

For all of these use cases, the knobs currently provided are insufficient, and require copying over all the logic in the .save() method.

The attached patch satisfies these use cases by allowing the user to subclass PasswordResetForm and override a .construct_email() method, whose job is to construct and return an EmailMessage to be sent by the .save() method. The changes are fully backwards-compatible, and a test demonstrating the subclassing approach is provided.

Attachments (1)

password_reset_custom_email.diff (4.3 KB) - added by Ethan Jucovy 5 years ago.

Download all attachments as: .zip

Change History (10)

Changed 5 years ago by Ethan Jucovy

comment:1 Changed 5 years ago by Aymeric Augustin

Triage Stage: UnreviewedAccepted

comment:2 Changed 5 years ago by anonymous

My need is to include an additional variable in the context that is used to render the email template. I don't see that the patch provided supports that use case?

comment:3 in reply to:  2 Changed 5 years ago by Ethan Jucovy

Replying to anonymous:

My need is to include an additional variable in the context that is used to render the email template. I don't see that the patch provided supports that use case?

Where will your extra context variable be coming from?

If it's something that you can derive without access to a request, then you can just inject it into the context in your overridden construct_email method. Likewise if it's something derived from request.POST then self.data will contain the full POSTed form, and you can inject your needed variable in construct_email.

comment:4 Changed 5 years ago by Aymeric Augustin

#12684 was a duplicate.

comment:5 Changed 4 years ago by Julien Bouquillon

Thanks ejucovy

+1 on this;

we definitely need to have full control on the sent email template and context.

comment:6 Changed 3 years ago by Tim Graham

Cc: timograham@… added
Patch needs improvement: set

Patch needs to be updated to apply cleanly.

comment:7 Changed 3 years ago by jorgecarleitao

Cc: jorgecarleitao added
Owner: changed from nobody to jorgecarleitao
Status: newassigned

comment:8 Changed 3 years ago by Claude Paroz

Needs documentation: set
Patch needs improvement: unset

The patch is promising. It still needs more docs however (release notes and also the construct_email method documentation).

comment:9 Changed 2 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: assignedclosed

In a00b78b1e2ac9bf271d55c1799138a27f5e0d03e:

Fixed #17431 -- Added send_mail() method to PasswordResetForm.

Credits for the initial patch go to ejucovy;
big thanks to Tim Graham for the review.

Note: See TracTickets for help on using tickets.
Back to Top