I wrote a simple contact form for a client in Django. However, whenever it sends e-mail, it wraps the header values in u'' objects. For example, the From: header is
From: (u'my#email.com',)
Here's the code that sends the message:
The form:
class ContactForm(forms.Form):
name = forms.CharField(max_length=100)
sender = forms.EmailField()
subject = forms.CharField(max_length=255)
message = forms.CharField(widget=forms.widgets.Textarea(attrs={'rows':15, 'cols': 72}))
The contact function:
def contact(request):
RECAPTCHA_PRIVATE_KEY = '******************'
captcha_error = ''
if request.method == 'POST':
form = ContactForm(request.POST)
captcha_response = captcha.submit(request.POST.get("recaptcha_challenge_field", None),
request.POST.get("recaptcha_response_field", None),
RECAPTCHA_PRIVATE_KEY,
request.META.get("REMOTE_ADDR", None))
if not captcha_response.is_valid:
captcha_error = "&error=%s" % captcha_response.error_code
elif form.is_valid():
name = form.cleaned_data['name'],
sender = form.cleaned_data['sender'],
subject = form.cleaned_data['subject'],
message = form.cleaned_data['message']
recipients = ['email#email.com']
try:
send_mail(subject, message, sender, recipients)
except BadHeaderError:
pass
flash_message = 'Thank you for contacting us. We will get back to you shortly.'
return render_to_response('pages/contact.html', {
'form': form,
'captcha_error': captcha_error,
'message': flash_message
})
It sends the e-mail perfectly, I check the appropriate mailbox and the e-mail appears. But these u'' objects prevent the e-mail's subject from appearing correctly and prevents it from being replied to.
What am I doing wrong?
Thanks in advance.
Lose the trailing commas here:
elif form.is_valid():
name = form.cleaned_data['name']
sender = form.cleaned_data['sender']
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
Related
Tests fail with an error response meaning that it is likely to be allowing email with wrong data and yet it should throw an HttpResponse as expected, I have tried to figure it out why my test is failing and returning 200 http status code but not as expected = 400.
reset password
class ResetPassword(View):
form_class = ForgetPasswordForm()
template_name = 'authentication/password_reset.html'
def get(self, request):
form = self.form_class
return render(request, self.template_name, {'form': form})
def post(self, request):
msg = None
form = ForgetPasswordForm(request.POST)
if form.is_valid():
data = form.cleaned_data.get('email')
associated_users = Users.objects.filter(Q(email = data))
if associated_users.exists():
for user in associated_users:
subject = 'Password Reset Requested'
email_template_name = "authentication/password_reset_email.txt"
c = {
"email": user.email,
'domain': '127.0.0.1:8000',
'site_name': 'ATB Project Organizer',
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'user': user,
'token': default_token_generator.make_token(user),
'protocol': 'http',
}
email = render_to_string(email_template_name, c)
try:
send_mail(subject, email, 'admin#example.com', [user.email], fail_silently=False)
except BadHeaderError:
return HttpResponse('Invalid header found')
msg = 'You have successfully reset your password!'
return redirect('/password_reset/done/')
else:
msg = 'No records found for this email, please make sure you have entered the correct email address!'
form = ForgetPasswordForm()
return render(request, 'authentication/password_reset.html', {'form': form, 'msg': msg})
Test to raise an exception
from django.test import TestCase
from django.urls import reverse
from django.core import mail
from django.contrib.auth import get_user_model
User = get_user_model()
class PasswordResetTest(TestCase):
def setUp(self):
self.user1 = User.objects.create_user("user1", email = "user1#mail.com", password = "password#121", orcid = '1234567890987654')
self.user2 = User.objects.create_user("user2", email = "user2#mail.com", password = "password#122", orcid = '1234567890987655')
self.user3 = User.objects.create_user("user3#mail.com", email = "not-that-mail#mail.com", password = "password#123", orcid = '1234567890987656')
self.user4 = User.objects.create_user("user4", email = "user4#mail.com", password = "passs", orcid = '1234567890987657')
self.user5 = User.objects.create_user("user5", email = "uѕer5#mail.com", password = "password#125", orcid = '1234567890987658') # email contains kyrillic s
self.user={
'username':'username',
'email':'testemail#gmail.com',
'password1':'password#123',
'password2':'password#123',
'orcid': '1234123412341239',
}
def test_user_can_resetpassword(self):
response = self.client.get(reverse('resetpassword'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'authentication/password_reset.html')
# Then test that the user doesn't have an "email address" and so is not registered
response = self.client.post(reverse('resetpassword'), {'email': 'admin#example.com'}, follow=True)
self.assertEqual(response.status_code, 200)
# Then test that the user doesn't have an "email address" and so is not registered
# Then post the response with our "email address"
# Then post the response with our "email address"
response = self.client.post(reverse('resetpassword'),{'email':'user1#mail.com'})
self.assertEqual(response.status_code, 302)
# At this point the system will "send" us an email. We can "check" it thusly:
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Password Reset Requested')
def test_exception_raised(self):
# verify the email with wrong data
data = {"uid": "wrong-uid", "token": "wrong-token"}
response = self.client.post(reverse('resetpassword'), data, format='text/html')
self.assertEqual(response.status_code, 400)
Error
File "../tests/test_passwordreset.py", line 55, in test_exception_raised
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
AssertionError: 200 != 400
Failing code
The default HTTP status code when you instantiate the HttpResponse class is 200 (OK). This is why your test fails.
Try this:
...
except BadHeaderError:
return HttpResponse('Invalid header found', status=400)
# Or more verbose:
# return HttpResponse('Invalid header found', status=HttpStatus.BAD_REQUEST)
...
or
...
except BadHeaderError:
return HttpResponseBadRequest('Invalid header found')
...
See the docs for more details.
Anyone know how to solved my issue, Im working with DJango-email with multiple recipient. Sending email in multiple recipient accounts from my DB are working, but now I want to send email and the email:body are depending on the Data ID.
This are the email list,
Scenario: Plate_No: 123123 will be send to example_email1#gmail.com only and ABV112 will be send again to example_email2#gmail.com and so on. Only the Plate_no assign in email will send, can someone help me to work my problem. Thank you!
auto send email script:
class HomeView(ListView):
cstatus = VR.objects.filter(Deadline__date = datetime.datetime.today(), sent_email="No")
print(cstatus)
recipient_list = []
for recipient in cstatus:
recipient_list.append(recipient.email)
print(recipient_list)
plate = ""
for carreg in cstatus:
print(carreg.plate_no)
plate = carreg.plate_no
if plate != "":
subject = 'FMS Automated Email'
html_message = render_to_string('vr/pms_email.html', {'content':cstatus})
plain_message = strip_tags(html_message)
from_email = 'FMS <fms#gmail.com>'
mail.send_mail(subject, plain_message, from_email, recipient_list, html_message=html_message, fail_silently=False)
cstatus.update(sent_email="Yes")
model = VR
context_object_name = 'list'
template_name = 'vr/list.html'
You can use a for-loop on your cstatus queryset to send the emails to the recipents. Did not test it, but it should look something like this:
for item in cstatus:
subject = 'FMS Automated Email'
html_message = render_to_string('vr/pms_email.html'{'content':item.Plate_no})
plain_message = item.Plate_no
recipent_list = [item.email]
from_email = 'FMS <fms#gmail.com>'
mail.send_mail(subject, plain_message, from_email, recipient_list, html_message=html_message, fail_silently=False)
item.update(sent_email="Yes")
According to what I understood regarding your query, this might what you need:
class HomeView(ListView):
cstatus = VR.objects.filter(Deadline__date = datetime.datetime.today(), sent_email="No")
print(cstatus)
recipient_list = {}
for recipient in cstatus:
recipient_list[recipient.plate_no] = recipient.email
print(recipient_list)
for carreg in cstatus:
print(carreg.plate_no)
plate = carreg.plate_no
if plate != "":
subject = 'FMS Automated Email'
html_message = render_to_string('vr/pms_email.html', {'content':carreg}) # or use plate for just plate_no
plain_message = strip_tags(html_message)
from_email = 'FMS <fms#gmail.com>'
mail.send_mail(subject, plain_message, from_email, [recipient_list[plate]], html_message=html_message, fail_silently=False)
cstatus.update(sent_email="Yes")
model = VR
context_object_name = 'list'
template_name = 'vr/list.html'
Or Use mass emailing in django:
link: https://docs.djangoproject.com/en/1.8/topics/email/#send-mass-mail
message1 = ('Subject here', 'Here is the message', 'from#example.com', ['first#example.com', 'other#example.com'])
message2 = ('Another Subject', 'Here is another message', 'from#example.com', ['second#test.com'])
send_mass_mail((message1, message2), fail_silently=False)
Add all the above message results in a tuple and add it in send_mass_mail. For eg.
datatuple = (
(subject, plain_message, from_email, to_email),
(subject, plain_message, from_email, to_email)
) # to_mail -> recipient_list[plate]
send_mass_mail(datatuple)
Let me know if I was wrong.
Ive built an contact form which sends an email. I'm just having a bit of trouble in relation to the account its being sent to. I want the email to be sent from "servwishes#gmail.com" to the "Contact_Email".
Right now the email is going from "Contact_Email" to "servwishes#gmail.com".
my views.py looks like this:
def contact(request):
Contact_Form = ContactForm
if request.method == 'POST':
form = Contact_Form(data=request.POST)
if form.is_valid():
contact_name = request.POST.get('contact_name')
contact_email = request.POST.get('contact_email')
contact_content = request.POST.get('content')
template = get_template('users/contact_form.txt')
context = {
'contact_name' : contact_name,
'contact_email' : contact_email,
'contact_content' : contact_content,
}
content = template.render(context)
email = EmailMessage(
"New contact form email",
content,
"Creative web" + '',
['servwishes#gmail.com'],
headers = { 'Reply To': contact_email }
)
email.send()
return render(request, 'users/contact.html', {'form':Contact_Form })
And my setting.py looks like:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'servwishes#gmail.com'
EMAIL_HOST_PASSWORD = '*******'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
If you look at the order of your arguments and convert them from positional to keyword, you currently have:
email = EmailMessage(
subject="New contact form email",
body=content,
from_email="Creative web" + '',
to=['servwishes#gmail.com'],
headers = { 'Reply To': contact_email }
)
I think there were a couple of issues here. I think you probably meant to do:
from_email='"Creative web" <servwishes#gmail.com>'
But since you didn't get that, it messed up the order of your positional arguments.
To should be to=contact_email
The other issue is I think you are misunderstanding the 'Reply To' header. That's who, when the recipient hits the reply button, the email will be sent back to. It is not who you are sending the email to.
I'm trying to have a FORGOT PASSWORD? functionality in my website, I'm simply generating a token with a user id and then I send the form where they can update their password along with this token, but the problem is that I can't actually get that token after I click on the link, I get none, can someone tell me what I'm missing exactly? here's what I've done so far:
# generates the token with the user id
def get_reset_password_token(user_id, expires_in=1800):
return jwt.encode({'reset_password': user_id, 'exp': time() + expires_in},
app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8')
# verfies the token recovered from the link
def verify_reset_password_token(token):
try:
id = jwt.decode(token, app.config['SECRET_KEY'],algorithms=['HS256'])['reset_password']
except:
print("token was invalid.")
return None
return print("all good")
# sends email to the user containing reset password link
def send_password_reset_email(user_id, user_mail):
token = get_reset_password_token(user_id)
msg = Message('[El-menu] Password Reset Request', sender ='noreply#demo.com', recipients =[user_mail])
msg.body = f'''To reset your password, visit the following link:
{url_for('reset_password', token=token , _external=True)}
If you didn't make this request, ignore this email and no changes will be madeSincerely,
Sincerely,
El-menu Team
'''
mail.send(msg)
return print("email sent with token " + token +" to email " + user_mail, file=sys.stderr)
#app.route("/reset_password_request", methods = ["GET", "POST"])
def reset_password_request():
if request.method == "POST":
email = request.form.get("email")
# checks for valid mail
if not email:
error = "you must submit a valid email"
return render_template("reset_password_request.html", error = error)
# performs a query to find information about given email, whether it's in the system or not?
user = db.execute("SELECT * FROM users WHERE email= :email", email = email)
if user:
user_mail = user[0]['email']
user_id = user[0]['id']
send_password_reset_email(user_id, user_mail)
password_reset = "Password reset link has been sent to your email!"
return render_template("login.html", password_reset = password_reset)
else:
return render_template("reset_password_request.html")
#app.route('/reset_password/<token>', methods = ["GET", "POST"])
def reset_password(token):
if request.method == "POST":
print("trying to reset password now..", file=sys.stderr)
print(token, file=sys.stderr)
user_id = verify_reset_password_token(token)
print(user_id, file=sys.stderr)
if not user_id:
print("token is none", file=sys.stderr)
return redirect(url_for('index'))
print(user_id, file=sys.stderr)
password = request.form.get("password")
confirmation = request.form.get("confirmation")
# Ensure password was submitted
if not password:
error = "You must provide a password"
return render_template("reset_password.html", error = error)
# Ensure confirmation was submitted
elif not confirmation:
error = "You must provide a password confirmation"
return render_template("reset_password.html", error = error)
reg = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d#$!#%*?&]{8,}$"
# compiling regex
pat = re.compile(reg)
# searching regex
mat = re.search(pat, password)
# validating conditions
if not mat:
error = "Password is weak"
return render_template("reset_password.html", error = error)
# Ensure Passwords match
if password != confirmation:
error = "Password and confirmation must match!"
return render_template("reset_password.html", error = error)
# Hash password
hashed_password = generate_password_hash(password)
db.execute("UPDATE users SET hash = :hash WHERE id = :id", hash = hashed_password, id = user_id)
return redirect("/")
else:
return render_template("reset_password.html")
I guess that's because the link you give {url_for('reset_password', token=token , _external=True)} in send_password_request_email makes a GET request so the user gets in reset_password and directly gets returned return render_template("reset_password.html")
You need to use render_template in order to render an email body that understands what token is.
So the first step would be to create an email template for the body of the email. The next step would be to use render_template and pass the token in.
Example from one of my Flask apps:
message = Message(
subject=render_template("email/reset_subject.txt"),
recipients=[user.email]
)
salt = current_app.config.get("SECURITY_PASSWORD_SALT", b"")
message.html = render_template(
"email/reset.html",
token=generate_code(user.email, salt=salt)
)
mail.send(message)
Here I am trying to redirect to another page if the form is submitted successfully but this code is not working properly .The code saves the form data sends the email , everything is fine but the problem is while redirecting to another page if the form succeed. The error I get is:
Django Version: 2.0.6
Exception Type: ValueError
Exception Value:
dictionary update sequence element #0 has length 0; 2 is required
context_processor.py
def volunteer_page2(request):
volunteer = Volunteer.objects.all().order_by('date')
if request.method == 'POST':
form = VForm(request.POST or None)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = "{0} with email address {1} has sent you new message \n\n{2}".format(name, email, form.cleaned_data['message'])
form.save(commit = False)
try:
send_mail(name, message, 'appname <settings.EMAIL_HOST_USER>', ['myemail'])
except:
return HttpResponse('Invalid header found')
form.save()
messages.success(request, 'Success')
return redirect('volunteer_page')
else:
messages.error(request, "Sorry try again")
else:
form = VForm()
return {'volunteer': volunteer, 'form':form}
views.py
def about_page(request):
about = About.objects.all().order_by('date')
banner = Banner.objects.all()
testimonial = Testimonial.objects.order_by('-pk')[0:2]
nav = Nav.objects.all()
footer = Footer.objects.all()
latest_event2 = Events.objects.order_by('-pk')[0:2]
context = {
'about': about,
'testimonial': testimonial,
'footer':footer,
'banner': banner,
'nav': nav,
'latest_event2': latest_event2,
}
return render(request, 'myapp/about.html', context)
settings.py
'myapp.context_processor.volunteer_page2'
Django's context processor should always return dictionary. In your code you are returning HttpResponse also. This is problem.