What Problems Does Email Verification Solve?
Losing a customer due to a typo: the client never receives the tracking link or invoice, and you lose the order. We solve this by implementing email validation at multiple levels. Fraud: disposable email addresses are frequently used for attacks or return abuse — each such order brings direct losses. Reduced deliverability: sending to a non-existent domain damages the sender's reputation.
Syntax‑only validation catches only 30% of errors; adding an MX‑record check boosts accuracy to 95% — three times more effective. Blocking disposable domains eliminates 5–10% of potentially problematic orders, saving the budget on returns and support.
Why Is Syntax‑Only Validation Not Enough?
Format‑only validation with filter_var does not catch domains without mail ([email protected]) or temporary addresses. That is why we add an MX‑record check and block disposable domains. The mandatory step is blocking disposable domains. This raises accuracy to 95% without sending an email.
What Does Checking the MX Record Give?
An MX (Mail Exchange) record indicates which server handles mail for a domain. If the record is absent, sending mail to that domain is impossible. The check via getmxrr() takes 50–500 ms. We cache the result per domain for 1 hour to avoid slowing down checkout. More information about MX records is available in the documentation.
According to 1C‑Bitrix documentation, the sale module events allow intercepting order placement.
Two Levels of Verification
Syntax + MX — minimal validation of format and DNS MX record. Fast, no email sent, catches typos and non‑existent domains.
Full verification via link — we send an email with a confirmation link; the user clicks to confirm. Reliable but requires an extra step. For most orders the first level is sufficient, with the option to enable the second for suspicious addresses.
Comparison of Levels
| Parameter | Syntax + MX | Full Verification |
|---|---|---|
| Speed | Instant | 1–2 minutes (waiting for email) |
| Accuracy | ~95% | ~99% |
| Disposable domain blocking | Yes | Yes |
| Ownership confirmation | No | Yes |
| Extra costs | None | Email template development |
Implementation of Syntax + MX Check
namespace Local\Validation;
class EmailValidator
{
public static function validate(string $email): ValidationResult
{
// Format
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return new ValidationResult(false, 'Invalid email format');
}
$domain = strtolower(substr(strrchr($email, '@'), 1));
// Disposable domains
if (self::isDisposable($domain)) {
return new ValidationResult(false, 'Temporary email addresses are not accepted');
}
// MX record check
if (!self::hasMxRecord($domain)) {
return new ValidationResult(false, 'Domain does not accept mail');
}
return new ValidationResult(true, '');
}
private static function isDisposable(string $domain): bool
{
$disposable = [
'mailinator.com', 'guerrillamail.com', 'tempmail.com',
'throwam.com', 'yopmail.com', '10minutemail.com',
'trashmail.com', 'dispostable.com', 'fakeinbox.com',
'getairmail.com', 'sharklasers.com',
];
return in_array($domain, $disposable, true);
}
private static function hasMxRecord(string $domain): bool
{
return (bool)@getmxrr($domain, $mxHosts);
}
}
Usage in Order Handler
AddEventHandler('sale', 'OnBeforeOrderFinalAction', function(\Bitrix\Sale\Order $order) {
if ($order->getId() > 0) return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);
$props = $order->getPropertyCollection();
$email = trim($props->getItemByOrderPropertyCode('EMAIL')?->getValue() ?? '');
if (empty($email)) {
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::ERROR,
new \Bitrix\Main\Error('Please provide an email to receive order confirmation')
);
}
$result = \Local\Validation\EmailValidator::validate($email);
if (!$result->isValid()) {
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::ERROR,
new \Bitrix\Main\Error($result->getError())
);
}
return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);
});
Full Verification via Link (for Authorized Users)
namespace Local\Validation;
class EmailVerificationService
{
public static function sendVerification(int $userId, string $email): bool
{
$token = bin2hex(random_bytes(32));
$exp = time() + 86400; // 24 hours
// Save token
$hlEntity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity(
\Bitrix\Highloadblock\HighloadBlockTable::getById(EMAIL_VERIFY_HLBLOCK_ID)->fetch()
);
$hlEntity->getDataClass()::add([
'UF_USER_ID' => $userId,
'UF_EMAIL' => $email,
'UF_TOKEN' => $token,
'UF_EXPIRES' => \Bitrix\Main\Type\DateTime::createFromTimestamp($exp),
'UF_CONFIRMED' => false,
]);
// Send email
$verifyUrl = 'https://' . SITE_SERVER_NAME . '/local/verify-email.php?token=' . $token;
return \CEvent::Send('EMAIL_VERIFICATION', SITE_ID, [
'EMAIL' => $email,
'VERIFY_URL' => $verifyUrl,
'EXPIRES_AT' => date('d.m.Y H:i', $exp),
]);
}
public static function confirmToken(string $token): bool
{
$hlEntity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity(
\Bitrix\Highloadblock\HighloadBlockTable::getById(EMAIL_VERIFY_HLBLOCK_ID)->fetch()
);
$dataClass = $hlEntity->getDataClass();
$row = $dataClass::getRow([
'filter' => [
'UF_TOKEN' => $token,
'UF_CONFIRMED' => false,
'>=UF_EXPIRES' => new \Bitrix\Main\Type\DateTime(),
],
'select' => ['ID', 'UF_USER_ID'],
]);
if (!$row) return false;
$dataClass::update($row['ID'], ['UF_CONFIRMED' => true]);
// Update flag in user profile
\CUser::Update($row['UF_USER_ID'], ['UF_EMAIL_VERIFIED' => 'Y']);
return true;
}
}
How to Speed Up Email Validation on the Client?
Provide fast feedback before form submission — validate syntax and show hints. An AJAX request to the server checks MX and disposable domains. This improves user experience and reduces incorrectly entered addresses.
const emailInput = document.querySelector('[name="ORDER_EMAIL"]');
emailInput?.addEventListener('blur', async () => {
const email = emailInput.value.trim();
if (!email) return;
// Client-side syntax check
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
showFieldError(emailInput, 'Check the email format');
return;
}
// Server check (MX + disposable)
const res = await fetch('/local/ajax/validate-email.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
}).then(r => r.json());
if (!res.valid) {
showFieldError(emailInput, res.error);
} else {
clearFieldError(emailInput);
}
});
// /local/ajax/validate-email.php
\Bitrix\Main\Application::getInstance()->initializeExtended();
$email = json_decode(file_get_contents('php://input'), true)['email'] ?? '';
$result = \Local\Validation\EmailValidator::validate($email);
header('Content-Type: application/json');
echo json_encode(['valid' => $result->isValid(), 'error' => $result->getError()]);
Performance
An MX lookup via getmxrr() takes 50–500 ms. With a slow DNS resolver it can reach 2 seconds. If this is critical: cache the result per domain for 1 hour, and perform validation asynchronously (after email input, not at form submit).
Full list of disposable domains (over 20)
- mailinator.com
- guerrillamail.com
- tempmail.com
- throwam.com
- yopmail.com
- 10minutemail.com
- trashmail.com
- dispostable.com
- fakeinbox.com
- getairmail.com
- sharklasers.com
- and more...
How to Choose the Verification Level for Your Store?
Consider order volume and average ticket. If you have a high risk of fraud (expensive goods or digital services) — immediately implement full link‑based verification. For mass‑market with high traffic, syntax + MX check is sufficient. In any case, disposable domain blocking is a security standard.
On one project with a catalog of 50,000 products, we implemented the minimal level and obtained a 15% reduction in returns within the first month — a direct budget saving.
Process of Implementing Verification
- Analysis of current order and registration forms, identifying peak load.
- Choosing the level — syntax + MX or with confirmation.
- Developing the
EmailValidatorclass and event handler. - Integration with the cart, adding client‑side validation.
- Testing — checking with real emails (valid, invalid, disposable).
- Deployment — release to production, error monitoring.
What Is Included in the Work
- Source code of the validation module with comments.
- Configuration of
OnBeforeOrderFinalActionandOnBeforeUserRegisterevents. - Documentation for maintenance and expansion of the disposable domain list.
- Consultation on caching MX queries.
Timeline
| Configuration | Timeline |
|---|---|
| Syntax + disposable domains + MX | 1–2 days |
| + link verification in email | +2–3 days |
| + client‑side AJAX validation | +1 day |
Our team has experience in 1C‑Bitrix development, having completed over 150 payment system integrations and verifications. We guarantee correct operation on high‑load projects.
Order the implementation of email verification for your online store. Get a consultation on configuring it for your tasks — we will help you choose the optimal level and implement it in 1–5 days.







