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
Related
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):
My app sits on Django 1.9.2 and Django REST Framework 3.3.2, with a single page app on the front-end. I must admit I'm new to Django but the docs are unmatched.
I'm trying to implement a custom PasswordResetForm view. My strategy is as follow:
User uses on a front-end form that POSTs data (email string) to an API endpoint (api/v1/password/reset) when she wants to reset her password.
If email is found in DB, send an email and return a successful response.
For part 1, here's the relevant code:
# urls.py
url(r'^api/v1/password/reset/?$', PasswordResetView.as_view(), name='password-reset-link')
-
# views.py
class PasswordResetView(GenericAPIView):
serializer_class = PasswordResetSerializer
permission_classes = (AllowAny,)
def post(self, request, *args, **kwargs):
# Use DRF serializer to validate data.
serializer = self.get_serializer(data=request.data)
# Ensure data is valid before proceeding.
if serializer.is_valid() == False:
return Response('error': serializer.errors, 'message': 'Error while attempting to reset password'}, status.HTTP_400_BAD_REQUEST)
else:
# Ensure the user exists.
existing_user = get_user_model().objects.filter(
email=serializer.validated_data.get('email')
)
if not existing_user:
return Response({'error': {'code': 'email_not_in_db'}}, status.HTTP_404_NOT_FOUND)
# Validated data fed to a child class of PasswordResetForm.
form = UserForgotPasswordForm(serializer.validated_data)
if form.is_valid():
path = os.path.join(os.path.dirname(os.path.abspath(__file__ + '../../')), 'templates/registration/password_reset_email.html')
try:
# Save form, effectively attempting to trigger mail sending.
# Unfortunately an exception gets thrown!
form.save(from_email='no-reply#abc.xyz', email_template_name=path, request=request)
return Response({'message': 'Password reset request sent'}, status=status.HTTP_200_OK)
except Exception as e:
return Response({'error': str(e), 'message': 'Error while attempting to reset password'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
-
# forms.py
class UserForgotPasswordForm(PasswordResetForm):
email = forms.EmailField(required=True, max_length=254)
class Meta:
model = CustomUser
fields = ('email',)
-
# my_app/templates/registration/password_reset_email.html
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password-reset-link' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% endautoescape %}
-
But I get the following error:
Reverse for 'password-reset-link' with arguments '()' and keyword arguments '{'uidb64': b'MTI1', 'token': '4g9-f370fd6ee48d90a40b67'}' not found. 1 pattern(s) tried: ['api/v1/password/reset/?$']
Any idea why? What am I missing? Thanks for your help.
In the url in your html you are passing a token and a uidb64:
{{ protocol }}://{{ domain }}{% url 'password-reset-link' uidb64=uid token=token %}
However, in your actual url, you do not reference the token or uidb64:
url(r'^api/v1/password/reset/?$', PasswordResetView.as_view(), name='password-reset-link')
I would recommend changing your url to:
url(r'^api/v1/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', PasswordResetView.as_view(), name='password-reset-link')
Your URL named password-reset-link doesn't support the keyword arguments uidb64 and token that you're sending it. Those keyword arguments aren't just extra data, they need to match somewhere in the URL pattern.
According to the error, your URL pattern is:
api/v1/password/reset/?$
In order to support what you want you'd need to put two named arguments called <uidb64> and <token>. For example:
api/v1/password/reset/(?P<uidb64>[a-zA-Z0-9]+)/(?P<token>[a-zA-Z0-9]+)/?$
You'll have to adjust your regex to support the uidb64 and token formats.
I want to send a html email to some address.
This is part of my code:
views.py
def addNewEvent(request):
try:
eventStatus = EventStatus.objects.filter(event=request.GET["id"])[0]
#try to send the mail
html = get_template('mail.html')
d = Context({ 'username': usuario.name,'title':'Testing mail!!','eventStatusId': str(eventStatus.id)})
html_content = html.render(d)
msg = EmailMultiAlternatives('Testing yo','Skyforger!', 'mymail#gmail.com', [mail2#gmail.com])
msg.attach_alternative(html_content, "text/html")
msg.send()
print('EventStatus id '+str(eventStatus.id))
except Exception, e:
print ('the error %s',(str(e)))
response = getBaseJSON()
response["event_id"]= eventStatus.id
return HttpResponse(json.dumps(response), content_type="application/json")
mail.html
<html>
<body>
<h1>{{title}}</h1>
<h2>Hi {{username}}</h2>
<h3>Message to friend</h3>
<form action="http://localhost:8000/confirmEvent" method="POST">
{% csrf_token %}
<input type="hidden" name="id" value="{{eventStatusId}}">
<textarea name="message_to_friend"></textarea><br>
<input type="submit" value="I'LL BE THERE!!">
</form>
</body>
</html>
The mail is sent OK, but when its form is submitted, this error is displayed:
Forbidden (403)
CSRF verification failed. Request aborted.
I can't find how to solve that error.
I followed many answers like these:
https://stackoverflow.com/a/10388110
Forbidden (403) CSRF verification failed. Request aborted. Even using the {% csrf_token %}
with no success.
How can I send the form inside the html mail avoiding the CSRF error.
You can use the csrf_exempt decorator to disable CSRF protection for a particular view.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def someview():
Its not recommended to disable csrf , but you can try this if you want :)
I replaced render() by render_to_string() with the param context_instance=RequestContext(request) and now this is working.
def addNewEvent(request):
try:
eventStatus = EventStatus.objects.filter(event=request.GET["id"])[0]
#try to send the mail
html = get_template('mail.html')
d = Context()
html_content = render_to_string('mail.html',{ 'username': usuario.name,'title':'Testing mail!!','eventStatusId': str(eventStatus.id)}, context_instance=RequestContext(request))
msg = EmailMultiAlternatives('Testing yo','Skyforger!', 'mymail#gmail.com', [mail2#gmail.com])
msg.attach_alternative(html_content, "text/html")
msg.send()
print('EventStatus id '+str(eventStatus.id))
except Exception, e:
print ('the error %s',(str(e)))
response = getBaseJSON()
response["event_id"]= eventStatus.id
return HttpResponse(json.dumps(response), content_type="application/json")
Everything works fine and I get the Succes message i have set when the email is sent. But its just not sending email to the given address.
Also I get the following message in terminal when i submit the form, where the local server is running. I believe the 200 message means that the communication is successful.
"POST /submit/ HTTP/1.1" 200 10141
Given below my views.py, settings.py, forms.py and the template file.
views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from .forms import SubmitForm
from django.template import Context, loader
from django.core.mail import send_mail,EmailMessage
def submit(request):
success = False
success_message = " Thanks!"
form = SubmitForm(request.POST or None)
if form.is_valid():
original_title = request.POST.get('original_title')
english_title = request.POST.get('english_title')
sent_email = 'receive#email.com'
message_template = loader.get_template('submit.txt')
message_context = Context({ 'original_title':original_title,'english_title':english_title,
})
mail = EmailMessage(original_title, english_title, [sent_email])
mail.send()
success = True
return render_to_response('submit.html',
{'form' : form,'success': success,'success_message':success_message},
context_instance=RequestContext(request))
settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'sender#gmail.com'
EMAIL_HOST_PASSWORD = '*****'
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = 'Sample < example#gmail.com >
forms.py
from django import forms
from django.conf import settings
from django.core.cache import cache
from django.contrib.admin import widgets
from django.shortcuts import get_object_or_404
import os
class SubmitForm(forms.Form):
title = forms.CharField()
name = forms.CharField()
submit.html
<form method="post" action="{% url 'submit' %}" style="width:75%;margin:auto">{%csrf_token%}
<legend>Title</legend>
<br/>
<div class="row">
<dl class="field">
<dd><label>Title: *</label></dd>
<dt class="text">{{ form.name.errors }}
{{ form.original_title }}</dt>
<dd class="msg">You filled this out wrong.</dd>
</dl>
<dl class="field ">
<dd><label>English Title: *</label></dd>
<dt class="text">{{ form.name.errors }}
{{ form.english_title }}</dt>
<dd class="msg">You filled this out wrong.</dd>
</dl>
<input class="submit three columns" type="submit" value="Register"/>
I have added the submit.txt also in proper way. I get the success_message when i click submit but no email sent.
When you initialize an EmailMessage, the third argument is the from address. You appear to have a list containing the receiver's address instead.
Make sure you create your message in the same way as the docs:
email = EmailMessage('Hello', 'Body goes here', 'from#example.com',
['to1#example.com', 'to2#example.com'], ['bcc#example.com'],
headers = {'Reply-To': 'another#example.com'})
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.