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 account onboarding@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!