How can I send a reset password email on Django? - django

During the process of creating my first website using Django framework, I encountered a little problem that I couldn't found a solution yet. So, when an user wants to reset his or her password, i'd like to send to him/her a reset mail. So far, I have this:
urls.py
from django.contrib.auth import views as auth_views
......
path('password-reset/', auth_views.PasswordResetView.as_view(template_name='registration/password_reset_form.html'),
name='password_reset'),
path('password-reset-confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name='registration/password_reset_confirm.html'),
name='password_reset_confirm'),
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(template_name='registration/password_reset_done.html'),
name='password_reset_done'),
path('password-reset-complete/',
auth_views.PasswordResetCompleteView.as_view(template_name='registration/password_reset_complete.html')),
....
settings.py
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_POST = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('traces_email')
EMAIL_HOST_PASSWORD = os.environ.get('traces_email_password')
I created a token generator for my link:
token_generator.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()
When I go through the reset flow, it does not send any email. It is still sent to my terminal.
Can somebody help me with this issue? Thank you so much for your time!

This setting
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
tells django to send the message to your terminal. To actually send an email, you need to use
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
This is described in the Django Docs.

Related

TimeoutError [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time

I wanna sent a email to users account to reset password. But whenever I enter the send it causes an error.
TimeoutError at /accounts/reset_password/
[WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I do not know why I am having a lot of issue in doing reset password.
Things which I have done or try
I already enable "less secure" apps in my gmail account.
I was also having a issue in password_reset_email.html
and for that I use
email_template_name=accounts/registration/password_reset_email.html
and after adding this the error was TemplateDoesNotExist. And then I make a dir in my accounts app and add a password_reset_email.html
Here is code. any help please
urls.py
from django.urls import path, reverse_lazy
from . import views
from django.contrib.auth import views as auth_views
app_name = 'accounts'
urlpatterns = [
path('register/', views.register, name='register'),
path('signin/', views.signin, name='signin'),
path('logout/', views.logout, name='logout'),
path('user_profile/', views.edit_profile, name='edit_profile'),
path('user_password/', views.change_password, name='change_password'),
# Reset password section
path('reset_password/',
auth_views.PasswordResetView.as_view(
template_name='accounts/password_reset.html',
success_url=reverse_lazy('accounts:password_reset_done'),
email_template_name='accounts/registration/password_reset_email.html'
),
name='reset_password'),
path('reset_password_sent/',
auth_views.PasswordResetDoneView.as_view(
template_name='accounts/password_reset_sent.html',
),
name='password_reset_done'),
path('reset_confirm/<uidb64>/<token>',
auth_views.PasswordResetConfirmView.as_view(
template_name='accounts/password_reset_form.html',
success_url=reverse_lazy('accounts:password_reset_complete')
),
name='password_reset_confirm'),
path('rest_password_complete/',
auth_views.PasswordResetCompleteView.as_view(
template_name='accounts/password_reset_done.html',
),
name='password_reset_complete')
]
settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '*******'
EMAIL_HOST_PASSWORD = '*******'

error on sending mail while test sending mail successfully in Django

I'm coding about Forget Password feature on Django. Reset mail will be sent when user fill out form and click Reset button. But I have a trouble here, mail isn't sent after user click button. I use sendtestmail command, sending mail successfully. And more, the content and mail subject that I define is not in the email it sent when I check by sendtestmail command. It took me all yesterday to fix above error but didn't work. Can somebody help me.
settings.py
...
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', 'vuthehuy.hus#gmail.com')
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', 'my_password_app')
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'Colo Shop <no-reply#localhost>')
app.urls
urlpatterns = [
path('password_reset/', auth_view.PasswordResetView.as_view(
template_name='account/password_reset_form.html',
form_class=EmailForgotPassword,
email_template_name='account/password_reset_email.html',
subject_template_name='account/password_reset_subject.txt'
), name='password_reset'),
path('password_reset/done/', auth_view.PasswordResetDoneView.as_view(
template_name='account/password_reset_done.html'
), name='password_reset_done'),
path('password_reset/confirm/<uidb64>/<token>/', auth_view.PasswordResetConfirmView.as_view(
template_name='account/password_change.html'
), name='password_reset_confirm'),
path('password_reset/complete/', auth_view.PasswordResetCompleteView.as_view(
template_name='account/password_change_done.html'
), name='password_reset_complete'),
]

Authentication Required error when sending email with Django

I'm trying to send a password-reset email using gmail server but I'am getting an error. 'SMTPSenderRefused Authentication Required'
The google account have - 1. 2-Step Verification on 2. Third-party access through app password 3. Access allowed for less secure app : On
'''
setting.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER') #my gmail acc
EMAIL_PASSWORD = os.environ.get('EMAIL_PASSWORD') #app password from gmail acc
EMAIL_PORT = 587
'''
'''
urls.py
path('password-reset/', PasswordResetView.as_view(
template_name='users/password-reset.html'), name='password_reset'),
path('password-reset-done/', PasswordResetDoneView.as_view(
template_name='users/password-reset-done.html'),
name='password_reset_done'),
path('password-reset-confirm/<uidb64>/<token>/',
PasswordResetConfirmView.as_view(
template_name='users/password_reset_confirm.html'),
name='password_reset_confirm'),
'''
I expect an email with a reset-password-link send to the user or whomever POSTed their email when prompted but what i get is this error -
'''
SMTPSenderRefused at /password-reset/
(530, b'5.5.1 Authentication Required. Learn more at\n5.5.1
https://support.google.com/mail/?p=WantAuthError p17sm3671371wrq.95 -
gsmtp', 'webmaster#localhost')
'''
create a new account in google and avoid two step verification.
Add your account name and password to settings directly
It will work
As you are new, hardcore these details directly to settings.py later you can configure in local environment

Django Rest Auth - Key error on Email Confirmation

I am trying to setup email verification in DRF using rest-auth.
The registration works correctly and the verification email is sent. However, when going to the verification link I receive a key error.
What I understand is that means that this verification key doesn't exist, but I don't understand how to fix that given that the registration process was supposedly a success?
I have the following paths in my urls.py:
path('', include('rest_framework.urls', namespace='rest_framework')),
path('', include('rest_auth.urls')),
path('registration/', include('rest_auth.registration.urls')),
path('registration/', RegisterView.as_view(), name='account_signup'),
re_path(r'^account-confirm-email/', VerifyEmailView.as_view(), name='account_email_verification_sent'),
re_path(r'^account-confirm-email/(?P<key>[-:\w]+)/$', VerifyEmailView.as_view(), name='account_confirm_email'),
The following settings in my settings.py:
ACCOUNT_AUTHENTICATION_METHOD = 'email'
LOGIN_REDIRECT_URL = '/'
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
ACCOUNT_CONFIRM_EMAIL_ON_GET = False
ACCOUNT_EMAIL_REQUIRED = True
And this is a screenshot of the error I am getting:
Key error
how I solved this issue
I had to create a view to verify the email my self, also note that I have a custom user model which is the goal when working on a big project
views.py
from rest_auth.registration.views import RegisterView
from django.contrib.auth import get_user_model
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import NotFound
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from allauth.account.models import EmailConfirmation, EmailConfirmationHMAC
from django.http import HttpResponseRedirect
class ConfirmEmailView(APIView):
permission_classes = [AllowAny]
def get(self, *args, **kwargs):
self.object = confirmation = self.get_object()
confirmation.confirm(self.request)
# A React Router Route will handle the failure scenario
return HttpResponseRedirect('/api/rest-auth/login/')
def get_object(self, queryset=None):
key = self.kwargs['key']
email_confirmation = EmailConfirmationHMAC.from_key(key)
if not email_confirmation:
if queryset is None:
queryset = self.get_queryset()
try:
email_confirmation = queryset.get(key=key.lower())
except EmailConfirmation.DoesNotExist:
# A React Router Route will handle the failure scenario
return HttpResponseRedirect('/login/failure/')
return email_confirmation
def get_queryset(self):
qs = EmailConfirmation.objects.all_valid()
qs = qs.select_related("email_address__user")
return qs
urls.py
from django.contrib import admin
from django.urls import path, re_path
from django.conf.urls import url, include
from rest_auth.registration.views import VerifyEmailView, RegisterView
from rest_auth.views import PasswordResetView, PasswordResetConfirmView
from users.api.views import ConfirmEmailView
urlpatterns = [
path('admin/', admin.site.urls),
url('api/rest-auth/', include('rest_auth.urls')),
url('api/account/', include('users.api.urls')),
url('api/rest-auth/registration/', include('rest_auth.registration.urls')),
url(r'^verify-email/$', VerifyEmailView.as_view(), name='account_email_verification_sent'),
url(r'^rest-auth/registration/account-confirm-email/(?P<key>[-:\w]+)/$', ConfirmEmailView.as_view(), name='account_confirm_email'),
url(r'^rest-auth/password/reset/$', PasswordResetView.as_view(), name='password_reset'),
url(r'^rest-auth/password/reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
]
settings.py
INSTALLED_APPS = [
...
'django.contrib.sites',
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_auth.registration',
'allauth',
'allauth.account',
'users',
]
SITE_ID = 1
# to use old_password when setting a new password
OLD_PASSWORD_FIELD_ENABLED = True
# to keep the user logged in after password change
LOGOUT_ON_PASSWORD_CHANGE = False
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_LOGOUT_ON_GET = True
# UNSURE
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 86400 # 1 day in seconds
ACCOUNT_LOGOUT_REDIRECT_URL ='/accounts/login/'
LOGIN_REDIRECT_URL = '/accounts/profile'
SOCIALACCOUNT_EMAIL_VERIFICATION = 'none'
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'youremail#gmail.com'
EMAIL_HOST_PASSWORD = 'yourpassword'
DEFAULT_FROM_EMAIL = 'youremail#gmail.com'
DEFAULT_TO_EMAIL = EMAIL_HOST_USER
EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = '/'
NOTE: I noticed that the URLs have to be in that order to work for me when they weren't in that order it didn't work for me. I also noticed that reset passwords give issues too so the fix is also there. I hope this solves your problem. and in case you post a reply and I haven't responded, just mail me at 'opeyemiodedeyi#gmail.com'
This might be an old post but I just wanna share what I used as a solution in hopes that it helps someone else experiencing a similar issue.
# import the confirm_email views from allauth.accounts.views
from allauth.account.views import confirm_email
# once that's done, change your url view portion from
# VerifyEmailView.as_view() to the newly imported view
re_path(r"^account-confirm-email/(?P<key>[-:\w]+)/$", confirm_email,
name="account_confirm_email"),

django alternative EMAIL_HOST settings

I want to implement django managment command which send emails by smtp with not default settings from settings.py file such as:
EMAIL_HOST
EMAIL_HOST_USER
EMAIL_HOST_PASSWORD
FROM_MAIL
EMAIL_USE_TLS
i want to send with my alternative settings different from settings.py without change it email settings for all site.
how to implement this?
Define your alternate email settings and then create a new mail connection using those settings:
settings.py
ALTERNATE_EMAIL_HOST_PASSWORD = 'your password'
ALTERNATE_EMAIL_HOST_USER = 'your user'
ALTERNATE_EMAIL_HOST = ''
ALTERNATE_EMAIL_PORT = 123
ALTERNATE_EMAIL_USE_TLS = True
Then create new connection using those settings:
from django.core import mail
from django.core.mail import send_mail
from django.conf import settings
# create new connection
connection = mail.get_connection()
connection.password = settings.ALTERNATE_EMAIL_HOST_PASSWORD
connection.username = settings.ALTERNATE_EMAIL_HOST_USER
connection.host = settings.ALTERNATE_EMAIL_HOST
connection.port = settings.ALTERNATE_EMAIL_PORT
connection.use_tls = settings.ALTERNATE_EMAIL_USE_TLS
# send email using new connection you just created
send_mail('my subject', 'my message', settings.DEFAULT_FROM_EMAIL,
['abc#gmail.com'], connection=connection)