Building an HTML email form – Frontend and Backend
Tags: javascript, php, frontend, backend
Published: 2024-03-05 15:30:22

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>
```
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">
```

Message field

```
<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" cols="50">
</textarea>
```

Message field notes:

- `<label for="message">`: This label is associated with the `textarea`. The `for` attribute should match the `id `of 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`. `rows `specifies 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">
```
Submit button

```
<input type="submit" value="Submit">
```
**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>
```
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;
}
```
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();
    }
});
```
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);
});
```
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>
```
**Set up Laravel for email sending**
Before you can send emails with Laravel, you need to configure the mail settings in your `.env `file. 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}"
```
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
```

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',
        );
    }

}
```
**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>
```
**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']);
```
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
}
```
**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'
]);
```
For more detailed guid on [building HTML email form](https://mailtrap.io/blog/html-email-form/), please check our blog post in the link.