How to: HTML contact form with Flask and Resend
In this article, I will show you how to add a contact form to your Flask website using HTML.
But writing the HTML for the contact form is only half the job!
I will also show you how to send emails using Python, so that when a user submits the contact form you receive an email with the form contents.
Here is an example of what the HTML contact form will look like:
To make the contact form we will use HTML and optionally Bootstrap, and for the backend code we will use Flask and the Resend API.
Our app will have a unique endpoint called /contact
where the user will be able to write their name, email address, and a message. When the user submits the contact form, an email will be sent to the website owner with the information submitted by the user.
Initial setup to start coding the Flask app
To begin, set up your Python development environment. Check out this blog post if you're not sure how.
You'll also need a Resend account. For what we're doing in this blog post, it's free.
As a first step, create a Resend API key. Since we are only interested in sending emails, you can select the Send emails
permission only. Make sure that you copy the API key, as you will not be able to see it again.
Once you have the API key, create a .env
file in your project with the following contents:
RESEND_API_KEY=<Your Resend API Key>
ADMIN_EMAIL=<Your Resend email address>
The ADMIN_EMAIL
is the email address that will receive the contact form submissions. An important thing to consider is that unless you have a custom domain (costs money), you will only be able to send emails to the email address with which you signed up for Resend. They do this to prevent spam.
As always, if you are planning on uploading the code to a public repository, make sure to add the .env
file to your .gitignore
file.
Afterwards, create a requirements.txt
file with the following content in your working directory:
flask==3.0.0
python-dotenv==1.0.0
resend==0.5.2
Confirm that your virtual environment is activated, then, run the command:
pip install -r requirements.txt
Finally, add a .flaskenv
file with the following content:
FLASK_DEBUG=1
This will ensure the app will reload when you make changes to the code.
Creating a basic HTML contact form
In this step we will add a contact form with no styling (we will add styles later on).
To do this, create a templates
folder and add a user-contact-form-template.html
file with the following content:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Contact Form</title>
</head>
<body>
<h2>Contact Us</h2>
<form action="/contact" method="POST">
<div>
<label for="name">Name</label>
<input type="text" name="name" required/>
</div>
<div>
<label for="email">Email</label>
<input type="email" name="email" required/>
</div>
<div>
<label for="message">Message</label>
<textarea name="message" rows="4" required></textarea>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
</div>
</body>
</html>
Creating the Flask app
Adding the imports
Now that we have all set up, we can start working on our app. Let's create an app.py
file and add the imports:
import os
import resend
from flask import Flask, redirect, render_template, request
The resend
package is the official Python client for the Resend API. We will use it to send emails.
From flask
we import a few things:
- The
Flask
class to create a Flask app. redirect
to send users to a different page when they submit the contact form.render_template
to send our HTML to the user's browser.request
to access the data submitted by the user.
We'll use the os
module to access the environment variables we defined in the .env
file.
Loading the environment variables with Flask
When we have the python-dotenv
package installed, Flask will automatically load the .env
file when we start the app.
To access their values, we use os.environ
:
resend.api_key = os.environ["RESEND_API_KEY"]
ADMIN_EMAIL = os.environ["ADMIN_EMAIL"]
After these lines, create a variable to store the HTML that will be sent to the site owner.
Creating the email HTML body
CONTACT_EMAIL = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Message Notification</title>
</head>
<body>
<h2>New Message Received!</h2>
<p><strong>Name:</strong> {name}</p>
<p><strong>Email:</strong> {email}</p>
<p><strong>Message:</strong></p>
<blockquote>
{message}
</blockquote>
</body>
</html>
"""
Later, we will use the .format()
method to inject the variables name
, email
, and message
into the HTML template.
Security Warning
For security reasons, in a production environment, you should use a template engine like Jinja to render HTML templates instead of using the .format()
method.
Creating the Flask app object
Next, create the Flask app:
app = Flask(__name__)
Coding the Flask contact form endpoint
Our endpoint looks as follows:
@app.route("/contact", methods=["GET", "POST"])
def contact():
if request.method == "POST":
# Load form data
form_data = request.form.to_dict()
# Configuring the email fields
params = {
"from": "Your Flask App <onboarding@resend.dev>",
"to": [ADMIN_EMAIL],
"subject": f"New message from {form_data['name']}!",
"html": CONTACT_EMAIL.format(**form_data),
}
# Sending the email and catching response
response = resend.Emails.send(params)
# Handle the response
if response.get("id"):
return redirect("/contact")
else:
return {"message": "Something went wrong. Please try again."}
else:
# Render the contact form
return render_template("user-contact-form-template.html")
There are quite a lot of things going on here, so let's break it down!
As a first step, we check if the request method is POST
. If it is, it means that the user submitted the contact form, so we can proceed to send the email. If it is not, it means that the user is trying to access the /contact
endpoint, so we render the contact form:
@app.route("/contact", methods=["GET", "POST"])
def contact():
if request.method == "POST":
# Handle the form submission ...
else:
# Render the contact form
return render_template("user-contact-form-template.html")
If the request method is POST
, we load the contact form data into a dictionary using request.form.to_dict()
. The resulting dictionary will look like this:
{
'name': 'Some Name',
'email': 'example@email.com',
'message': 'Some message'
}
Next, we create a new dictionary with the filled email fields that we need to send the email:
@app.route("/contact", methods=["GET", "POST"])
def contact():
if request.method == "POST":
# Load form data
form_data = request.form.to_dict()
# Configuring the email fields
params = {
"from": "Your Flask App <onboarding@resend.dev>",
"to": [ADMIN_EMAIL],
"subject": f"New message from {form_data['name']}!",
"html": CONTACT_EMAIL.format(**form_data),
}
else:
# Render the contact form
return render_template("user-contact-form-template.html")
from
: since we haven't configured a DNS, we can only send emails with the default resend accountonboarding@resend.dev
.to
: it contains the administrator email loaded from the environment variable.subject
: we create a custom title by using f-strings to inject the name loaded from the for data.html
: contains the HTML body of the email. We use the.format()
method with keyword arguments provided by the dictionary keys to inject the custom content.
After filling in the email data, we send it using Resend API and catch the response:
@app.route("/contact", methods=["GET", "POST"])
def contact():
if request.method == "POST":
# Load form data
form_data = request.form.to_dict()
# Configuring the email fields
params = {
"from": "Your Flask App <onboarding@resend.dev>",
"to": [ADMIN_EMAIL],
"subject": f"New message from {form_data['name']}!",
"html": CONTACT_EMAIL.format(**form_data),
}
# Sending the email and catching response
response = resend.Emails.send(params)
# Handle the response
if response.get("id"):
return redirect("/contact")
else:
return {"message": "Something went wrong. Please try again."}
else:
# Render the contact form
return render_template("user-contact-form-template.html")
Exploring the Resend dashboard
Resend has a really helpful user interface where we can see information related to the emails we sent, here is an example of the overview menu:
And another example of how the requests and responses look like from Render's side:
Filling in the HTML contact form
Now that we have put all the pieces together, we can go to the terminal and run flask with the command:
flask run
Then, navigate to the URL http://localhost:5000/contact
, fill out the HTML contact form, and check out your mail inbox!
Remember that since we are using Resend's testing service, we can only send emails to the address we registered with.
Improve our HTML contact form with Bootstrap
To add Bootstrap 5 styles to our HTML contact form as shown in the first screenshot, replace the contents of the user-contact-form-template.html
with the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Contact Form</title>
<!-- Bootstrap CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossorigin="anonymous"
/>
<style>
/* You can add additional custom styles here if needed */
.contact-form {
max-width: 600px;
margin: 50px auto;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="container">
<div class="contact-form">
<h2>Contact Us</h2>
<form action="/contact" method="POST">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input
type="text"
class="form-control"
id="name"
name="name"
required
/>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input
type="email"
class="form-control"
id="email"
name="email"
required
/>
</div>
<div class="mb-3">
<label for="message" class="form-label">Message</label>
<textarea
class="form-control"
id="message"
name="message"
rows="4"
required
></textarea>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</body>
</html>
Conclusion
In this article we showed you how to send emails with the Resend API and Flask. We created an HTML contact form, processed the form data, populated the email fields and body with the form data, sent the email, handled the response, and finally we added custom Bootstrap 5 styling.
You can learn a lot more about web development with Flask with our course, Web Developer Bootcamp with Flask and Python. In it, we cover how to use Flask, HTML, and CSS, to build 4 different projects of increasing complexity. Check it out!