Advertising sustains the DA. Ads are hidden for members. Join today

Webform Cookbook

How to programmatically validate Webform destination emails

Last updated on
13 December 2024

This page has not yet been reviewed by Webform Cookbook maintainer(s) and added to the menu.

This example shows how to extend Webform's EmailWebformHandler to validate a form, in this case to check recipient addresses in a Webform. An example use case is requiring that any Webform recipient is an internal user or organization account.  

In a custom class, use annotations to define a custom Webform handler and it's custom validateForm routine. In it we call parent::validateForm() to keep the original validation, but check the recipients list after. 

./my_module/src/Plugin/WebformHandler/MyModuleEmailValidation.php: 
<?php

namespace Drupal\my_module\Plugin\WebformHandler;

use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Plugin\WebformHandler\EmailWebformHandler;
use Drupal\webform\WebformSubmissionInterface;

/**
 * Custom email webform handler with additional validation.
 *
 * @WebformHandler(
 *   id = "my_module_email_validation",
 *   label = @Translation("Custom Email Validation"),
 *   category = @Translation("Notification"),
 *   description = @Translation("Webform handler retricting the domain(s) Webforms are sent to."),
 *   cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_UNLIMITED,
 *   results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
 * )
 */
class MyModuleEmailValidation extends EmailWebformHandler {

  /**
   * Allowed mail to domains.
   */
  const ALLOWED_RECIPIENT_DOMAINS = ['@harvard.edu', '@dfci.harvard.edu'];

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {
    // Call the parent validation.
    parent::validateForm($form, $form_state, $webform_submission);

    // Get the recipient addresses.
    $recipients = $this->getRecipients($webform_submission);

    // Skip empty or `_default` values.
    $recipients = array_filter($recipients, function ($email) {
      return $email !== '_default';
    });

    // Validate email domains.
    if (!$this->isEmailAllowed($recipients)) {
      $form_state->setErrorByName('to_mail', $this->t('An email (@emails) did not match allowed domains: @domains', [
        '@emails' => implode(', ', $recipients),
        '@domains' => implode(', ', self::ALLOWED_RECIPIENT_DOMAINS),
      ]));
    }
  }

  /**
   * Resolve Webform recipient emails.
   *
   * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
   *   The Webform submission.
   *
   * @return array
   *   The resolved recipient email addresses.
   */
  private function getRecipients(WebformSubmissionInterface $webform_submission) {
    $to_mail = $this->configuration['to_mail'] ?? '';

    $to_mail = \Drupal::token()->replace($to_mail, [
      'webform_submission' => $webform_submission,
      'user' => \Drupal::currentUser(),
    ]);

    // Provide an array, if a comma-separated string.
    return is_array($to_mail) ? $to_mail : array_filter(explode(',', $to_mail));
  }

  /**
   * Verify email domains are allowed.
   *
   * @param string|array $recipients
   *   The email addresses to check.
   *
   * @return bool
   *   TRUE if recipients are within allowed domains, FALSE otherwise.
   */
  private function isEmailAllowed($recipients) {
    $recipients = (array) $recipients;
    foreach ($recipients as $single_email) {
      $single_email = trim($single_email);
      if (!array_filter(self::ALLOWED_RECIPIENT_DOMAINS, fn($domain) => str_ends_with($single_email, $domain))) {
        return FALSE;
      }
    }
    return TRUE;
  }

}

In your module, replace Webform's default email handler with the extended version.

 my_module.module:
<?php

/**
 * @file
 */

use Drupal\my_module\Plugin\WebformHandler\MyModuleEmailValidation;

/**
 * Implements hook_webform_handler_info_alter().
 */
function my_module_webforms_webform_handler_info_alter(array &$handlers) {
  // Add custom validation to Webforms.
  if (isset($handlers['email'])) {
    $handlers['email']['class'] = MyModuleEmailValidation::class;
  }
}

 

Checking webform validation, ensure it has an email handler or, create one:

  1. Go to /admin/structure/webform/add.

  2. Create a Webform and Save it.

  3. Add these Webform elements to test with:

    • Email (single)

    • Email multiple (allows comma separated addresses)

  4. Click Save

  5. Then, edit Webform [xyz] > Settings > Emails/ Handlers: 

    • Edit an email handler 

    • Set it's Recipients to your Email or Email multiple field.

    • (Toggle which email field to test single vs comma separated emails)

  6. Click Save

Testing Validation

  1. View the new webform.

  2. Complete fields; and provide an invalid address.

  3. Click Submit

  4. Confirm error message:
    "Error: An email did not match allowed…"


Help improve this page

Page status: No known problems

You can: