Password Reset and Notifications

Add password reset email and in-app notices for follows, likes, and comments.

Goal for this part

Add Django’s password-reset email flow and a simple in-app notification list for follows, likes, and comments. Locally, mail prints in the terminal. On the VPS, the same views send through Postmark (or Mailgun).

Concepts

Password reset is a single-use token tied to SECRET_KEY and the user’s last password change. If SECRET_KEY rotates on every deploy, old links die — that is why part 12 stores the key in a systemd env file. Notifications are rows, not emails, for this teaching app: actor, verb, target post or user, read_at.

Walkthrough: reset

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
DEFAULT_FROM_EMAIL = "Westloop <hello@westloop.example>"

Wire Django’s four auth views: request, done, confirm, complete. Templates only need to extend the Westloop base. In production you will set:

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.postmarkapp.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ["POSTMARK_USER"]
EMAIL_HOST_PASSWORD = os.environ["POSTMARK_TOKEN"]

Create a Notification when someone follows you, likes your post, or comments. The header badge is a count of rows where read_at is null. Opening /notifications/ marks them read.

How to run it and what you should see

Open Forgot password, enter Ada’s email, and watch the runserver terminal for the reset URL. Open that link, set a new password, and sign in with it. Then have Grace like Ada’s post: Ada’s bell should show 1.

Common mistakes

Console backend means no inbox — look at the terminal. If the token is invalid, SECRET_KEY changed between request and confirm. Do not notify people about their own likes. Never log the raw reset link in production access logs if you can avoid it.

Try this

Request a reset, change Ada’s password in admin, then try the old email link. It should fail. That is the “token bound to password” property working.