跳转到内容
Integration

如何在 Node.js 中验证电子邮件而不安装包

| 7 min read

三个 API 调用检查语法、MX 记录和一次性域。 没有 npm 安装,没有正则表达式文件,没有 SMTP 超时。 在任何 Node.js 版本中都可以通过 fetch 工作。

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

正则表达式捕获格式。 它错过了其他一切。 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命令可以查看响应形状:

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 集成:快速注册路线

这是一个完整的 Express 路由处理程序,用于验证 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,则注册将继续。 您用错过的支票换取不间断的用户流。

三层验证

/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 检查会阻止发明的域。 一次性支票可以阻止一次性注册。 它们共同弥补了正则表达式留下的空白。

添加到 Next.js API 路由

相同的逻辑在 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 检查确认该域有邮件服务器。 确认特定邮箱需要发送电子邮件,这种方法有意避免这样做。 对于大多数注册流程,域级验证就足够了。

Role-based addresses

地址如 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 方法

特征 电子邮件验证器 深层电子邮件验证器 博托伊API
依赖关系 1 5+ 0(本机获取)
格式检查 是的 是的 是的
MX检查 是(SMTP) 是(DNS)
一次性检测 是(本地列表) 是(700 多个域名)
SMTP 探测 是(不可靠) 否(基于 DNS)
防火墙安全 是的 是的
维护 你更新 你更新 API更新

npm 包方法将验证逻辑及其数据(域列表、正则表达式模式)放入您的代码库中。 您拥有更新。 当新的一次性提供商推出时,需要有人打开 PR 来添加它。 API 方法减轻了维护工作。 域列表在服务器端更新。 您的代码保持不变。

权衡:API 增加了网络依赖性。 Express 和 Next.js 示例中显示的失败打开模式 处理这个。 如果 API 关闭,验证会通过,并且您依赖其他注册保护(电子邮件确认、速率限制) 直到 API 恢复。

FAQ

如何在 Node.js 中验证电子邮件地址而不安装包?
Use the native fetch API to call a validation endpoint like the botoi email API. Send a POST request with the email address, and the API returns format validity, MX record status, and disposable provider detection. No npm install, no regex maintenance, and no SMTP connections required.
Node.js 的最佳电子邮件验证 API 是什么?
The best API combines three checks in one call: syntax validation, MX record verification, and disposable domain detection. The botoi API covers all three and returns results in under 100ms. It works from any Node.js version that supports fetch (18+), and the free tier handles 100 requests per day.
如何在不发送消息的情况下检查电子邮件地址是否存在?
您可以使用基于 DNS 的检查来验证域是否具有有效的 MX 记录,这会确认邮件服务器存在并接受连接。 The botoi /v1/email-mx/verify endpoint does this over DNS without opening an SMTP connection, so your IP never gets blocklisted. 此方法确认域是真实的,但无法确认特定邮箱是否存在。
How do I detect disposable email addresses in Node.js?
Call the botoi /v1/disposable-email/check endpoint with the email address. It checks against 700+ known disposable providers and returns an is_disposable boolean. You can combine this with format validation and MX checking for a thorough validation pipeline, all using native fetch calls.
正则表达式足以在 Node.js 中进行电子邮件验证吗?
不可以。正则表达式仅检查格式。 像 user@fakdomain123.com 这样的电子邮件会通过正则表达式,但没有邮件服务器。 user@mailinator.com passes regex but is a throwaway address. 有效的验证需要检查 MX 记录并筛选一次性提供商,而正则表达式无法做到这一点。

开始使用 botoi 构建

150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。