DEV Community

Cover image for Building an HTML email form – Frontend and Backend
Veljko Ristic
Veljko Ristic

Posted on

Building an HTML email form – Frontend and Backend

There are two ways to create an HTML email form

  1. Use the mailto: address action element.
  2. Use backend script to handle data and send emails.

The first method is something you shouldn’t try. Sending form data directly to an email from a web form without server-side processing isn’t recommended due to security and privacy risks.

The following tutorial covers methods that include server-side scripting. And I added a special section to ensure that any sensitive information is encrypted and transmitted securely.

First, I cover the front end that sends an HTTP POST request to the backend. Next, I go into the backend to send emails, using Laravel, Java, Node.js, Python, or C#. Then, I’ll give you tips and some examples of security measures.

How to create an HTML contact form – Quick guide

As said, I’ll be covering the backend scripting for a few popular languages and frameworks. So, to make the HTML code easily integrated with the scripts, it’s critical to ensure the HTML form is universally compatible with each language.

Here’s how to create a simple HTML form:

Form structure
Start with a basic HTML form structure. The action attribute should be set to a generic handler, which can be specified in the backend script.

<form action="process-form" method="post" enctype="multipart/form-data">
  <!-- Form elements will go here -->
</form>
Enter fullscreen mode Exit fullscreen mode

Note: The enctype="multipart/form-data" is important if you plan to include file uploads. It’s compatible with all backend technologies. The backend scripts also feature exemplary snippets without the support for file uploads.

*Input elements *
As needed, you can include the following elements.

Text fields

<label for="name">Name:</label>
<input type="text" id="name" name="name">
Enter fullscreen mode Exit fullscreen mode

Message field

<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" cols="50">
</textarea>
Enter fullscreen mode Exit fullscreen mode

Message field notes:

  • <label for="message">: This label is associated with the textarea. The for attribute should match the idof the textarea, which helps with accessibility.

  • <textarea>: This is the element used for multi-line text input.

  • id="message": The ID of the textarea, which is referenced by the label.

  • name="message": The textarea name attribute is important as it’s the key that will be used to access this piece of data on the server side.

  • rows="4" and cols="50": These attributes define the size of the textarea. rowsspecifies the number of lines, and cols specifies the width in terms of character columns. You can adjust these numbers based on your layout requirements.

Email field

<label for="email">Email:</label>
<input type="email" id="email" name="email">
Enter fullscreen mode Exit fullscreen mode

Submit button

<input type="submit" value="Submit">
Enter fullscreen mode Exit fullscreen mode

Form action
The action attribute in the form should be a placeholder that will be replaced by the specific endpoint of your backend technology (Laravel, Java, Node.js, Python, or C#).

For instance, in Laravel, you might set it to a route defined in your web routes, while in Node.js, it might point to an Express.js route.

Backend integration (quick notes)

  • Laravel: Use a route in web.php to handle the form submission.
  • Java: Set up a servlet or a Spring Controller to process the form.
  • Node.js: Use an Express.js route to handle the POST request.
  • Python (Flask/Django): Define a view function or a Django view to process the form.
  • C# (ASP.NET): Use a controller action in an ASP.NET MVC application.

Processing form data
Each backend technology will have its way of accessing form data (e.g., request.getParameter() in Java, req.body in Node.js, request.form in Flask).

Ensure that the form data is properly validated and sanitized in the backend script to prevent security vulnerabilities.

Sending emails
Each backend will have a different method for sending emails. Use the respective libraries or frameworks available for each technology.

Pro tips:

  • You can also embed radio buttons or checkboxes in the form. Here I aimed for simplicity, focusing on the email and message, so there aren’t checkboxes and radio buttons.
  • Consider implementing CAPTCHA to prevent spam submissions and confirm that the form is being filled out by a human. Later, I’ll show you how to integrate Google’s reCAPTCHA.
  • It’s best to use a proper email-sending service like Mailtrap Email Delivery Platform to ensure your emails securely land at the desired address.

HTML email form with CSS styles

Without CSS, the form looks bland and might actually affect the conversions. So, I’ll make it more elegant, and the exemplary form below contains Name, Email, and Message fields, plus the Submit button.

The HTML form

<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div class="container">
        <form id="contact-form" action="process-form.php" method="post">
            <div class="form-group">
                <label for="name">Name:</label>
                <input type="text" id="name" name="name" required>
            </div>

            <div class="form-group">
                <label for="email">Email:</label>
                <input type="email" id="email" name="email" required>
            </div>

            <div class="form-group">
                <label for="message">Message:</label>
                <textarea id="message" name="message" rows="4" required></textarea>
            </div>

            <div class="form-group">
                <input type="submit" value="Submit">
            </div>
        </form>
    </div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Quick Explainer:

  • HTML Structure: The form is wrapped in a div with a class container for styling purposes. Each input field is enclosed in a div with a class form-group for better control over spacing and layout.
  • Required Fields: The required attribute in the input fields ensures that the form cannot be submitted without filling these fields. The CSS (style.css)
body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    margin: 0;
    padding: 0;
}

.container {
    width: 70%;
    margin: 30px auto;
    padding: 20px;
    background: #fff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.form-group {
    margin-bottom: 15px;
}

.form-group label {
    display: block;
    margin-bottom: 5px;
}

.form-group input[type="text"],
.form-group input[type="email"],
.form-group textarea {
    width: 100%;
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
    box-sizing: border-box;
}

.form-group input[type="submit"] {
    background-color: #5cb85c;
    color: white;
    padding: 10px 15px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

.form-group input[type="submit"]:hover {
    background-color: #4cae4c;
}
Enter fullscreen mode Exit fullscreen mode

Quick Explainer:

  • The body style sets the font and background color of the page.
  • The container class styles the form’s container with a white background, centered alignment, and a subtle box shadow for a modern look.
  • The form-group class provides spacing between each form element.
  • Input fields (text, email, textarea) are styled to take full width with some padding and border-radius for a pleasant rounded corner look. I changed the submit button type a bit. It’s styled with a green background color, which changes to a slightly darker green on hover for a subtle interactive effect. Reminder: Replace process-form.php (placeholder) in the form’s action attribute with the actual script that will process the form data.

JavaScript to enhance the form behavior

HTML provides only basic validation attributes. Whereas, JavaScript allows for more dynamic and responsive validation that can improve user experience. But note that this isn’t by any means a security measure.

However, it’s a much better approach to handling the form code and it can markedly improve user experience. For example, they won’t need to wait for the web page to refresh to see if the submission was successful.

Now, to create a JavaScript-enhanced HTML email form that works seamlessly with various backend technologies (like Laravel, Java, Node.js, Python, and C#), I’ll focus on two main aspects:

  1. Form validation
  2. AJAX submission Check the following code to see how it’s done.

*Form validation *

document.getElementById('contact-form').addEventListener('submit', function(event) {
    var nameInput = document.getElementById('name').value.trim();
    var emailInput = document.getElementById('email').value.trim();
    var messageInput = document.getElementById('message').value.trim();
    var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Simple email regex pattern

    if (nameInput === '') {
        alert('Please enter your name.');
        event.preventDefault();
    } else if (!emailPattern.test(emailInput)) {
        alert('Please enter a valid email address.');
        event.preventDefault();
    } else if (messageInput === '') {
        alert('Please enter your message.');
        event.preventDefault();
    }
});
Enter fullscreen mode Exit fullscreen mode

Pro Tip:

The script above relies on a simple regex to validate an email, and it works for exemplary purposes. But on production, assuming you’re getting a lot of submissions, it may return false positives or false negatives, unless the regex is a mile long.

To offset that, consider using a proper validation library such as:

  • AbstractAPI javascript-email-validation
  • Yup

Submitting form data with AJAX

I made script below universal so that it dynamically adapts to the server-side technologies.

document.getElementById('contact-form').addEventListener('submit', function(event) {
    event.preventDefault();

    var formData = new FormData(this);
    var actionUrl = this.getAttribute('action'); // Dynamically get the action URL

    var xhr = new XMLHttpRequest();
    xhr.open('POST', actionUrl, true);
    xhr.onload = function () {
        if (xhr.status === 200) {
            alert('Email sent successfully!');
        } else {
            alert('An error occurred while sending the email.');
        }
    };
    xhr.send(formData);
});
Enter fullscreen mode Exit fullscreen mode

Quick Notes:

  • Dynamic Action URL: Instead of hardcoding the action URL (like send-email.php), the script now dynamically retrieves the URL from the form’s action attribute. This means you can set the action URL to any server-side script (PHP, Java, Node.js, etc.), and the JavaScript will adapt accordingly.
  • Form Data: The FormData object is used to capture and send all the form data, making it easy to handle on the server side, regardless of the technology used.
  • Ensure that the endpoint (e.g., route in Laravel, or controller in ASP.NET) specified in the form’s action attribute can handle FormData sent via POST request.
  • Each backend technology will have its way of extracting and processing the data, but the front-end submission process remains consistent and universal.

Backed for HTML5 forms to send emails

I’ll give you backend script examples in five popular scripting languages. Note that the exemplary scripts are geared toward Mailtrap users.

HTML form email in PHP (Laravel)

The framework’s Mail class, combined with its view-based approach to email content, allows for easy and flexible email handling.

Before you proceed with the backend, you need to make some changes to frontend HTML file.
First create a view file, for example/resources/views/welcome.blade.php. Then, ensure the specified route is matching this ‘welcome’ view.

Note: Importing CSS and JS files parts are a little bit different from the original file. By default, these assets should be in the ‘public’ folder of your Laravel project.

<link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" >
<script src="{{ asset('js/app.js') }}" ></script>
Enter fullscreen mode Exit fullscreen mode

Set up Laravel for email sending
Before you can send emails with Laravel, you need to configure the mail settings in your .envfile. Laravel supports various mail drivers and here’s an example of setting up SMTP in the .env file:

MAIL_MAILER=smtp
MAIL_HOST=your_mailtrap_smtp_host.io
MAIL_PORT=2525
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=example@example.com
MAIL_FROM_NAME="${APP_NAME}"
Enter fullscreen mode Exit fullscreen mode

Replace the values with your Mailtrap mail server details. And if port 2525 doesn’t work for you, use 587.

Create a mailable class
Laravel uses “mailable” classes to encapsulate each email’s data and configuration. You can generate a new mailable class using the Artisan command:

php artisan make:mail ContactFormMail
Enter fullscreen mode Exit fullscreen mode

This command creates a new class in the App\Mail namespace. You can define the build method to configure the email’s subject, view, and data:

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Queue\SerializesModels;


class ContactFormMail extends Mailable
{
    use Queueable, SerializesModels;

    public $formData;

    public function __construct($data)
    {
        $this->formData = $data;
    }

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'emails.contact',
        );
    }

}
Enter fullscreen mode Exit fullscreen mode

Create the email view
Create a view (e.g., resources/views/emails/contact.blade.php) that Laravel will use for the email content. You can use Blade templating to dynamically populate data from the form:

<!DOCTYPE html>
<html>
<head>
    <title>New Contact Form Submission</title>
</head>
<body>
    <h1>Contact Form Submission</h1>
    <p>Name: {{ $formData['name'] }}</p>
    <p>Email: {{ $formData['email'] }}</p>
    <p>Message: {{ $formData['message'] }}</p>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Handle form submission in a controller
Important Note:

The frontend may prevent the default event when submitting the email form and just send an API call to the backend server. In this case, the API URL is /api/email. and the API request is handled in routes/api.php. To fix this, add the following line in the apip.php file. I omitted the ‘/api’ because of the structure of the project.

Route::post('/email', [EmailController::class, 'sendEmail']);
Enter fullscreen mode Exit fullscreen mode

In the controller that handles the form submission, use the Mail facade to send the email:

use Illuminate\Support\Facades\Mail;
use App\Mail\ContactFormMail;

public function sendEmail(Request $request)
{
    $formData = $request->all();

    Mail::to('receiver@example.com')->send(new ContactFormMail($formData));

    // Return response or redirect
}
Enter fullscreen mode Exit fullscreen mode

Security and validation
Ensure to validate and sanitize the form data to prevent security issues like XSS and injection attacks. Laravel provides a robust validation system that you can use in your controller:

$request->validate([
    'name' => 'required',
    'email' => 'required|email',
    'message' => 'required'
]);
Enter fullscreen mode Exit fullscreen mode

For more detailed guid on building HTML email form, please check our blog post in the link.

Top comments (0)