Перейти к содержимому
Integration

Как проверить электронную почту в Node.js без установки пакета

| 7 min read

Три вызова API проверяют синтаксис, записи MX и одноразовые домены. Нет установки npm, нет файла регулярных выражений, нет тайм-аута SMTP. Работает из выборки в любой версии Node.js.

Email validation interface on a laptop screen
Photo by Stephen Phillips on Unsplash

Regex ловит формат. Он пропускает все остальное. user@fakdomain123.com проходит. user@mailinator.com проходит. admin@company.com (ролевой адрес, который вы должны отметить) проходит. У каждого регулярного выражения, которое вы копируете из Stack Overflow, есть одна и та же слепая зона: оно проверяет символы, а не инфраструктуру.

Пакеты npm также не решают эту проблему. email-validator добавляет зависимость и по-прежнему проверяет только формат. deep-email-validator выполняет проверку SMTP, в результате чего время ожидания за брандмауэрами истекает, и IP-адрес вашего сервера заносится в черный список почтовых провайдеров.

Вам понадобятся три проверки: синтаксис, записи MX и обнаружение одноразового поставщика. Botoi API выполняет все три операции за один POST. Нет установки. Нет файла регулярных выражений. Нет SMTP-соединения.

API-вызов

Одна команда завитка, чтобы увидеть форму ответа:

curl -X POST https://api.botoi.com/v1/email/validate \\
  -H "Content-Type: application/json" \\
  -d '{"email": "test@tempmail.xyz"}'

Ответ расскажет вам все об адресе:

{
  "success": true,
  "data": {
    "email": "test@tempmail.xyz",
    "is_valid": false,
    "reason": "no_mx_records",
    "is_free": false,
    "is_role": false,
    "is_disposable": true,
    "domain": "tempmail.xyz",
    "format_valid": true
  }
}

format_valid подтверждает синтаксис. is_valid объединяет формат, MX и возможность доставки в одно логическое значение. is_disposable флаги одноразовых поставщиков. is_role ловит адреса вроде admin@ и info@. reason сообщает вам, почему проверка не удалась, когда is_valid является ложным.

Интеграция Node.js: экспресс-маршрут регистрации

Вот полный обработчик экспресс-маршрута, который проверяет электронную почту на POST. /signup используя собственную выборку. Шаблон отказоустойчивого открытия гарантирует, что сбой Botoi никогда не блокирует реальную регистрацию:

import express from 'express';

const app = express();
app.use(express.json());

app.post('/signup', async (req, res) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password are required' });
  }

  // Validate email before creating the account
  try {
    const validation = await fetch('https://api.botoi.com/v1/email/validate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': \`Bearer \${process.env.BOTOI_API_KEY}\`,
      },
      body: JSON.stringify({ email }),
      signal: AbortSignal.timeout(3000),
    });

    const result = await validation.json();

    if (result.success && !result.data.is_valid) {
      return res.status(422).json({
        error: 'Invalid email address',
        reason: result.data.reason,
      });
    }
  } catch {
    // Fail open: if the API is unreachable, let the signup proceed
    console.warn('Email validation API unreachable, skipping check');
  }

  // Email passed validation; continue with account creation
  // await createUser(email, password);

  return res.status(201).json({ message: 'Account created' });
});

app.listen(3000);

Маршрут отклоняет недействительные электронные письма с кодом 422 и конкретным reason из API. Если API недоступен, регистрация продолжается. Вы обмениваете пропущенный чек на бесперебойный поток пользователей.

Трехуровневая проверка

The /v1/email/validate конечная точка охватывает основы. Для тщательной проверки объедините три конечные точки:

  • /v1/email/validate для синтаксиса и формата
  • /v1/email-mx/verify для проверки записи MX
  • /v1/disposable-email/check для одноразового обнаружения

Эта вспомогательная функция вызывает все три и возвращает структурированный результат:

interface ValidationResult {
  valid: boolean;
  formatValid: boolean;
  mxValid: boolean;
  isDisposable: boolean;
  reason: string | null;
}

const API_BASE = 'https://api.botoi.com/v1';
const headers = {
  'Content-Type': 'application/json',
  'Authorization': \`Bearer \${process.env.BOTOI_API_KEY}\`,
};

async function validateEmail(email: string): Promise<ValidationResult> {
  const result: ValidationResult = {
    valid: true,
    formatValid: false,
    mxValid: false,
    isDisposable: false,
    reason: null,
  };

  // Layer 1: Syntax and format check
  const formatRes = await fetch(\`\${API_BASE}/email/validate\`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ email }),
    signal: AbortSignal.timeout(3000),
  });
  const formatData = await formatRes.json();

  if (!formatData.success || !formatData.data.format_valid) {
    return { ...result, valid: false, reason: 'invalid_format' };
  }
  result.formatValid = true;

  // Layer 2: MX record verification
  const mxRes = await fetch(\`\${API_BASE}/email-mx/verify\`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ email }),
    signal: AbortSignal.timeout(3000),
  });
  const mxData = await mxRes.json();

  if (!mxData.success || !mxData.data.has_mx) {
    return { ...result, valid: false, reason: 'no_mx_records' };
  }
  result.mxValid = true;

  // Layer 3: Disposable provider detection
  const dispRes = await fetch(\`\${API_BASE}/disposable-email/check\`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ email }),
    signal: AbortSignal.timeout(3000),
  });
  const dispData = await dispRes.json();

  if (dispData.success && dispData.data.is_disposable) {
    return { ...result, valid: false, isDisposable: true, reason: 'disposable_provider' };
  }

  return result;
}

Используйте это следующим образом:

const result = await validateEmail('user@tempmail.xyz');

if (!result.valid) {
  console.log(\`Rejected: \${result.reason}\`);
  // Rejected: disposable_provider
}

Каждый уровень улавливает разные классы плохих писем. Проверки формата останавливают ввод мусора. Проверки MX останавливают изобретенные домены. Одноразовые чеки предотвращают одноразовую регистрацию. Вместе они закрывают пробел, который оставляет открытым регулярное выражение.

Добавление в маршрут API Next.js

Та же логика работает в обработчике маршрута Next.js App Router по адресу app/api/validate-email/route.ts. В этой версии проверка формата и одноразовая проверка выполняются параллельно, чтобы сократить задержку:

import { NextResponse } from 'next/server';

const API_BASE = 'https://api.botoi.com/v1';
const headers = {
  'Content-Type': 'application/json',
  'Authorization': \`Bearer \${process.env.BOTOI_API_KEY}\`,
};

export async function POST(req: Request) {
  const body = await req.json();
  const email = body.email?.trim().toLowerCase();

  if (!email) {
    return NextResponse.json(
      { error: 'Email is required' },
      { status: 400 }
    );
  }

  try {
    // Run format check and disposable check in parallel
    const [formatRes, dispRes] = await Promise.all([
      fetch(\`\${API_BASE}/email/validate\`, {
        method: 'POST',
        headers,
        body: JSON.stringify({ email }),
        signal: AbortSignal.timeout(3000),
      }),
      fetch(\`\${API_BASE}/disposable-email/check\`, {
        method: 'POST',
        headers,
        body: JSON.stringify({ email }),
        signal: AbortSignal.timeout(3000),
      }),
    ]);

    const [formatData, dispData] = await Promise.all([
      formatRes.json(),
      dispRes.json(),
    ]);

    if (formatData.success && !formatData.data.format_valid) {
      return NextResponse.json(
        { valid: false, reason: 'Invalid email format' },
        { status: 422 }
      );
    }

    if (dispData.success && dispData.data.is_disposable) {
      return NextResponse.json(
        { valid: false, reason: 'Disposable emails are not allowed' },
        { status: 422 }
      );
    }

    // Then check MX records
    const mxRes = await fetch(\`\${API_BASE}/email-mx/verify\`, {
      method: 'POST',
      headers,
      body: JSON.stringify({ email }),
      signal: AbortSignal.timeout(3000),
    });
    const mxData = await mxRes.json();

    if (mxData.success && !mxData.data.has_mx) {
      return NextResponse.json(
        { valid: false, reason: 'Email domain has no mail server' },
        { status: 422 }
      );
    }

    return NextResponse.json({ valid: true });
  } catch {
    // Fail open on API errors
    return NextResponse.json({ valid: true });
  }
}

Позвоните по этому маршруту из формы регистрации onBlur обработчик для проверки электронного письма перед отправкой пользователем. Параллель Promise.all сохраняет время ответа менее 200 мс для большинства запросов.

Обработка пограничных случаев

Три шаблона сбивают с толку наивных валидаторов:

Всеобъемлющие домены

Некоторые домены принимают электронную почту на любой адрес. anything@catch-all-domain.com не подпрыгнет, но почтовый ящик может не существовать. Проверка MX подтверждает, что в домене есть почтовый сервер. Для подтверждения конкретного почтового ящика требуется отправить электронное письмо, чего намеренно избегают при таком подходе. Для большинства процессов регистрации достаточно проверки на уровне домена.

Ролевые адреса

Адреса типа admin@, info@, и support@ являются общими почтовыми ящиками. Они действительны, но являются плохими кандидатами на владение учетной записью, поскольку их не контролирует ни один человек. API помечает их значком is_role: true. Вы можете предупредить пользователя или заблокировать регистрацию в зависимости от потребностей вашего продукта.

Плюс адресация

user+tag@gmail.com доставляет в user@gmail.com. Это законная функция, а не злоупотребление. Но это позволяет одному человеку создавать множество учетных записей с одним и тем же почтовым ящиком. Если вы хотите предотвратить это, снимите + суффикс перед проверкой и сохраните нормализованный адрес.

Вот функция, которая обрабатывает все три:

async function validateEmailStrict(email: string): Promise<{
  valid: boolean;
  warnings: string[];
  reason: string | null;
}> {
  const warnings: string[] = [];

  // Check for plus addressing (user+tag@gmail.com)
  const localPart = email.split('@')[0];
  if (localPart.includes('+')) {
    warnings.push('plus_addressing');
  }

  const res = await fetch('https://api.botoi.com/v1/email/validate', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': \`Bearer \${process.env.BOTOI_API_KEY}\`,
    },
    body: JSON.stringify({ email }),
    signal: AbortSignal.timeout(3000),
  });

  const data = await res.json();

  if (!data.success) {
    return { valid: false, warnings, reason: 'api_error' };
  }

  // Flag role-based addresses (admin@, info@, support@)
  if (data.data.is_role) {
    warnings.push('role_based_address');
  }

  // Reject disposable providers
  if (data.data.is_disposable) {
    return { valid: false, warnings, reason: 'disposable_provider' };
  }

  // Reject domains with no MX records
  if (!data.data.is_valid && data.data.reason === 'no_mx_records') {
    return { valid: false, warnings, reason: 'no_mx_records' };
  }

  return { valid: data.data.is_valid, warnings, reason: null };
}
const result = await validateEmailStrict('admin+test@example.com');
// {
//   valid: true,
//   warnings: ['plus_addressing', 'role_based_address'],
//   reason: null
// }

Пакеты npm и подход API

Особенность email-валидатор глубокий валидатор электронной почты Ботой API
Зависимости 1 5+ 0 (собственная выборка)
Проверка формата Да Да Да
MX-проверка Нет Да (SMTP) Да (DNS)
Одноразовое обнаружение Нет Да (местный список) Да (более 700 доменов)
SMTP-зондирование Нет Да (ненадежно) Нет (на основе DNS)
Брандмауэр безопасный Да Нет Да
Обслуживание Вы обновляете Вы обновляете Обновления API

Пакетный подход npm помещает логику проверки и ее данные (списки доменов, шаблоны регулярных выражений) в вашу кодовую базу. Вы являетесь владельцем обновлений. Когда запускается новый одноразовый поставщик, кому-то нужно открыть PR, чтобы добавить его. Подход API снимает с вас эту нагрузку. Список доменов обновляется на стороне сервера. Ваш код останется прежним.

Компромисс: API добавляет сетевую зависимость. Шаблон отказа открытия, показанный в примерах Express и Next.js. справляется с этим. Если API не работает, проверка проходит, и вы полагаетесь на другие средства защиты при регистрации (подтверждение по электронной почте, ограничение скорости). пока API не восстановится.

FAQ

Как проверить адрес электронной почты в Node.js без установки пакета?
Используйте собственный API выборки для вызова конечной точки проверки, например API электронной почты botoi. Отправьте запрос POST с адресом электронной почты, и API вернет допустимость формата, состояние записи MX и обнаружение одноразового поставщика. Не требуется установка npm, обслуживание регулярных выражений и SMTP-соединения.
Какой API проверки электронной почты лучше всего подходит для Node.js?
Лучший API объединяет три проверки в одном вызове: проверку синтаксиса, проверку записи MX и обнаружение одноразового домена. API botoi охватывает все три и возвращает результаты менее чем за 100 мс. Он работает с любой версией Node.js, поддерживающей выборку (18+), а уровень бесплатного пользования обрабатывает 100 запросов в день.
Как проверить, существует ли адрес электронной почты, не отправляя сообщение?
Вы можете убедиться, что в домене есть действительные записи MX, используя проверку на основе DNS, которая подтверждает, что почтовый сервер существует и принимает соединения. Конечная точка botoi /v1/email-mx/verify делает это через DNS, не открывая SMTP-соединение, поэтому ваш IP-адрес никогда не попадет в черный список. Этот подход подтверждает, что домен реален, но не может подтвердить, существует ли конкретный почтовый ящик.
Как обнаружить одноразовые адреса электронной почты в Node.js?
Вызовите конечную точку botoi /v1/disposable-email/check, указав адрес электронной почты. Он проверяет более 700 известных одноразовых поставщиков и возвращает логическое значение is_disposable. Вы можете объединить это с проверкой формата и проверкой MX для создания тщательного конвейера проверки, и все это с использованием собственных вызовов выборки.
Достаточно ли регулярного выражения для проверки электронной почты в Node.js?
Нет. Regex проверяет только формат. Электронная почта типа user@fakdomain123.com передает регулярное выражение, но не имеет почтового сервера. user@mailinator.com передает регулярное выражение, но является одноразовым адресом. Эффективная проверка требует проверки записей MX и проверки одноразовых поставщиков, чего регулярное выражение сделать не может.

Начните разработку с botoi

150+ API-эндпоинтов для поиска, обработки текста, генерации изображений и утилит для разработчиков. Бесплатный тариф, без банковской карты.