Django password reset. Not sending mail - django

I'm trying to get the django password reset working but the reset email does not get sent.
I know my email is properly configured because the following works both in the shell and in one of my views (I'm using it to get support email to myself).
from django.core.mail import send_mail
send_mail('Subject here', 'Here is the message.',
'admin#mydomain.com',['me#gmail.com'], fail_silently=False)
I can get to my reset password view (password/reset/) and after I give it my email it correctly redirects me to password/reset/done/ but it doesn't sends the email.
Here's my urls.py:
(r'^password/reset/$','django.contrib.auth.views.password_reset'),
(r'^password/reset/done/$','django.contrib.auth.views.password_reset_done'),
(r'^password/reset/confirm/$','django.contrib.auth.views.password_reset_confirm'),
(r'^password/reset/complete/$','django.contrib.auth.views.password_reset_confirm'),
(r'^password/change/$','django.contrib.auth.views.password_change'),
(r'^password/change/done/$','django.contrib.auth.views.password_change_done'),
Here's my password_reset_form.html:
<html>
<head>
<link rel="stylesheet" type="text/css" href="/media/css/style_login.css" />
<title>InformaciĆ³n de acceso requerida</title>
</head>
<body>
<div id="wrapper">
<h1>Recuperar password</h1>
<p>Utilice este formulario cuando desee recuperar el password para su usuario.</p>
{% if form.errors %}
<p>No hay un usuario registrado con ese correo electronico.</p>
{% endif %}
<form method="post" action="{% url django.contrib.auth.views.password_reset_done %}">
{% csrf_token %}
{{ form }}
<input class="login" type="submit" value="Recuperar" />
</form>
</div>
</body>
Any ideas? Thanks

I should have mention I'm using hostgator as my provider. So this is my settings.py
EMAIL_HOST = 'my-domain.com'
EMAIL_HOST_PASSWORD = 'my cpanel password'
EMAIL_HOST_USER = 'my cpanel user'
EMAIL_PORT = 25
EMAIL_USE_TLS = False
DEFAULT_FROM_EMAIL = 'webmaster#my-host.com'
SERVER_EMAIL = 'root#my-domain.com'
The above settings work!

In my case I created the users using create_user(). My idea was to create a bunch of accounts and then tell people they could go to the password reset form to set their password. I think it sucks if you need to tell them 'Use password "welcome123" and then don't forget to modify your password' or such.
I found out if I did not pass Password='foo' or also if I passed Password=None to create_user() password resets are not sent. This is because Django sometimes uses an empty password to know that it does not need to authenticate locally, but rather use LDAP or such.
So now I do this:
User.objects.create_user(
user_name,
email=user_email,
password=os.urandom(32),
)
And I can direct people to use the password reset function for their new accounts. I think it would be awesome if I had an option in create_user to automatically send emails for account activation to users, though!

You need to add a default from address e.g:
DEFAULT_FROM_EMAIL = 'info#mymail.com'
I see now it is in the comments but will add it here in case anyone misses them too.

Related

Error in Django to show the sender's email

I am trying to view the sender's email that is being sent to the email host. I am able to send emails to the email_host_user using environment variables and have allowed access for less secure apps in Yahoo account. However, when I do the "from_email" I received an error: SMTPSenderRefused--(550, b'Request failed; Mailbox unavailable', 'bill#yahoo.com')--'bill#yahoo.com is just a random sender's email though I am not able to send to the email_host. I think there must be some issues with my views.py? I appreciate your feedback!
settings.py
EMAIL_HOST='smtp.mail.yahoo.com'
EMAIL_HOST_USER=os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD=os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
print(os.environ.get('EMAIL_HOST_USER'))
print(os.environ.get('EMAIL_HOST_PASSWORD'))
print(os.environ.get('SECRET_KEY'))
views.py
def contact(request):
if request.method=='POST':
message=request.POST.get('message', '')
from_email=request.POST.get('from_email', '')
send_mail('Contact Form',
message,
from_email,
[settings.EMAIL_HOST_USER],
fail_silently=False
)
return render(request, 'first_app/contact.html')
contact.html
<form action="/contact" method="POST">
{% csrf_token %}
<input type="email" name="from_email" placeholder="Your email">
<textarea name="message" placeholder="Message...">
</textarea>
<input type="submit">
</form>
Yahoo won't allow you to send email from an unauthorized email. You can only use your EMAIL_HOST_USER email address to send emails.
What you can do is set EMAIL_HOST_USER as sender and add a Reply-To header with the email address provided through the form.
You should use EmailMessage for this
from django.core.mail import EmailMessage
def contact(request):
if request.method=='POST':
message=request.POST.get('message', '')
from_email=request.POST.get('from_email', '')
email = EmailMessage(
subject='Contact Form',
message=message,
from_email=settings.EMAIL_HOST_USER,
recipient_list=[settings.EMAIL_HOST_USER'],
reply_to=[from_email]
)
email.send(fail_silently=False)
return render(request, 'first_app/contact.html')
docs

Django request.method automatically set to GET and not POST

I'd like to setup an LDAP Authentication Backend in Django, and I've already used ldap3 to confirm a bind, with success.
I'm now realising that writing a class for my LDAP Backend with just ldap3 is not so straightforward, and that installing
django_auth_ldap could be another route to explore.
I've tested already some code to create a bind to the LDAP "server", and then perform a simple search. All okay. This method I tested is outside of my Django framework.
When implementing the same method into my Django framework, I encounter an issue when the method gets called. Because of the print statements, I know the view is getting called as exptected, but the part of the code whereby the first "if" statement should be executed, does not get called unless I change from "POST"
to "GET". But then this seems to create the next issue (when I set to "GET", so to force the next lines to be executed), because I'd like that a login page then gets called, where I can then input my LDAP credentials,
ultimately confirming the LDAP connection. Here is my code:
views.py
def login_ldap(request):
LDAP_SERVER = '10.222.4.88'
searchFilter='random'
print (request)
print (LDAP_SERVER)
print ("request.method:{0}".format(request.method))
if request.method == "GET":
print ("if statement executed")
username = request.GET['username']
print ("U:{0}".format(username))
password = request.GET['password']
print ("P:{0}".format(password))
# Define the server and bind_dn
server = Server(LDAP_SERVER, get_info=ALL)
bind_dn = 'cn={0}, ou=Prod, ou=Extern, ou=User, ou=ABC, dc=DEF, dc=com'.format(username)
# Define the Connection
conn = Connection(server, bind_dn, password, auto_bind=True) # Use raise_exceptions=True for exceptions
print ("search: {0}",format(conn.search))
print ("conn: {0}",format(conn))
conn.start_tls() #Session now on a secure channel. See output from following print statement and "tls started"
print ("conn_tls: {0}",format(conn))
d = conn.extend.standard.who_am_i()
print (d)
#print ("Server Info: {0}",format(server.info))
conn.open()
conn.bind()
# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "ou=ABC, dc=DEF, dc=com"
if conn.bind():
conn.search(
search_base=LDAP_AUTH_SEARCH_BASE,
search_filter= '(cn={})'.format(searchFilter), # This is the user being searched for
search_scope=SUBTREE # BASE & LEVEL also possible settings
)
entry = conn.entries[0]
res = conn.bind()
print (res)
return render(request, 'search_page.html', {'entry':entry})
The error message received on my webpage:
MultiValueDictKeyError at /login_ldap/
"'username'"
Request Method: GET
Request URL: http://127.0.0.1:8000/login_ldap/
Django Version: 1.11
Exception Type: MultiValueDictKeyError
Exception Value:
"'username'"
I assume this is related to the GET and no longer the POST method. Why is the request.method being automatically set to GET and not POST when implementing
this in Django? Is this class for the authentication in the correct location, in the views.py file or should there be a separate file for this?
What should be included in the settings.py exactly (related to BACKEND_AUTH)?
EDIT:
views.py
def login_view(request):
if request.POST:
username = request.POST['username']
print ("U:{0}".format(username))
password = request.POST['password']
print ("P:{0}".format(password))
user = authenticate(username=username, password=password)
print (user)
if user is not None:
if user.is_active:
login(request, user)
return redirect('index')
else:
messages.error(request, "User is not active in Database")
else:
print ("Please check your credentials!")
messages.error(request, "Please check your username and password!")
return render(request, 'login.html')
index.html
<div class="row">
<div class="col-lg-3"></div>
<div class="col-lg-6"><H1>This is the public page, Please Login</H1></div>
</div>
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login_ldap/$', login_ldap, name='login_ldap'),
url(r'^login/$', login_view, name='login'),
url(r'^logout/$', logout_view, name='logout'),
url(r'^change_password/$', change_password, name='change_password'),
url(r'^$', index, name='index'),
]
settings.py
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
search_page.html
{% load static %}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link href='{% static "login.css" %}' rel="stylesheet">
<div class="wrapper">
<form method='post' action="" class="form-signin">{% csrf_token %}
<h2 class="form-signin-heading">Please login</h2>
<input type="text" class="form-control" name="username" placeholder="Username" required="" autofocus=""/>
<br>
<input type="password" class="form-control" name="password" placeholder="Password" required=""/>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
</form>
</div>
You can use get() function to get the data.
if request.method == "GET":
print ("if statement executed")
username = request.GET.get('username')
For more reference you can see here,
MultiValueDictKeyError in Django
And about POST method you may require to import the csr_exempt and use the decorator before your view.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def myView(request):

Django Password Reset through TastyPie API causing tags in email to render incorrectly

I've built a password reset function for a django system that is exposed through a tastypie api. The rendering process looks like this
form = PasswordResetForm({'email': reset_email})
form.full_clean()
form.save({
'use_https': request.is_secure(),
'token_generator': default_token_generator,
'from_email': settings.DEFAULT_FROM_EMAIL,
'email_template_name': 'registration/password_reset_email.html',
'request': request
})
return self.create_response(request, { 'success': True })
I've used the standard Django password reset email template. When I call the endpoint, the http request gets rendered in some of the custom tags e.g
Markup:
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb36=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
Expected result:
Please go to the following page and choose a new password:
httt://www.myurl.com/password-reset
"Your username, in case you've forgotten: User Name
Actual result
Please go to the following page and choose a new password:
httt://{'request': , POST:, COOKIES:{}, META:{'CONTENT_LENGTH': '48', (...)
"Your username, in case you've forgotten: User Name
It strikes me as odd that the model based template tags render correctly, but the global ones (e.g. 'Site_name') and the reset url & token seem to break. I'm sure that's a good clue as to the cause of the problem, but I don't know where to go next.
Would be great if anyone can help.
Thanks

Issue with saving user information using django_registration

I am using django_registration v0.8 and using the docs here: http://readthedocs.org/docs/django-registration/en/latest/index.html
I have successfully installed the app, and I am using the default backend for my registration purposes.
I have tested this and I can get the form to show up properly at '/accounts/register'
However, one problem is that if I try and break the form input (different password1 and password2 or improper username), no validation errors are being invoked.
The issue also, is that the username, email, and password data is not being stored in auth_user, and the activation email isn't being sent.
From the default backend doc, "During registration, a new instance of django.contrib.auth.models.User is created to represent the new account, with the is_active field set to False. An email is then sent to the email address of the account, containing a link the user must click to activate the account; at that point the is_active field is set to True, and the user may log in normally."
I believe this new instance of django.contrib.auth.models.User is not being created.
I have also included the necessary email settings:
EMAIL_USE_TLS = True
EMAIL_HOST = "smtp.gmail.com"
EMAIL_HOST_USER = "Email"
EMAIL_HOST_PASSWORD = "Password"
EMAIL_PORT = 587
Any help on getting this straight? I am pretty sure I am missing something simple, but been trying to figure it out without any progress. Any help is greatly appreciated.
Sounds like the form is actually catching the error but you're just not seeing it. Do you have any code in your template that's checking for form errors? Something like the following could help you see if an error has occured:
{% if form.errors %}
<div class="lead">
<h3 class="error">
Please correct the error{{ form.errors|pluralize }} below.
</h3>
</div>
{% endif %}

django-registration Email Customizations

I am using django-registration, and have two questions with regards to customizing the email sent after a user has requested to reset his password.
This is what I currently have in password_reset_email.html:
{% load i18n %}
{% blocktrans %} Please click the link below to change your password:
{% endblocktrans %}
{% block reset_link %}{{ domain }}{% url auth_password_reset_confirm uidb36=uid, token=token %}
Thanks,
Mysite
{% endblock %}
And in my settings.py:
DEFAULT_FROM_EMAIL = 'Mysite'
I have two questions --
1) Currently the email is from Mysite, with return address 'Mysite'. How do I make it so it appears as Mysite, but the return address is 'Mysite#no-reply.com'?
2) Currently the subject of the email says 'Password reset on Mysite'How/where do I change the subject of the reset-password email?
1) You should change your email setting to DEFAULT_FROM_EMAIL = 'Mysite <Mysite#no-reply.com>'
2) The last I checked, this was not changeable. django-registration has the subject line hardcoded.
EDIT:
Correction: The password reset subject line is set by Django's PasswordResetFormnot django-registration.
You can change the subject of the email in your <...>templates/registration/activation_email_subject.txt
Make sure that file exists, then put in it whatever you want.
Also, your email should be "no-reply#mysite.com" instead of mysite#no-replay.com.