How to Create a Contact Form in WordPress: Complete Guide for Beginners

WordPress Contact Form: How to Create, Customize, and Fix Issues
Denys Romanov Denys Romanov 08 april 2026, 06:49 762
For beginners

Every WordPress website that serves a business, freelancer, or organization, needs a way for visitors to get in touch. A contact form handles that job. It sits on your page, collects a visitor's name, email, and message, and delivers the submission straight to your inbox,  without exposing your email address publicly.

This guide walks you through how to create a contact form in WordPress from start to finish. You'll learn the plugin route (fastest for most people), the manual route (no plugin required), and how to handle everything that comes after: embedding the form, customizing fields, styling, configuring SMTP for reliable delivery, blocking spam, staying GDPR-compliant, and troubleshooting the most common problems.

Whether you're building your first WordPress website or cleaning up a site that's been running without a proper contact form, this article has you covered.

Why Does a WordPress Website Need a Contact Form?

The most evident reason is professionalism. Posting a raw email address on your website invites problems. Spam bots constantly scrape publicly listed email addresses. Once your address lands on a spam list, you'll spend more time deleting junk mail than reading useful messages.

A contact form fixes that. It acts as a middleman, allowing visitors to type their message into the form, which sends it to your inbox, and your actual email address stays hidden from crawlers.

Beyond spam prevention, there are practical benefits that make a contact form a better option for most sites:

  • Lower friction for visitors: Clicking a mailto: link opens whatever email client the visitor has on their computer, which might not even be configured. A contact form lets them type and send without leaving your page.
  • Data you can act on: With a form, you choose what information you collect. Need a phone number? Add a field. Want visitors to pick a topic from a dropdown? Easy. That structured data is far more useful than a freeform email that might not contain half the details you need.
  • Spam filtering options: Contact forms can be paired with tools like reCAPTCHA, honeypot fields, and token-based validation. A plain email address has zero built-in protection.
  • Lead generation: If your site generates business leads, a contact form is one of the most direct conversion tools you have. Pair it with analytics, and you can track how many visitors actually reach out versus how many visit the page.
  • Consistency across devices: A mailto: link behaves differently on desktop, mobile, and tablets depending on what email client is set as the default. A contact form renders and works the same everywhere.

For small business owners and WordPress beginners, a working contact form is one of those things that seem minor but quietly affect how many people actually contact you. Skipping it means losing potential customers to inconvenience.

What Types of Contact Forms Can You Use in WordPress?

Not all contact forms are the same. The one you need depends on what you want it to do.

Simple Contact Forms

The most common type, containing three to five fields: name, email, optional subject, message text, and a submit button. This is what most business websites, blogs, and portfolios use. It handles general inquiries, and it loads fast due to minimalistic markup.

If your only goal is to let people reach you, a simple contact form is the right call. Overloading it with unnecessary fields reduces completion rates. People don't want to fill out ten fields just to ask a question.

Advanced Multi-Purpose Forms

When you need more than a basic message box, WordPress contact forms can be extended into more complex structures. These include:

  • Multi-step forms that break long questionnaires into pages. Useful for detailed service requests or application processes.
  • Conditional logic forms that show or hide fields based on previous answers. For example, selecting "Request a Quote" from a dropdown might reveal additional fields for project details, while "General Question" keeps the form short.
  • File upload forms that let visitors attach documents, images, or PDFs. Common for job application pages or support ticket systems.

Most of these advanced features require a premium form plugin or custom code. But the core of every WordPress contact form is the same: HTML markup, server-side processing, and an email delivery mechanism. Everything else is layered on top.

Now, let’s create a simple contact form using a WordPress plugin.

How to Create a Contact Form in WordPress Using a Plugin

Using a plugin is the fastest and most common way to add a contact form to a WordPress site. You don't need to write code, and most plugins give you a drag-and-drop builder that works inside the WordPress dashboard.

For this walkthrough, we're using WPForms. It's one of the most popular WordPress contact form plugins, and its free version (WPForms Lite) includes everything you need for a basic contact form.

Step 1: Install and Activate WPForms

Log in to your WordPress admin dashboard and navigate to Plugins in the left navigation menu. In the search bar, type “WPForms. Look for the listing titled "WPForms – Easy Form Builder for WordPress" and click Install Now

Installing WPForms

Once the installation completes, click Activate.

Activating WPForms

After activation, you'll see a new WPForms menu item in your left sidebar. That's your form builder.

WPForms menu

Now, when you hover your cursor around the newly added WPForms menu, you get a list of options for designing the contact form.

Step 2: Create a New Contact Form

Go to WPForms -> Add New Form. You'll be prompted to name your form. Something like "Contact Form" works fine.

Create a New Contact Form in WordPress

Below the name field, you'll see a list of pre-built templates. Select Simple Contact Form

Simple Contact Form in WordPress

Alternatively, you can use the out-of-the-box AI contact form builder provided by WordPress, which I think is really cool :)

After selecting Simple Contact Form, WPForms generates a form with three default fields: Name, Email, and Comment or Message. For a basic contact page, this is usually enough.

WPForms Contact Form

The contact form builder provides you with a simple drag-and-drop builder in the left panel. You can easily add more fields or do any necessary customizations, as described below.

Step 3: Customize Your Form Fields

The drag-and-drop builder lets you add, remove, or rearrange fields. On the left panel, you'll see available field types: single-line text, paragraph text, dropdown, checkboxes, number, email, and more.

To add a field, drag it from the left panel into the form preview on the right. To edit an existing field, click on it and modify as required.

A few practical tips for customizing fields:

  • Keep it short: Each field you add reduces the chance someone will complete the form. Stick to what you actually need.
  • Mark essential fields as required: Name, email, and message should all be required so you don't receive blank submissions.
  • Use placeholder text wisely: Placeholders inside fields can guide visitors (e.g., “john@example.com" for email), but don't rely on them as labels. They disappear once the user starts typing.

Step 4: Configure Form Settings and Save

Click the Settings tab in the form builder. Under General, you can set the submit button text, enable anti-spam protection, and configure the confirmation message visitors will see after submitting.

Configure Form Settings in WordPress

Under Notifications, make sure the email address receiving submissions is correct. By default, WPForms sends submissions to the WordPress admin email. You can change this to any other address or add multiple recipients separated by commas.

Under Confirmations, choose what to do after submission: show a message, redirect to a page, or redirect to a URL. For most contact forms, a simple "Thanks! We'll get back to you within 24 hours" message is enough.

Hit Save when you're done. Your form is now ready to embed.

Step 5: Add Contact Form to a Page

You can either place the form on an existing contact page or create a new one. To create a new contact form page, navigate to Pages -> Add Page, then enter a title for your page.

Next, add the form using the WPForms block. Click the Plus (+) button on the top-left to insert a block, search for “WPForms”, and select it. From the dropdown, choose the form you created earlier, and a preview of the form will appear in the editor.

Add WordPress Contact Form to a Page

Next, click Publish or Update to save your form. Your form has now been added to your website.

How to Create a Contact Form in WordPress Without a Plugin

Not everyone wants to install a plugin for a contact form. Maybe you're trying to keep your plugin count low for performance reasons, or you want full control over the form's behaviour. Creating a contact form in WordPress without a plugin is entirely possible; it just requires working with HTML, PHP, and CSS directly.

For a deeper dive into how WordPress handles email sending at the code level, check out the guide on How to Send Emails in WordPress.

Prerequisites

  • Basic experience with HTML, CSS, and PHP.
  • Knowledge of WordPress.

Step 1: Create a new HTML form inside WP Pages

To create a new HTML form inside WP pages, navigate to Pages -> Add Page, then enter a title for your page. On the top-left, click the (+) icon. In the search bar, enter “custom HTML”. Next, click “Custom HTML”.

Create a new HTML form inside WP Pages

The HTML editor opens up in your page editor:

WordPress Contact Form HTML editor

Step 2: Write custom HTML and CSS code for your form.

In the HTML editor, create the HTML structure for your form, and add CSS for styling. You can copy and paste the code sample below to get a beautiful form preview.

<style>
body {
    font-family: 'Inter', sans-serif;
    background: linear-gradient(135deg, #0f172a, #1e293b);
    margin: 0;
    padding: 40px 0;
}

#contact-form {
    max-width: 520px;
    margin: 0 auto;
    padding: 40px 30px;
    background: #ffffff;
    border-radius: 16px;
    box-shadow: 0 20px 50px rgba(0,0,0,0.25);
    position: relative;
    overflow: hidden;
}

/* Top accent bar */
#contact-form::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: 6px;
    width: 100%;
    background: linear-gradient(90deg, #6366f1, #06b6d4);
}

.form-group {
    position: relative;
    margin-bottom: 24px;
}

/* Inputs */
#contact-form input,
#contact-form textarea {
    width: 100%;
    padding: 14px 12px;
    border: 1px solid #cbd5e1;
    border-radius: 10px;
    outline: none;
    font-size: 14px;
    background: transparent;
    transition: all 0.25s ease;
}

#contact-form textarea {
    min-height: 120px;
    resize: none;
}

/* Focus effect */
#contact-form input:focus,
#contact-form textarea:focus {
    border-color: #6366f1;
    box-shadow: 0 0 0 3px rgba(99,102,241,0.2);
}

/* Floating labels */
.form-group label {
    position: absolute;
    top: 50%;
    left: 12px;
    transform: translateY(-50%);
    background: #fff;
    padding: 0 6px;
    color: #64748b;
    font-size: 13px;
    pointer-events: none;
    transition: 0.2s ease;
}

.form-group textarea + label {
    top: 20px;
    transform: none;
}

#contact-form input:focus + label,
#contact-form input:not(:placeholder-shown) + label,
#contact-form textarea:focus + label,
#contact-form textarea:not(:placeholder-shown) + label {
    top: -8px;
    font-size: 11px;
    color: #6366f1;
}

/* Button */
#contact-form button {
    width: 100%;
    padding: 14px;
    border: none;
    border-radius: 10px;
    background: linear-gradient(90deg, #6366f1, #06b6d4);
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

#contact-form button:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
</style>

<form id="contact-form" action="/wp-admin/admin-post.php" method="post">
    <input type="hidden" name="action" value="submit_contact_form">

    <div class="form-group">
        <input type="text" name="name" id="name" required placeholder=" ">
        <label for="name">Your Name</label>
    </div>

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

    <div class="form-group">
        <textarea name="message" id="message" required placeholder=" "></textarea>
        <label for="message">Your Message</label>
    </div>

    <button type="submit">Send Message</button>
</form>

The form includes Name, Email, and Message fields with a submit button, just like the plugin form of earlier, but the main upgrade is in the structure and styling. It uses a centered card layout with CSS gradients, box-shadow, and border-radius, while each input is wrapped in a .form-group to enable floating labels using :focus and :not(:placeholder-shown) selectors. Transitions and focus states improve interactivity, and the form still submits via POST to admin-post.php using a hidden action field for WordPress handling.

This is what the form preview looks like:

Сustom HTML and CSS code for WordPress Contact form

Step 3: Create a Function to Handle Form Submission

Open your theme's functions.php file (or better yet, your child theme's functions.php) and add a handler function that processes incoming form data. This function needs to do four things: verify the request is legitimate, check for spam, validate and sanitize the input, and send the email.

/**
* Process the custom contact form submission.
* Validates input, checks for spam, and sends an email
* to the site administrator.
*/
function process_contact_form_submission() {

    // Verify the nonce to block forged requests
    if (
        ! isset( $_POST['contact_nonce_field'] ) ||
        ! wp_verify_nonce( $_POST['contact_nonce_field'], 'submit_contact_form' )
    ) {
        wp_die( 'Security check failed. Please go back and try again.' );
    }

    // Honeypot -- if this hidden field has a value, it's a bot
    if ( ! empty( $_POST['website_url'] ) ) {
        wp_safe_redirect( home_url( '/contact/?status=sent' ) );
        exit;
    }

    // Sanitize inputs
    $name    = sanitize_text_field( $_POST['name'] ?? '' );
    $email   = sanitize_email( $_POST['email'] ?? '' );
    $message = sanitize_textarea_field( $_POST['message'] ?? '' );

    // Validate -- bail out if anything is missing or malformed
    if ( empty( $name ) || empty( $message ) || ! is_email( $email ) ) {
        wp_safe_redirect( home_url( '/contact/?status=error' ) );
        exit;
    }

    // Build the email
    $recipient = get_option( 'admin_email' );
    $subject   = sprintf( 'New message from %s (%s)', $name, $email );
    $body      = "Name: {$name}\nEmail: {$email}\n\nMessage:\n{$message}";
    $headers   = array(
        'Content-Type: text/plain; charset=UTF-8',
        'Reply-To: ' . $name . ' <' . $email . '>',
    );

    $sent = wp_mail( $recipient, $subject, $body, $headers );

    // Redirect back with a status indicator
    $status = $sent ? 'sent' : 'failed';
    wp_safe_redirect( home_url( '/contact/?status=' . $status ) );
    exit;
}

add_action( 'admin_post_nopriv_submit_contact_form', 'process_contact_form_submission' );
add_action( 'admin_post_submit_contact_form', 'process_contact_form_submission' );

This function runs when someone submits the contact form. It first checks the nonce token to confirm the request came from your site (is not forged), then inspects the website_url honeypot field to filter out bots. After that, it sanitizes and validates the name, email, and message fields, rejecting anything empty or malformed before passing the cleaned data to wp_mail(), which sends the message to your site's admin email with a Reply-To header pointing back to the visitor. Finally, it redirects the user to the contact page with a status parameter so your template can display a success or failure message.

A few things to note about the code:

  • Nonce verification is the first check that runs. WordPress nonces are single-use tokens that confirm the form submission originated from your site and not from an external source trying to forge a request. The wp_nonce_field() call in your form HTML generates the token, and wp_verify_nonce() here validates it. Without this step, your form is vulnerable to CSRF (cross-site request forgery) attacks.
  • The honeypot field is a hidden input in your form's HTML that legitimate visitors never see or interact with. Automated bots, however, tend to fill in every available field. If the honeypot contains any value on submission, the function quietly redirects the bot without sending an email. No error message, and no indication it was caught.
  • wp_safe_redirect() instead of wp_redirect() is the safer choice here. It restricts redirects to your own domain by default, which prevents open redirect vulnerabilities where an attacker could manipulate the redirect target.

Next, update your HTML code with the code below:

<form id="contact-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
    <input type="hidden" name="action" value="submit_contact_form">
    <?php wp_nonce_field( 'submit_contact_form', 'contact_nonce_field' ); ?>

    <!-- Honeypot: invisible to humans, traps bots -->
    <div style="position: absolute; left: -9999px;" aria-hidden="true">
        <input type="text" name="website_url" tabindex="-1" autocomplete="off" />
    </div>

    <div class="form-group">
        <input type="text" name="name" id="name" required placeholder=" ">
        <label for="name">Your Name</label>
    </div>
    <div class="form-group">
        <input type="email" name="email" id="email" required placeholder=" ">
        <label for="email">Email Address</label>
    </div>
    <div class="form-group">
        <textarea name="message" id="message" required placeholder=" "></textarea>
        <label for="message">Your Message</label>
    </div>
    <button type="submit">Send Message</button>
</form>


Two things are worth noting about the HTML changes. First, I swapped the hardcoded /wp-admin/admin-post.php path for <?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>. This generates the correct URL dynamically, so it still works if WordPress is installed in a subdirectory or if the admin path is ever changed. Second, the honeypot field is named website_url,  a name that looks legitimate to bots but won't conflict with your actual form fields.

Build a reusable shortcode with validation and spam protection

The entire form code from the previous section can be packaged into a shortcode. This keeps things maintainable. One shortcode renders the form anywhere, and a separate handler function processes submissions.

Step 1: Register the shortcode

In your functions.php, register a shortcode that outputs the form:

add_shortcode( 'custom_contact_form', 'render_contact_form_shortcode' );

Step 2: Build the callback function

The callback renders the form HTML and displays feedback messages based on the status query parameter set by the handler after submission.

function render_contact_form_shortcode() {
    ob_start();

    // Display feedback based on redirect status
    if ( isset( $_GET['status'] ) ) {
        switch ( $_GET['status'] ) {
            case 'sent':
                echo '<div class="success-message">Your message has been sent successfully.</div>';
                break;
            case 'error':
                echo '<div class="validation-message">Please fill in all fields with valid information.</div>';
                break;
            case 'failed':
                echo '<div class="validation-message">Something went wrong. Please try again.</div>';
                break;
        }
    }
    ?>

    <form id="contact-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
        <input type="hidden" name="action" value="submit_contact_form">
        <?php wp_nonce_field( 'submit_contact_form', 'contact_nonce_field' ); ?>

        <!-- Honeypot: invisible to humans, traps bots -->
        <div style="position: absolute; left: -9999px;" aria-hidden="true">
            <input type="text" name="website_url" tabindex="-1" autocomplete="off" />
        </div>

        <div class="form-group">
            <input type="text" name="name" id="name" required placeholder=" ">
            <label for="name">Your Name</label>
        </div>
        <div class="form-group">
            <input type="email" name="email" id="email" required placeholder=" ">
            <label for="email">Email Address</label>
        </div>
        <div class="form-group">
            <textarea name="message" id="message" required placeholder=" "></textarea>
            <label for="message">Your Message</label>
        </div>
        <button type="submit">Send Message</button>
    </form>

    <?php
    return ob_get_clean();
}

Drop [custom_contact_form] into any page or post, and the form renders wherever you place it. The actual submission processing is handled by the process_contact_form_submission() function we registered earlier with admin_post hooks.

Step 3: CSRF protection with nonces

The form already includes wp_nonce_field( 'submit_contact_form', 'contact_nonce_field' ), which generates a hidden token. On the server side, our handler verifies it before touching any data:

if (
    ! isset( $_POST['contact_nonce_field'] ) ||
    ! wp_verify_nonce( $_POST['contact_nonce_field'], 'submit_contact_form' )
) {
    wp_die( 'Security check failed. Please go back and try again.' );
}

A nonce (short for “number used once”) is WordPress's built-in defense against cross-site request forgery. It confirms the submission came from your form, not from a malicious third-party page trying to forge a request.

Step 4: Add reCAPTCHA

To block spam bots beyond the honeypot, add Google reCAPTCHA to the form. Register your site at the Google reCAPTCHA admin console to get a site key and secret key, then add the widget to your form and verify the response server-side.

Use reCAPTCHA v3 as it runs invisibly in the background and scores each submission from 0.0 (likely bot) to 1.0 (likely human), so users never have to solve image puzzles or tick checkboxes.

Heads up: Google is migrating all reCAPTCHA keys to Google Cloud projects, and the free tier is now capped at 10,000 assessments per month. If your site exceeds that volume, you'll start incurring charges. Cloudflare Turnstile is a solid free alternative without puzzle solving, Google Cloud account dependency, or usage caps.

Step 5: Fix email delivery

The wp_mail() function relies on your server's PHP mail() function, which is unreliable by nature. Emails often land in spam or don't arrive at all because there's no proper authentication.

The fix is to route emails through a dedicated SMTP service. Plugins like WP Mail SMTP, FluentSMTP (completely free), or Post SMTP replace the default wp_mail() transport layer and connect your site to services like UniOne’s SMTP. This drastically improves deliverability.

I'll cover how to set up a proper email-sending service in a later section.

Client-side validation with JavaScript

The PHP validation in our handler works ok, but when it catches invalid input, the user gets redirected back to the form and loses everything they typed. That's a fast way to lose people.

JavaScript validation prevents the redirect entirely. It checks the fields before the form hits the server and shows errors instantly:

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

    var name    = document.getElementById('name').value.trim();
    var email   = document.getElementById('email').value.trim();
    var message = document.getElementById('message').value.trim();

    var errors = [];

    if (name === '') {
        errors.push('Please enter your name.');
    }
    if (email === '' || !(/^[^@]+@[^@]+\.[^@]+$/.test(email))) {
        errors.push('Please enter a valid email address.');
    }
    if (message === '') {
        errors.push('Please enter a message.');
    }

    // Remove any previous error messages
    var existing = document.querySelectorAll('.validation-message');
    existing.forEach(function(el) { el.remove(); });

    if (errors.length > 0) {
        var form = document.getElementById('contact-form');
        errors.forEach(function(msg) {
            var div = document.createElement('div');
            div.className = 'validation-message';
            div.innerText = msg;
            form.insertBefore(div, form.firstChild);
        });
    } else {
        this.submit();
    }
});

The email regex in this example is intentionally made simple. It catches obvious typos but won't cover every edge case. For production use, especially on high-traffic sites or WooCommerce stores – consider a dedicated validation library, like one of these:

  • Validator.js: validation and sanitization methods
  • Parsley.js:  full form validation library
  • jQuery Validation Plugin: client-side form validation

Important: Use both layers. Never rely on client-side checks alone, since they can be bypassed by disabling JavaScript or submitting requests directly. JavaScript validation improves UX by giving instant feedback. Server-side PHP validation in process_contact_form_submission() is your safety net. 

How to Enable Email Notifications for Your Contact Form

This section shows you how to enable notifications for your hand-coded contact form, so you don’t miss out on submissions.

Step 1: Navigate to the WPForms menu builder

Open your form in the builder, then go to Settings -> Notifications. By default, one notification is already configured. The key fields to check are:

  • Send To Email Address:  This defaults to {admin_email}, which pulls the email from your WordPress general settings. Replace it or add additional addresses separated by commas if multiple people need to receive submissions.
  • Email Subject: Customize this so you can identify form submissions in your inbox at a glance. Something like "New Contact Form Submission from {field_id='1'}" (where field_id references the name field) is more useful than the generic default.
  • From Email: This should be an email address at your own domain (e.g., noreply@yourdomain.com), not the visitor's email. Setting the visitor's address here would cause deliverability issues because the email appears spoofed.
  • Reply-To: Set this to {field_id='2'} (the visitor's email field). This way, when you hit reply in your email client, it goes straight to the person who contacted you.

Step 2: Editing Contact Form 7

Open the form editor and click the Mail tab. You'll see fields for To, From, Subject, Additional Headers, and Message Body. The same principles apply: your domain email in From, the visitor's email in Reply-To (add it under Additional Headers as Reply-To: [your-email] where [your-email] is the mail tag for the email field).

For manually coded forms, if you used the wp_mail() approach from the earlier sections, email notifications are already built in. The $to, $subject, and $headers variables in your PHP code control where the email goes, what the subject line says, and how reply routing works.

How to Configure SMTP for WordPress Contact Forms

WordPress sends emails using wp_mail(), which relies on PHP's mail() function — no SPF checks, no DKIM signature, no authentication. To providers like Gmail or Outlook, these unauthenticated emails from a shared hosting server look like spam. They either land in junk or get silently dropped. Your visitor submits the form, WordPress confirms the send, but nothing arrives.

This isn't a WordPress bug; it's how PHP mail() works on most hosts. The fix is using an SMTP server, which routes emails through a dedicated mail server with proper credentials. The email gets verified sender information, passes authentication checks, and safely reaches the inbox. Think of it as upgrading from shouting across a crowded room to making a direct phone call.

To send emails via SMTP, you need an SMTP server. You may either use your own or the one provided by a dedicated mail service provider like UniOne.

Follow these steps to get started with UniOne’s SMTP relay service:

  1. Sign up for a free UniOne account here.
  2. Add and verify your domain name. To learn more, refer to our guide on Setting up the domain’s DNS records. Alternatively, as a new user, you can use the free, pre-verified sandbox domain, which is a temporary domain for testing your email sending functionality before setting up your production domain.
  3. Navigate to Settings -> SMTP Configuration to get your SMTP credentials for sending emails.

Now that you have your SMTP credentials ready, you can start sending emails with WordPress contact forms via SMTP. 

The most widely used plugin for this is WP Mail SMTP. Here's how to set it up:

Step 1: Install and activate WP Mail SMTP

Navigate to Plugins in the left navigation menu. In the search bar, type “WP Mail SMTP” 

Installing and activating WP Mail SMTP

Click Install Now, then Activate

Step 2:  Launch the setup wizard

To run the setup wizard, navigate to WP Mail SMTP -> Settings -> General -> Launch Setup Wizard.

Launching the WP Mail SMTP setup wizard

This wizard guides you through each step needed to fully set up WP Mail SMTP. 

Note: For the From Email address, use an email address on your UniOne-verified domain, or your pre-verified sandbox domain.

Step 3: Configure email service

After launching the setup wizard, you’ll be taken to a page that prompts you to select an email service for your SMTP configuration. There are several email service providers supported by WP Mail SMTP:

Configuring SMTP email service in WordPress

For the purpose of this tutorial, select Other SMTP. Next, click Save and Continue. 

On the next page, configure SMTP settings by providing the following details:

  • SMTP Host: smtp.eu1.unione.io or smtp.us1.unione.io (enter the one you’ve registered at)
  • Encryption: TLS (recommended) or SSL
  • SMTP Port: 587 for TLS or 465 for SSL
  • SMTP Username: Login number on UniOne’s SMTP Configuration page.
  • SMTP Password: Password on UniOne’s SMTP Configuration page.

Step 4: Send a test email

At the end of the step up, WP Mail SMTP sends a test email to your inbox. This is what it looks like:

Sending a test email in WordPress

Step 5: Verify SMTP with your custom contact form

With WP Mail SMTP configured and UniOne's credentials in place, the natural question is: do I need to go back and update the process_contact_form_submission() function we wrote earlier?

No. Here's why.

Look at the line in our handler that actually sends the email:

$sent = wp_mail( $recipient, $subject, $body, $headers );

This line calls WordPress's native wp_mail() function. Once WP Mail SMTP plugin is active, it intercepts every wp_mail() call across your entire site, including your custom contact form, password resets, WooCommerce receipts, plugin notifications, all of it. 

It reroutes those emails through the SMTP server you’ve specified, instead of PHP's default mail() function. Your form code stays exactly the same. The plugin handles the swap at a lower level.

So our handler keeps working as written. The only difference is what happens after wp_mail() fires. Instead of PHP tossing an unauthenticated message, WP Mail SMTP authenticates with UniOne using your credentials, and UniOne then attaches proper headers and delivers the email through infrastructure that Gmail, Outlook, and Yahoo actually trust.

One detail worth noting. Look at our handler's $headers array:

$headers = array(
    'Content-Type: text/plain; charset=UTF-8',
    'Reply-To: ' . $name . ' <' . $email . '>',
);

We're not setting a From header manually here, and that's intentional. WP Mail SMTP overrides the From address globally with the email you’ve configured earlier on Step 2. 

If you hardcode a From header in your function that doesn't match your verified domain, it creates a mismatch that email providers flag as suspicious. Let WP Mail SMTP handle From. Use Reply-To for the visitor's email so you can respond to them directly from your inbox.

How to Add reCAPTCHA to a Contact Form

To add reCAPTCHA to WPForms, go to WPForms -> Settings -> CAPTCHA. Select reCAPTCHA and choose your version (v2 or v3). 

Adding reCAPTCHA to Wordpress Contact Form

You'll need to register your site at Google's reCAPTCHA admin console to get a Site Key and Secret Key. Paste both keys into the WPForms settings page. After saving, open your form in the builder, and drag the reCAPTCHA field into the form layout. Next, click Save Settings.

For Contact Form 7, since version 5.1, reCAPTCHA v3 is integrated natively. Go to Contact -> Integration in your WordPress dashboard, find the reCAPTCHA section, and click Setup Integration. Enter your Site Key and Secret Key. Once saved, reCAPTCHA v3 is automatically applied to all your CF7 forms, with no shortcode edits required.

For manually coded forms, you'll need to load the reCAPTCHA JavaScript library in your template, render the widget in the form HTML, and verify the response token server-side using Google's API endpoint during PHP form processing.

How to Make a Contact Form GDPR-Compliant

If your website serves visitors in the European Union and you want to handle personal data responsibly, your contact form needs to comply with the General Data Protection Regulation.

GDPR requires that you collect personal data only with informed consent, that you explain what you do with that data, and that you store it securely. For a WordPress contact form, that translates to a few specific actions:

  • Add a consent checkbox: Before the submit button, include a checkbox (not pre-checked) with a label along the lines of: "I consent to having this website store my submitted information so they can respond to my inquiry. See our [Privacy Policy] for details". In WPForms, add a Checkboxes field with a single option and mark it as required. In Contact Form 7, use the [acceptance] tag.
  • Update your Privacy Policy: Your site's privacy policy page should explain that you collect data through a contact form, what data you collect (name, email, message), why you collect it (to respond to inquiries), how long you store it, and who has access. WordPress has a built-in Privacy Policy page template under Settings -> Privacy that gives you a starting point.
  • Limit data collection: Ask for information you actually need. Collecting a phone number, mailing address, and date of birth when all you need is a name and email violates the GDPR principle of data minimization.
  • Control data retention: Don't store contact form submissions indefinitely. If your form plugin saves entries in the database (as WPForms Pro does by default), set up a process to delete old entries regularly. Under GDPR, you should only keep personal data as long as it serves the purpose it was collected for.
  • Handle reCAPTCHA carefully: Google reCAPTCHA sends user data to Google's servers for analysis, which raises GDPR concerns. To stay compliant, disclose reCAPTCHA usage in your privacy policy, and consider loading the reCAPTCHA script only after the visitor interacts with the form rather than on every page load. Some GDPR-focused plugins like Real Cookie Banner can help manage this by deferring the reCAPTCHA script until the user gives consent.
  • Consider alternatives to Google reCAPTCHA. If GDPR compliance is a priority, GDPR-friendly anti-spam solutions exist. Honeypot fields don't send any data to third parties. Token-based anti-spam plugins that run entirely on your own server avoid the issue of third-party data transfers altogether.

Troubleshooting Common WordPress Contact Form Problems

You've built the form, embedded it, configured SMTP, and added spam protection. Everything should normally work without any troubles. Yet WordPress contact forms have some recurring issues that may trip up even experienced site owners. Here's how to diagnose and fix the most common ones.

Contact Form Not Sending Emails

This is the single most reported WordPress contact form issue, and the root cause is almost always the same: your site is trying to send emails through PHP's mail() function instead of an authenticated SMTP connection.

Here are some quick troubleshooting checks you can try out:

  • Check your spam and junk folders first: It sounds obvious, but a significant number of "missing" form emails are sitting in spam. If you find them there, mark them as "Not Spam" and proceed with the SMTP fix below. The emails are being sent, they're just not trusted by your mailbox provider.
  • Confirm SMTP is configured: If you haven't set up an SMTP plugin like WP Mail SMTP, do that now. Without SMTP, WordPress emails lack authentication headers (SPF, DKIM), and most email providers will either junk them or drop them silently. Refer to the SMTP section earlier in this guide for the full setup process.
  • Verify your From address: The "From" email in your form notification settings must match a real email address at your domain. If your site is example.com, the From address should be something like contact@example.com or noreply@example.com. Using a Gmail or Yahoo address as the sender while actually sending from a different server triggers spoofing filters and causes delivery failures.

In most cases, the above tips should help ensure that your emails are sent successfully. Yet, note that in some cases the recipients can still fail to get the emails even though they’ve been processed as needed – such cases might be a sign that you need to Improve Email Deliverability in general. 

Contact Form Emails Going to Spam?

Emails that send ok but land in spam share a common trait: they lack proper authentication. Email providers like Gmail, Outlook, and Yahoo evaluate incoming messages against several criteria, and failing any of them can push your email into the junk folder.

  • Missing SPF record: An SPF (Sender Policy Framework) record in your domain's DNS tells receiving servers which mail servers are authorized to send email on behalf of your domain. Without it, your form emails look unauthorized.
  • Missing DKIM signature: DKIM (DomainKeys Identified Mail) attaches a cryptographic signature to each outgoing email. The receiving server checks this signature against a public key in your domain’s DNS records. If the signature is missing or doesn't match, the email is treated as suspicious.
  • No DMARC policy: DMARC (Domain-based Message Authentication, Reporting, and Conformance) ties SPF and DKIM together and tells receiving servers what to do with emails that fail authentication checks. Having a DMARC record, even a basic one, improves your domain's reputation.
  • Mismatched From address: If your form sends notifications "from" an address that doesn't belong to the server sending the email, spam filters flag it immediately. This is the most common cause of contact form emails landing in spam.
  • Your server's IP is on a blacklist: Shared hosting environments deploy hundreds of sites on the same IP address. If one single site on that IP sends spam, the IP can get blacklisted, dragging your emails down with it. Using a dedicated transactional email provider (via SMTP) sidesteps this entirely because your emails route through the provider's clean, monitored IP pool.

To fix all of these issues, configure SMTP with a reputable email service and set up SPF, DKIM, and DMARC records for your domain. Your SMTP provider's documentation will give you the exact DNS entries to add.

For a comprehensive walkthrough on diagnosing and resolving deliverability issues, read the guide on how to stop my emails going to spam.

Conclusions

A WordPress contact form is not rocket science but still involves more than dropping a widget on a page. You need reliable email delivery (SMTP), spam protection (honeypot fields, reCAPTCHA), and if you serve EU visitors, then you need to think about GDPR compliance.

Use a plugin like WPForms or Contact Form 7 for speed, or build the form manually for full control. Either way, configure sending emails through an SMTP service like UniOne, so your emails actually arrive. If something breaks, check your SMTP credentials, DNS records, and plugin conflicts first. 

If you're looking to improve the reliability and performance of your WordPress email setup beyond the contact form, these UniOne tools can help:

  • SMTP Relay Service: UniOne's SMTP service handles transactional and marketing email delivery through a dedicated infrastructure. Integration takes minutes: configure your SMTP credentials in a plugin like WP Mail SMTP, and your WordPress emails will route through UniOne's authenticated servers. You get custom headers, visual dashboards, CSV data exports, and top delivery speed.
  • Email Integration: Connect your WordPress site, CRM, or marketing tools to UniOne's email platform through pre-built integrations. This is useful if your contact form feeds into a broader workflow, lead nurturing sequences, support ticket systems, or automated follow-ups.
  • Email Validation API: Reduce bounced emails and fake submissions by validating email addresses in real time. The API checks syntax, domain existence, and mailbox status before an email is ever sent. Integrating it with your contact form means fewer dead-end submissions and better sender reputation over time.

FAQ

What is the easiest way to create a contact form in WordPress?

Installing a plugin like WPForms Lite is the quickest and easiest method. After activation, you select a pre-built contact form template, customize the fields with a drag-and-drop builder, and embed the form on any page using a block or shortcode. The entire process takes about five minutes with zero coding.

Do I need reCAPTCHA on my contact form?

It depends on how much spam you receive. A honeypot field (included by default in many form plugins) catches most bot submissions. If you're still getting spam after enabling a honeypot, adding reCAPTCHA v3 (invisible to users) is a strong next step. Keep in mind that reCAPTCHA sends data to Google, so if GDPR compliance matters to you, disclose its usage in your privacy policy or consider server-side anti-spam alternatives.

How do I make my WordPress contact form GDPR-compliant?

Add a required consent checkbox to the form with a link to your privacy policy. Update the privacy policy to explain what data the form collects, why, how long it's stored, and who has access. Only collect the information you actually need. If you store form entries in your database, set up a retention schedule to delete old submissions. And if you use third-party services like reCAPTCHA, disclose that in your privacy policy as well.

Related Articles
Blog
For beginners
Franchise Email Marketing. How to Build a Reputation and Win Sales?
Learn practical tips and tricks on scaling your franchise business with email marketing.
Vitalii Piddubnyi
20 august 2025, 07:1615 min
Blog
For beginners
Email Delivery Issues: How to Identify and Fix Them?
Learn about the most common email delivery issues, and how to avoid them.
Valeriia Klymenko
29 january 2025, 13:4115 min
Blog
For beginners
Dedicated IP vs Shared IP: Which One Improves Deliverability?
The main differences between shared and dedicated IPs are explained easily.
Denys Romanov
02 june 2026, 20:2811 min