Email Verification (OTP)

Updated: 

Verify email addresses before the form is submitted. Visitors receive a 6-digit one-time code at the address they entered and must confirm it — the form cannot be submitted until the code matches. Unlike double opt-in, which validates the address only after you’ve already accepted the submission, OTP verification guarantees that every entry that reaches you carries a real, reachable mailbox.

Use Cases

  • High-stakes forms – Applications, B2B quote requests, and bookings where a mistyped or fake email means a lost lead you can never reply to.
  • Giveaways and contests – Stop throwaway and bot entries; each submission is tied to a mailbox someone actually controls.
  • Lead quality – Combine with the Enhanced Email Field (free-provider and disposable-domain blocking) for a complete email quality gate: only business addresses, and only verified ones.
  • Reducing spam – Bots that auto-fill forms cannot complete the verification step; the check is enforced on the server, so skipping the on-page widget doesn’t help them.

How to Use

  1. Navigate to WordPress Dashboard → Settings → Form Enhancer
  2. Locate “Email Verification (OTP)” in the Fields section and toggle it ON
  3. Open your form in the Fluent Forms editor and click your Email field
  4. Set “Require Email Verification (OTP)” to Yes
  5. Optionally adjust the Email Verification Error Message shown when someone tries to submit without verifying
  6. Save the form

Enabling the toggle automatically adds the new settings to email fields in your existing forms — no need to recreate anything.

What the visitor sees

  1. A “Verify email” button appears below the email field
  2. After entering their address and clicking it, they receive a 6-digit code by email
  3. A code input appears with a “Confirm code” button (and a “Resend code” button with a 30-second countdown)
  4. Once the code matches, the field shows “Email address verified.” and the form can be submitted
  5. If they change the email address afterwards, the verification resets and the new address must be verified too

The buttons automatically pick up your form’s submit-button color, so the widget matches your form’s styling.

Key Features

Server-Side Enforcement

The verification is checked during form validation on the server. Hiding or manipulating the on-page widget does not bypass it — an unverified submission is always rejected with your configured error message.

Rate Limiting and Abuse Protection

LimitValue
Code validity10 minutes
Wrong guesses per code5, then the code is invalidated
Codes per email address3 per 10 minutes (cleared on successful verification)
Codes per IP address10 per hour

Codes are stored only as salted hashes, never in plain text. The endpoint refuses to send codes for forms that don’t have OTP enabled, so it cannot be misused to send unsolicited email. A temporary mail outage does not consume the visitor’s quota — only successfully sent codes count.

Works With Page Caching

The verification endpoints are designed to work on cached pages (no nonce that could go stale), the same approach Fluent Forms itself uses for submissions.

Clean Database

All verification data lives in self-expiring transients. Codes and counters are deleted as soon as they’re used, the verification proof is removed once the submission is stored, and uninstalling the plugin purges everything.

Customizable Emails

The verification email (subject and body) can be adjusted with filters:

add_filter('formenhancer/email_otp/mail_subject', function ($subject, $email, $form_id) {
	return 'Your code for Example.com';
}, 10, 3);

add_filter('formenhancer/email_otp/mail_body', function ($body, $code, $email, $form_id) {
	return 'Hi!' . PHP_EOL . PHP_EOL . "Your verification code is {$code}. It expires in 10 minutes.";
}, 10, 4);

Notes

  • Mail deliverability matters – The code arrives via wp_mail(), so use a proper SMTP setup (e.g. FluentSMTP) to keep codes out of spam folders and delivery fast.
  • Verification validity – A successful verification is valid for 30 minutes and for one submission; each stored submission requires its own verification.
  • Conditional logic – The verification widget follows the email field: if conditional logic hides the field, the widget (and the requirement) is hidden with it.
  • Multiple email fields – Each OTP-enabled email field in a form is verified independently.
  • Translations – All visitor-facing texts are translatable via the plugin’s formenhancer text domain.