BadHeaderError using Flask with FlaskMail and Postfix on Ubuntu server - python

I'm running a fullstack website with Flask and SQLite. On the page I have a contact-section to let visitors send me an email. The contact-section consists of an HTML form which sends the information to the webserver via HTTP POST. The server itself uses the FlaskMail plugin to create the message and send it to the mail-server (in this case a postfix server I set up on the same server).
However, I'm getting a BadHeaderError every time I click submit.
I already looked for existing fixes and found an existing Stackoverflow question here. However, the solution there seems to be unrelated to my issue.
Relevant code from webserver.py (Flask python file):
app = Flask(__name__)
app.debug = True
app.config['MAIL_USERNAME'] = 'admin'
app.config['MAIL_PASSWORD'] = 'password'
app.config['MAIL_USE_TLS'] = True
mail = Mail(app)
#app.route('/contact', methods=['GET', 'POST'])
def contact():
lang = get_lang(request.headers)
if request.method == 'GET':
if lang == 'de':
return render_template('contact.html', lang=lang, title=title_de, descriptio$
else:
return render_template('contact.html', lang=lang, title=title_en, descriptio$
elif request.method == 'POST':
name = request.form['name']
email = request.form['email']
company = request.form['company']
message = request.form['message']
if not name:
flash('Please enter your name')
return redirect(url_for('contact'))
if not email:
flash('Please enter your e-mail address')
return redirect(url_for('contact'))
if not message:
flash('Please enter a message')
return redirect(url_for('contact'))
message += '\n\n'
message += ('Name: ' + name)
message += '\n\n'
message += ('Company: ' + company)
msg = Message(message, sender=email, recipients=['pawelczyk.johannes#gmail.com'])
mail.send(msg)
flash('You will receive an automatic confirmation mail')
return redirect(url_for('index'))
else:
flash('Bad request')
return redirect(url_for('index'))
Apache error log: pastebin
HTML:
<div id="contact-form-container">
<form id="contact-form" action="{{ url_for('contact') }}" method="post">
<div>
<div class="contact-form-row">
<h3 class="to-left">Name:</h3>
<input class="to-right" type="text" name="name" placeholder="Name">
</div>
<div class="contact-form-row">
<h3 class="to-left">E-Mail:</h3>
<input class="to-right" type="text" name="email" placeholder="E-Mail">
</div>
<div class="contact-form-row">
<h3 class="to-left">Firma (optional):</h3>
<input class="to-right" type="text" name="company" placeholder="Firma">
</div>
<h3 class="gap-over">Ihre Nachricht:</h3>
<textarea cols="40" rows="10" name="message"></textarea></br>
</div>
<div class="middle">
<input class="button" type="submit" value="Senden">
</div>
</form>
</div>

Related

Django web app mail using Sendgrid or Amazon SES - Not receiving emails

Thank you very much for helping people with software issues.
I'm developing a simple web application using Django, and I wanted to have a contact form so users can contact me for feedback and other topics. That mail would arrive in my Gmail for simpler communication.
I have followed many tutorials and update settings.py, forms.py, and views.py many times and I still have not received any email unless I send it via cmd like this:
from django.core.mail import send_mail
send_mail(
'Subject here',
'Here is the message.',
'validated email',
['validated email']
)
I have of course created accounts in both SendGrid and Amazon SES, validate the emails, and used the keys.
for views.py I have used these two contact views, one or the other, and I have modified any part of them many times trying to get the receive the email, also validated email is the email I used with SES or Sendgrid.
from django.shortcuts import render, redirect
from .forms import ContactForm
from django.core.mail import send_mail, BadHeaderError
from django.http import HttpResponse, HttpResponseRedirect
from django.conf import settings
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
subject = "Contact"
body = {
'first_name': form.cleaned_data['first_name'],
'last_name': form.cleaned_data['last_name'],
'email': form.cleaned_data['email'],
'message':form.cleaned_data['message'],
}
message = "\n".join(body.values())
try:
send_mail(subject, message, 'validated email', ['validated email'], fail_silently=False)
except BadHeaderError: #add this
return HttpResponse('Invalid header found.')
form = ContactForm()
return render(request, 'contact.html', {'form':form})
or
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
try:
first_name = request.POST.get('first_name')
last_name = request.POST.get('last_name')
email = request.POST.get('email')
message = request.POST.get('message')
send_mail(first_name, last_name, email, message, 'validated email', ['validated email'], fail_silently=False)
except BadHeaderError:
return HttpResponse('Invalid header found.')
return HttpResponse('Thank you')
form = ContactForm
return render(request, 'contact.html', {'form':form})
forms.py
from django import forms
class ContactForm(forms.Form):
first_name = forms.CharField(max_length = 50)
last_name = forms.CharField(max_length = 50)
email = forms.EmailField(max_length = 150)
message = forms.CharField(widget = forms.Textarea, max_length = 2000)
I have actually manipulated plenty of times the settings for both companies, quitting and adding code but any change seems to work.
Amazon SES settings.py
EMAIL_BACKEND = 'django_ses.SESBackend'
AWS_ACCESS_KEY_ID = '***CM7Y7'
AWS_SECRET_ACCESS_KEY = '***n8GKA+sp80cY'
AWS_SES_REGION_NAME = 'eu-west-2' #(ex: us-east-2)
AWS_SES_REGION_ENDPOINT ='email.eu-west-2.amazonaws.com' #(ex: email.us-east-2.amazonaws.com)
Sendgrid settings.py
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'apikey' # this is exactly the value 'apikey'
SENDGRID_API_KEY = 'SG.JFR****' # this is your API key
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_BACKEND = 'sgbackend.SendGridBackend'
SENDGRID_SANDBOX_MODE_IN_DEBUG = True
SENDGRID_ECHO_TO_STDOUT = True
form part of contact.html
<form class="border-right pr-5 mb-5" method="post" id="contactForm" name="contactForm">
{% csrf_token %}
<div class="row">
<div class="col-md-6 form-group">
<input type="text" class="form-control" name="first_name" id="first_name" placeholder="First name">
</div>
<div class="col-md-6 form-group">
<input type="text" class="form-control" name="last_name" id="last_name" placeholder="Last name">
</div>
</div>
<div class="row">
<div class="col-md-12 form-group">
<input type="text" class="form-control" name="email" id="email" placeholder="Email">
</div>
</div>
<div class="row">
<div class="col-md-12 form-group">
<textarea class="form-control" name="message" id="message" cols="30" rows="7" placeholder="Write your message"></textarea>
</div>
</div>
<div class="row">
<div class="col-md-12">
<input type="submit" value="Send Message" class="btn btn-primary rounded-0 py-2 px-4">
<span class="submitting"></span>
</div>
</div>
</form>
In the command prompt and using the developer's tools of chrome and firefox, everything seems to work, but I'm not receiving any email in my Gmail account not also in the spam folder. I would really appreciate it if you can please help me because I have checked plenty of tutorials and posts, editing many code but still not seeing it working. Thank you very much in advance any suggestion will be welcome.

Flask Error, in Python script does not work

unfortunately my script no longer works in Flask. I don't know how to fix this. I would be very grateful if you could help me. Here are my codes:
#app.route("/register", methods=["GET", "POST"])
def register():
if request.method == "POST":
username = request.form["uname"]
password = request.form["passwd"]
with open("user.txt", "r") as file:
file.write(username + "\n" + password)
return render_template("register.html")
<form action="/register" method="POST">
<div class="container">
<label for="usm"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="usm" required>
<label for="pwd"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="pwd" required>
<button type="submit" name="login">Login</button>
</div>
</form>
This is my error:
werkzeug.exceptions.BadRequestKeyError
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'uname'
Your form is sending a field named usm:
<input ... name="usm">
You're expecting a field named uname:
username = request.form["uname"]
The same stands for pwd/passwd.
Also, you can't .write() to a file opened with the "r" mode.

WTForms/flaskforms not retrieving data properly via submit button

So I'm just trying to get the submit button to work properly.
Work properly meaning to get the user input for email and password to be directed to my login.
Currently, it only redirects to the index.html, but I want it to go result with a redirect to either profile or error.
Here's the python part:
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in if credentials provided are correct."""
form = LoginForm(request.post)
# this is if its POST
if form.validate and request.method == 'POST':
email = request.form['email']
password = request.form['password']
if email == admin#gmail.com" and password == "admin":
return redirect(url_for('/home'))
else:
return redirect(url_for('/error'))
# this is if its GET
#return render_template("index.html", form=form)
This is the login form
class LoginForm(FlaskForm):
email = StringField('email', validators=[InputRequired()])
password = PasswordField('password', validators=[InputRequired()])
remember = BooleanField('remember me')
Here's the html part:
<div class="modal-body">
<form role="form">
<div class="form-group">
<div class="input-group">
<form method="POST" action="{{ url_for('login')}}">
{{ form.csrf }}
<dl style="width: 100%;">
<div class="form-group">
<form role="form">
<div class="form-group">
<div class="input-group">
{{ wtf.form_field(form.email) }}
{{ wtf.form_field(form.password) }}
</div>
</div> <!-- /.form-group -->
</form>
</div> <!-- /.form-group -->
<div style="margin-left: 70%;" class="checkbox">
{{ wtf.form_field(form.remember) }}
</div>
<div class="modal-footer">
<input class="btn btn-lg btn-primary btn-block" style="background-color: #3eb2a0;border-color: #3eb2a0;" type="submit" value="Sign In">
</div>
</dl>
</form>
</div>
</div>
</form>
</div>
Only problems i see with your code is one:
if email == admin#gmail.com" and password == "admin":
return redirect(url_for('/home'))
You do not have a quotation mark before admin#gmail.com
two:
return redirect(url_for('/home'))
is there a reason for the forward slash? have you tried 'home'
edit:
Here is an example of how i set up views that are similar to yours
#bp.route('/upvote', methods=['GET', 'POST'])
def view():
form = key()
if form.validate_on_submit():
received_key = form.key_code.data
url = form.url.data
username = form.username.data
return redirect(url_for('views.success')) #views is the name of the blueprint the success route is in
return render_template('upvote.html', title='title here', form=form)
form.validate_on_submit():
Takes the place of form.validate and form.submit.data/if response.method ='POST'
and you can then retrieve the data stored in the forms by form.variable.data.
Check to see if you are even receiving data back from the forms at all. It seems like it might not be recieving the post request and skipping everything under your "if request.method = 'POST'" statement.
Your view would look like:
#app.route("/login", methods=["GET", "POST"])
def login()
form = LoginForm()
# this is if its POST
if form.validate_on_submit():
email = form.email.data
password = form.password.data
if email == "admin#gmail.com" and password == "admin":
return redirect(url_for('home'))
else:
return redirect(url_for('error'))
#return render_template("index.html", form=form)

Flask authentication (login page)

I'm trying to create a login page using flask and when they enter their correct credentials they will pass, but even when they enter a wrong password and username they will pass anyway!
my form index.html
<form method="post" action="/" role="login">
<h3>ADMIN LOGIN</h3>
<div class="form-group">
<input type="text" name="username" required class="form-control" placeholder="Enter Username" />
<span class="glyphicon glyphicon-user"></span>
</div>
<div class="form-group">
<input type="password" name="password" required class="form-control" placeholder="Enter password" />
<span class="glyphicon glyphicon-lock"></span>
</div>
<button type="submit" name="go" class="btn btn-primary btn-block">Login Now</button>
Reset password
</form>
My identityFace.py as my main
from flask import Flask, session, render_template, request, redirect, g, url_for
import os
import model as dbHandler
app = Flask(__name__)
app.secret_key = 'development key'
#app.route('/', methods=['POST', 'GET'])
def home():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# dbHandler.insertUser(username, password)
users = dbHandler.retrieveUsers()
return render_template('home.html', users=users)
else:
return render_template('index.html')
if __name__ == '__main__':
app.run()
and my model.py is
import sqlite3 as sql
def retrieveUsers():
con = sql.connect("ExamsFaceId.db")
cur = con.cursor()
cur.execute("SELECT username, password FROM users")
users = cur.fetchall()
con.close()
return users
It doesn't return an error.
All you did want query for all the users in the database. Nowhere did you verify the entered information
Try implementing your own userExists(username, password) function against the database.
For example,
'SELECT username WHERE username=%s AND password=%s'
Then return cur.rowcount > 0
Back in Flask, check if not db.userExists(username, password), then redirect() back to login.
Alternatively, I think you should really just be using Flask-Admin + Flask-Security plugins because it'll give you this and fix your plain-text password problem.

Modal Sign Up and Login form on the same page

I have a dynamic web-page that should process two forms: a login form and a register form. I am using WTForms to process the two forms but I am having some trouble making it work, since both forms are being rendered to the same page. Actually, I have created 3 diferent pages for register, login and homepage.
#!/usr/bin/env python2.7
from flask import Flask, render_template, flash, request, url_for, redirect , session
from wtforms import Form, BooleanField, TextField, PasswordField, validators
from passlib.hash import sha256_crypt
from MySQLdb import escape_string as thwart
import gc
from connection import connection
from functools import wraps
class RegistrationForm(Form):
email = TextField('email', [validators.Length(min=6, max=50)])
password = PasswordField('password', [
validators.Required(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the Terms of Service and Privacy Notice (updated Jan 22, 2015)', [validators.Required()])
app = Flask(__name__)
app.secret_key = 'mysecretkey'
#app.route('/')
def homepage():
try:
return render_template("index.html")
except Exception as e:
return(str(e))
#app.route('/login/', methods=["GET","POST"])
def login_page():
error = ''
try:
c, conn = connection()
if request.method == "POST":
data = c.execute("SELECT * FROM users WHERE email = (%s)",
(thwart(request.form['email']),))
data = c.fetchone()[2]
if sha256_crypt.verify(request.form['password'], data):
session['logged_in'] = True
session['email'] = request.form['email']
flash("You are now logged in")
return redirect(url_for('homepage'))
else:
error = "Invalid credentials. Try Again."
gc.collect()
return render_template("sign-in.html", error = error)
except Exception as e:
flash(e)
error = "Invalid credentials. Try Again!"
return render_template("sign-in.html", error = error)
#app.route('/register/', methods=["GET","POST"])
def register_page():
try:
form = RegistrationForm(request.form)
if request.method == "POST" and form.validate():
email = form.email.data
password = sha256_crypt.encrypt((str(form.password.data)))
c, conn = connection()
x = c.execute("SELECT * FROM users WHERE email = (%s)",
(email,))
if int(x) > 0:
flash("That email adress is already in use.")
return render_template('register.html', form=form)
else:
c.execute("INSERT INTO users (email, password) VALUES (%s, %s)",
(thwart(email), thwart(password)))
conn.commit()
flash("Thanks for registering!")
c.close()
conn.close()
gc.collect()
session['logged_in'] = True
session['email'] = email
return redirect(url_for('homepage'))
return render_template("sign-up.html", form=form)
except Exception as e:
return(str(e))
This is my login HTML:
{% block body %}
<div class="container">
<br>
<h4>Please Login:</h4>
<br>
<form action="" class="form-inline" method="post">
<input type="text" class="form-control" placeholder="Email" name="email" value="{{request.form.email}}">
<input type="password" class="form-control" placeholder="Password" name="password" value="{{request.form.password}}">
<input class="btn btn-default" type="submit" value="Login">
</form>
</div>
{% endblock %}
</body>
And this is my register.html:
{% block body %}
<div class="container">
<h4>Register</h4>
<br>
{% from "_formhelpers.html" import render_field %}
<form method="post" action="http://lapatrat.pythonanywhere.com/register/">
<dl>
{{render_field(form.First_Name)}}
{{render_field(form.Second_Name)}}
{{render_field(form.Grade)}}
{{render_field(form.username)}}
{{render_field(form.email)}}
{{render_field(form.password)}}
{{render_field(form.confirm)}}
{{render_field(form.accept_tos)}}
</dl>
<p><input type="submit" value="Register"></p>
</form>
{% if error %}
<p class="error"><strong>Error:</strong>{{error}}</p>
{% endif %}
</div>
{% endblock %}

Categories