Laravel Contact Form: How to Implement It, Validate Data, and Send Emails

On April 02, 2024
11min read
Veljko Ristić Content Manager @ Mailtrap
This image is a symbolic graphic representation of Laravel contact form for an article that covers the topic in detail.

No need to beat around the bush. In this tutorial, I will tell you how to create a Laravel contact form, fetch and validate the data from it, then send an email using the contact form. 

Also, there’s a special section about email testing to ensure your contact form flow is running smoothly. I’ll use Mailtrap Email Delivery Platform SMTP and PHP SDKs to cover the testing and sending methods. 

How to create a contact form in Laravel?

Creating a contact form in Laravel involves several steps, from setting up your Laravel environment to handling form submissions. 

This guide assumes you know how to install Laravel and are familiar with its basic concepts. I’ll start by setting up a new project, creating the form, routing, and finally creating a controller to handle form submissions.

I won’t be adding any CSS styles and span class functions to help bootstrap the flow. The main focus is on data collection, validation, and email notifications. But feel free to customize the form to match the styles of your Contact page. 

Setting Up

First, ensure you have Composer installed on your machine as it’s essential for managing Laravel projects. Open your terminal and run the following command to create a new Laravel project:

composer create-project --prefer-dist laravel/laravel laravelContactForm

Navigate into your project directory:

cd laravelContactForm

Creating the Form

In Laravel, views are stored in the resources/views directory. You’ll create a blade file for your contact form here.

  1. Create a Blade file: Inside resources/views, create a new file named contact.blade.php.
  2. Design the form: Edit contact.blade.php to include a simple contact form. Here’s an example:
<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
</head>
<body>
    <h1>Contact Us</h1>

    <form method="POST" action="{{ route('contact.submit') }}">
        @csrf {{-- Cross-Site Request Forgery protection --}}
        <label for="name">Name:</label><br>
        <input type="text" id="name" name="name" required><br>

        <label for="email">Email:</label><br>
        <input type="email" id="email" name="email" required><br>

        <label for="message">Message:</label><br>
        <textarea id="message" name="message" required></textarea><br>

        <input type="submit" value="Submit">
    </form>
</body>
</html>

This form includes basic fields for the user’s name, email, and message, and it uses POST to submit data.

Pro Tip: If you want to use JavaScript with Laravel, you need to add the JS code to the blade php file. The injection doesn’t happen on auto when you compile the files. 

Routing

To display your form, you need to define a route that returns the view containing your contact form. Open the routes/web.php file and add the following route:

use Illuminate\Support\Facades\Route;

Route::get('/contact', function () {
    return view('contact');
})->name('contact');

Creating a controller

To handle form submission, you’ll need a controller.

  1. Generate a controller: Use Artisan, Laravel’s command-line tool, to generate a new controller:
php artisan make:controller ContactFormController
  1. Open the newly created: app/Http/Controllers/ContactFormController.php file and add a method to handle the form submission:
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ContactFormController extends Controller
{
    public function submit(Request $request)
    {
        // Here you will handle the form submission, like validating input and sending emails.
        return back()->with('success', 'Thank you for your message!');
    }
}
  1. Update your routes: Modify routes/web.php to use the controller for form submission:
use App\Http\Controllers\ContactFormController;

Route::get('/contact', function () {
    return view('contact');
})->name('contact');

Route::post('/contact', [ContactFormController::class, 'submit'])->name('contact.submit');

Now, when the form is submitted, it will trigger the submit method in your ContactFormController, where you can add validation, email sending logic, and more.

How to collect data from a Laravel contact form

Once you have your contact form set up in Laravel, the next steps involve collecting the data submitted by users. Laravel makes it easy to handle form data securely with built-in features like CSRF protection and the Request object for data collection. 

Form submission

To ensure the form submits data correctly and securely, you’ll need to use the POST method and include Laravel’s CSRF token in the form. 

This has already been demonstrated in the contact form creation section, but it pays to take a closer look.

Securing with CSRF Protection

Laravel automatically generates a CSRF “token” for each active user session managed by the application. This token is used to verify that the authenticated user is the one making the requests to the application.

When defining your HTML form, include the CSRF token as a hidden input field:

<form method="POST" action="{{ route('contact.submit') }}">
    @csrf
    <!-- Form fields here -->
</form>

The @csrf directive generates a hidden input field containing the CSRF token, ensuring your form submissions are protected against CSRF attacks.

Handling submission

After the form is submitted, the data is sent to the server where it can be captured and processed by your controller. 

The ContactFormController I created earlier will handle this process.

Capturing form data:

Laravel provides several ways to access the data sent through the HTTP request. The two most common methods are using the Request object or the request helper function. 

Here’s how you can use them in your ContactFormController:

Using the request object:

Modify the submit method in your ContactFormController to accept an instance of Request:

use Illuminate\Http\Request;

class ContactFormController extends Controller
{
    public function submit(Request $request)
    {
        // Capture the data
        $name = $request->input('name');
        $email = $request->input('email');
        $message = $request->input('message');

        // Process the data (e.g., validation, sending email)

        return back()->with('success', 'Thank you for your message!');
    }
}

Using the request helper function:

Alternatively, you can use the request helper function to access the request data without explicitly passing the Request object:

class ContactFormController extends Controller
{
    public function submit()
    {
        // Capture the data using the request helper
        $name = request('name');
        $email = request('email');
        $message = request('message');

        // Process the data

        return back()->with('success', 'Thank you for your message!');
    }
}

Both methods are equally valid, and the choice between them depends on your preference or the specific requirements of your project.

After capturing the data, you’d want to validate it to ensure the data meets certain criteria before processing or sending data to MySQL, SQLite, etc. 

How to validate and verify data from a contact form

Laravel provides a powerful form validation feature that is flexible and easy to use. Here, I’ll be exploring validation rules and the validation of custom messages. 

Validation rules

You can apply validation rules directly in your controller or through form request classes. For simplicity and directness, I’ll apply validation rules in the controller handling the form submission.

To validate the data received from the contact form, you can use the validate method provided by the Request object. 

The method takes an array where the keys are the form input names and the values are the rules you want to apply to these inputs.

Example of applying validation rules in Controller:

In your ContactFormController, modify the submit method to include validation logic:

use Illuminate\Http\Request;

class ContactFormController extends Controller
{
    public function submit(Request $request)
    {
        $validatedData = $request->validate([
            'name' => 'required|min:3|max:255',
            'email' => 'required|email',
            'message' => 'required|min:10',
        ]);

        // Process the data (e.g., sending email)

        return back()->with('success', 'Thank you for your message!');
    }
}

In this example, the name field must be present and must have a length between 3 and 255 characters. The email field must be present and be a valid email address. The message field is required and must be at least 10 characters long.

Custom messages

While Laravel’s default error messages for validation rules are quite clear, you might want to customize them to better fit your application or to provide translations. 

You can do this by passing a second array to the validate method, where the keys are the rule names and the values are the custom messages.

Example of custom validation messages:

$messages = [
    'name.required' => 'We need to know your name!',
    'email.required' => 'Don't forget your email address!',
    'email.email' => 'Please provide a valid email address.',
    'message.required' => 'A message is required to submit the form.',
];

$validatedData = $request->validate([
    'name' => 'required|min:3|max:255',
    'email' => 'required|email',
    'message' => 'required|min:10',
], $messages);

This modification allows you to provide a more personalized experience and clearer instructions to your users, which can help reduce frustration and improve the overall usability of your contact form.

Send an email from the Laravel contact form using SMTP

To send an email from your Laravel contact form, you’ll need to configure Laravel to use an SMTP server, generate a Mailable class for representing the email, and then modify your controller to send the email once the form is submitted and validated. 

We’ll use Mailtrap Email Sending to show you the flows. It gives gives developers an infrastructure with high deliverability rates by default and by design. 

Configuration

First, you need to configure Laravel to use Mailtrap’s SMTP server for sending emails. This involves setting up several environment variables in your .env file that Laravel will use to send emails.

  1. Set up Mailtrap: If you haven’t already, sign up for Mailtrap and add and verify your domain. Once verified, you can proceed to add the SMTP settings.
  1. Configure .env: Open your Laravel project’s .env file and update the SMTP settings with the ones provided by Mailtrap. Replace the placeholders with your actual Mailtrap credentials:
MAIL_MAILER=smtp
MAIL_HOST=live.smtp.mailtrap.io
MAIL_PORT=587
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="from@example.com"
MAIL_FROM_NAME="${APP_NAME}"

These settings tell Laravel to use Mailtrap’s SMTP server for email sending. And make sure you have the admin access to the domain you’ll use to send mail. 

Mailable class

Laravel uses “mailables” to encapsulate each email’s configuration and content. To create a mailable:

  1. Generate mailable: Run the following Artisan command to create a new mailable class named ContactMail:
php artisan make:mail ContactMail
  1. Customize mailable: Open the generated class at app/Mail/ContactMail.php. Customize it to include the data from your contact form and to use a view for the email’s content:
namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ContactMail extends Mailable
{
    use Queueable, SerializesModels;

    public $details;

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

   
public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Contact Mail',
        );
    }
public function content(): Content
    {
        return new Content(
            view: 'emails.contact',
        );
    }
public function attachments(): array
    {
        return [];
    }
}
  1. Create email view: Create a new Blade view at resources/views/emails/contact.blade.php for the email’s body. Customize this view to display the contact form submission data:
<!DOCTYPE html>
<html>
<head>
    <title>Contact Form Submission</title>
</head>
<body>
    <p>Name: {{ $details['name'] }}</p>
    <p>Email: {{ $details['email'] }}</p>
    <p>Message: {{ $details['message'] }}</p>
</body>
</html>

Sending email

After setting up the Mailable class and configuring Mailtrap, you’re ready to send emails from your contact form.

  1. Modify the Controller: Update the submit method in your ContactFormController to send the email using the validated data:
use Illuminate\Http\Request;
use App\Mail\ContactMail;
use Illuminate\Support\Facades\Mail;

class ContactFormController extends Controller
{
    public function submit(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|min:3|max:255',
            'email' => 'required|email',
            'message' => 'required|min:10',
        ]);

        Mail::to('destination@example.com')->send(new ContactMail($validated));

        return back()->with('success', 'Thank you for your message!');
    }
}

Replace destination@example.com with the email address where you want to receive the test submissions or use another Mailtrap inbox to capture these emails as well.

Send email from the Laravel contact form using API

If you want to automate the sending process, using Mailtrap API is more convenient. Also, Mailtrap has an official PHP SDK, making the whole setup more straightforward, as you won’t need to manually code the integration into your project. 

Note, that the SDK is compatible with Laravel 9.x and above, and here’s how to set it all up. 

Configuration

I assume that you already added and verified your domain with Mailtrap, so I won’t be covering those steps here. 

  1. Use Composer to install the dependencies and Mailtrap’s PHP client. 
composer require railsware/mailtrap-php symfony/http-client nyholm/psr7
  1. In the config/mail.php file, add Mailtrap transport. This transport needs to be set as default.
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Mailer Configurations
    |--------------------------------------------------------------------------
    */
    'mailers' => [
   
            // start mailtrap transport
            'mailtrap' => [
                'transport' => 'mailtrap'
            ],
            // end mailtrap transport
   
    ]
];
  1. Go to your .env file and add Mailtrap credentials 
MAIL_MAILER="mailtrap"
MAILTRAP_HOST="send.api.mailtrap.io"
MAILTRAP_API_KEY="YOUR_API_KEY_HERE"
  1. To set up new variables, run the clear configuration cache command. 
php artisan config:clear

Mailable class

  1. Use the snippet below to create a mailable class. 
php artisan make:mail WelcomeMail
  1. The app/Mail/WelcomeMail.php class configuration. 
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Attachment;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Mail\Mailables\Headers;
use Illuminate\Queue\SerializesModels;
use Mailtrap\EmailHeader\CategoryHeader;
use Mailtrap\EmailHeader\CustomVariableHeader;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Header\UnstructuredHeader;

class WelcomeMail extends Mailable
{
    use Queueable, SerializesModels;

    private string $name;

    /**
    * Create a new message instance.
    */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    /**
    * Get the message envelope.
    */
    public function envelope(): Envelope
    {
        return new Envelope(
            from: new Address('jeffrey@example.com', 'Jeffrey Way'),
            replyTo: [
                      new Address('taylor@example.com', 'Taylor Otwell'),
                  ],
            subject: 'Welcome Mail',
            using: [
                      function (Email $email) {
                          // Headers
                          $email->getHeaders()
                              ->addTextHeader('X-Message-Source', 'example.com')
                              ->add(new UnstructuredHeader('X-Mailer', 'Mailtrap PHP Client'))
                          ;

                          // Custom Variables
                          $email->getHeaders()
                              ->add(new CustomVariableHeader('user_id', '45982'))
                              ->add(new CustomVariableHeader('batch_id', 'PSJ-12'))
                          ;

                          // Category (should be only one)
                          $email->getHeaders()
                              ->add(new CategoryHeader('Integration Test'))
                          ;
                      },
                  ]
        );
    }

    /**
    * Get the message content definition.
    */
    public function content(): Content
    {
        return new Content(
            view: 'mail.welcome-email',
            with: ['name' => $this->name],
        );
    }

    /**
    * Get the attachments for the message.
    *
    * @return array<int, \Illuminate\Mail\Mailables\Attachment>
    */
    public function attachments(): array
    {
        return [
          Attachment::fromPath('https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-new-logo.svg')
                ->as('logo.svg')
                ->withMime('image/svg+xml'),
        ];
    }

    /**
    * Get the message headers.
    */
    public function headers(): Headers
    {
        return new Headers(
            'custom-message-id@example.com',
            ['previous-message@example.com'],
            [
                'X-Custom-Header' => 'Custom Value',
            ],
        );
    }
}

Sending email

  1. Under resources/views/mail/welcome-email.blade.php create a template. 
Hey, {{$name}} and welcome here 😉

<br>
Funny Coder
  1. In the app/routes/console.php file, add a CLI router. 
<?php

use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Mail;

/*
|--------------------------------------------------------------------------
| Console Routes
|--------------------------------------------------------------------------
|
*/

Artisan::command('send-welcome-mail', function () {
    Mail::to('testreceiver@gmail.com')->send(new WelcomeMail("Jon"));
    // Also, you can use specific mailer if your default mailer is not "mailtrap" but you want to use it for welcome mails
    // Mail::mailer('mailtrap')->to('testreceiver@gmail.com')->send(new WelcomeMail("Jon"));
})->purpose('Send welcome mail');
  1. To send the email, call the CLI command. 
php artisan send-welcome-mail

How to test your emails before sending?

Testing the emails from your contact form or Laravel application helps keep an eye on the contact form’s functionality. Plus, you’ll be able to confirm and validate the data received from the contact form. 

More importantly, it’s not uncommon for forms to handle bits and pieces of sensitive or private information about your users. Therefore, you have to be 100% none of the data is corrupted and that the submission system is working as intended. 

Now, I’ll show you how to run email tests using Mailtrap Email Testing SMTP and API methods. It’s an email sandbox to inspect and debug emails in staging, dev, and QA environments before sending them to recipients.

SMTP

I’m assuming you’re already a Mailtrap user, if not, click here to sign up. Anyway, here’s the quick integration flow. 

  1. After signing into the app, select Email Testing, then Inboxes and choose My Inbox
Mailtrap email testing My Inbox
  1. Under Integrations, click the drop-down and select the Laravel configuration in line with your project. 
Mailtrap email testing Integration selection
  1. Copy-paste the configuration into your email-sending script and run it. 
  2. In a matter of seconds, you’ll receive the email in your Inbox. 

Keep in mind that the Laravel configurations offered are exemplary. Feel free to customize them to your email template as you deem appropriate. 

API

Here, I’ll be using Mailtrap PHP SDK for testing purposes. It’s the most straightforward configuration that shares much the same steps as the API email sending method. 

To give you a clear idea of the flow and the scope, I’ll briefly revisit steps mentioned in the sending section, and provide the code only for one section that’s different. 

If you need additional information about the methodology, check the official GitHub docs

  1. Use composer to instally Symphony or Guzzle HTTP client. 
  2. In your config/mail.php, add Mailtrap transport. Again, the transport needs to be set as default. 
  3. [This step is different] In your env file, you need to change the variables to testing. It’s critical to set the MAILTRAP_API_KEY to sandbox and get your Inbox ID*, MAILTRAP_INBOX_ID.   
MAIL_MAILER="mailtrap"

MAILTRAP_HOST="sandbox.api.mailtrap.io"
MAILTRAP_API_KEY="YOUR_API_KEY_HERE"
MAILTRAP_INBOX_ID=1000001
  1. Run the command to clear configuration cache, the same as in the API sending method. 
  2. Create a mailable class and add the app/Mail/WelcomeMail.php class configuration. 
  3. Create a template under resources/views/mail/welcome-email.blade.php and add a CLI router in the app/routes/console.php file. 
  4. Run the CLI command to send the email. 

Note:

* Please find your MAILTRAP_INBOX_ID in the Inbox URL. See image reference below. 

Mailtrap email tesing Inbox ID

Wrapping up

This guide aimed to demystify the process of building, validating, and processing a Laravel contact form. With the basics in hand, the real adventure begins as you tailor your form to the unique requirements of your application. 

Laravel gives you the tools; how you wield them to enhance user engagement and ensure data integrity is up to you. Keep experimenting, learning, and growing your Laravel expertise with Mailtrap Email Delivery Platform.

Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.