How to programmatically validate Webform destination emails
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:
-
Go to /admin/structure/webform/add.
-
Create a Webform and Save it.
-
Add these Webform elements to test with:
-
Email (single)
-
Email multiple (allows comma separated addresses)
-
-
Click Save
-
Then, edit Webform [xyz] > Settings > Emails/ Handlers:
-
Edit an email handler
-
Set it's Recipients to your
EmailorEmail multiplefield. -
(Toggle which email field to test single vs comma separated emails)
-
-
Click Save
Testing Validation
-
View the new webform.
-
Complete fields; and provide an invalid address.
-
Click Submit
-
Confirm error message:
"Error: An email did not match allowed…"
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion