При верификации email адресов одним из самых сложных сценариев, с которым вы столкнётесь, является catch-all email сервер. Эти серверы принимают почту для любого адреса в своём домене, что делает невозможным определение через стандартную SMTP верификацию, существует ли конкретный почтовый ящик на самом деле. Понимание обнаружения catch-all email имеет решающее значение для всех, кто серьёзно относится к поддержанию качества списков рассылки и максимизации показателей доставляемости.
В этом подробном руководстве мы рассмотрим всё, что вам нужно знать о catch-all email: что это такое, почему они существуют, как их обнаружить и, что важнее всего, как обрабатывать их в процессе верификации email. Независимо от того, являетесь ли вы разработчиком, создающим систему валидации email, или маркетологом, пытающимся очистить свой список рассылки, это руководство даст вам знания и инструменты, необходимые для эффективной работы с catch-all доменами.
Надёжная стратегия верификации email должна учитывать catch-all серверы. Без правильного обнаружения и обработки результаты вашей верификации могут создать у вас ложную уверенность в доставляемости email. Давайте погрузимся в технические детали и практические решения.
Что такое Catch-All Email сервер?
Catch-all email сервер, также известный как accept-all сервер, настроен на приём входящей почты для любого адреса в своём домене, независимо от того, существует ли этот конкретный почтовый ящик. Когда вы отправляете email на anyaddress@catchall-domain.com, сервер принимает его без возврата, даже если почтовый ящик с именем "anyaddress" никогда не создавался.
Как работает конфигурация Catch-All
В типичной конфигурации email сервера, когда приходит сообщение для несуществующего почтового ящика, сервер отвечает сообщением об отклонении "550 User not found" или подобным. Такое поведение позволяет системам верификации email определять, существует ли адрес, проверяя ответ сервера.
Catch-all серверы ведут себя иначе. Они настроены на приём всей входящей почты независимо от адреса получателя. Затем почта может быть:
Направлена в специальный почтовый ящик - один администратор получает все сообщения
Сохранена в общей очереди - сообщения хранятся для последующей сортировки
Молча удалена - принята, но удалена без доставки
Переадресована в другую систему - отправлена на другой сервер для обработки
Вот пример того, как это выглядит в конфигурации почтового сервера Postfix:
Начните проверять email с BillionVerify уже сегодня. Получите 100 бесплатных кредитов при регистрации — кредитная карта не требуется. Присоединяйтесь к тысячам компаний, улучшающих ROI email-маркетинга с помощью точной проверки email.
Кредитная карта не требуется · 100+ бесплатных кредитов в день · Начать за 30 секунд
99.9%
Точность
Real-time
Скорость API
$0.00014
За email
100/day
Бесплатно навсегда
Существует несколько законных причин, по которым организации настраивают catch-all email:
1. Предотвращение потери деловой переписки
Малые предприятия часто беспокоятся о пропуске важных писем из-за опечаток или вариаций в именах сотрудников. Если кто-то отправит письмо на john.smith@company.com, но настоящий адрес jsmith@company.com, конфигурация catch-all гарантирует, что сообщение не будет потеряно.
2. Гибкая маршрутизация email
Некоторые организации используют catch-all как часть сложной системы маршрутизации email. Вся входящая почта поступает в центральную очередь, где автоматически сортируется и распределяется на основе правил.
3. Мониторинг безопасности
Команды безопасности иногда настраивают catch-all для мониторинга того, какие адреса атакуют злоумышленники или спамеры. Эта информация помогает выявлять попытки фишинга или утечки данных.
4. Совместимость со старыми системами
Организации, переходящие с одной email системы на другую, могут временно включить catch-all, чтобы гарантировать, что никакие сообщения не будут потеряны во время перехода.
5. Защита конфиденциальности
Некоторые организации, заботящиеся о конфиденциальности, используют catch-all домены для создания уникальных email адресов для каждого сервиса, на который они регистрируются, что упрощает отслеживание, какие компании передают или публикуют их данные.
Проблема для верификации Email
Для целей верификации email catch-all серверы представляют значительную проблему. Когда вы выполняете SMTP верификацию на catch-all домене, сервер отвечает с подтверждением "250 OK" для каждого адреса, который вы тестируете — будь то реальный или полностью вымышленный.
Рассмотрим этот пример SMTP сессии:
> MAIL FROM:<test@verify.local>
< 250 OK
> RCPT TO:<real.user@catchall-domain.com>
< 250 OK
> RCPT TO:<completely.fake.address@catchall-domain.com>
< 250 OK
> RCPT TO:<asdfghjkl12345@catchall-domain.com>
< 250 OK
Все три адреса получают одинаковый положительный ответ, что делает невозможным отличить реального пользователя от поддельных адресов только через SMTP верификацию.
Как обнаружить Catch-All Email серверы
Обнаружение того, настроен ли почтовый сервер как catch-all, требует умного подхода: тестирование с адресом, который определённо не должен существовать, и наблюдение за ответом сервера.
Алгоритм обнаружения
Базовый алгоритм обнаружения catch-all работает следующим образом:
Сгенерируйте случайный, несуществующий адрес в целевом домене
Выполните SMTP верификацию этого поддельного адреса
Проанализируйте ответ:
Если сервер принимает поддельный адрес → Вероятно, это catch-all
Если сервер отклоняет поддельный адрес → Применяется обычная верификация
Реализация на Node.js
Вот полная реализация на Node.js для обнаружения catch-all:
const net = require('net');
const dns = require('dns').promises;
const crypto = require('crypto');
class CatchAllDetector {
constructor(options = {}) {
this.timeout = options.timeout || 10000;
this.fromEmail = options.fromEmail || 'verify@verify.local';
this.fromDomain = options.fromDomain || 'verify.local';
}
/**
* Generate a random email address that definitely doesn't exist
*/
generateRandomEmail(domain) {
const randomString = crypto.randomBytes(16).toString('hex');
const timestamp = Date.now();
return `nonexistent-${randomString}-${timestamp}@${domain}`;
}
/**
* Get the primary MX server for a domain
*/
async getMXServer(domain) {
try {
const records = await dns.resolveMx(domain);
if (!records || records.length === 0) {
return null;
}
// Sort by priority and return the primary server
records.sort((a, b) => a.priority - b.priority);
return records[0].exchange;
} catch (error) {
return null;
}
}
/**
* Perform SMTP verification on an email address
*/
async smtpVerify(email, mxServer) {
return new Promise((resolve) => {
const socket = new net.Socket();
let step = 0;
let result = { accepted: false, response: '' };
const commands = [
null, // Wait for greeting
`EHLO ${this.fromDomain}\r\n`,
`MAIL FROM:<${this.fromEmail}>\r\n`,
`RCPT TO:<${email}>\r\n`,
'QUIT\r\n'
];
socket.setTimeout(this.timeout);
socket.on('data', (data) => {
const response = data.toString();
const code = parseInt(response.substring(0, 3));
if (step === 0 && code === 220) {
socket.write(commands[1]);
step++;
} else if (step === 1 && code === 250) {
socket.write(commands[2]);
step++;
} else if (step === 2 && code === 250) {
socket.write(commands[3]);
step++;
} else if (step === 3) {
result.response = response.trim();
result.accepted = code === 250 || code === 251;
socket.write(commands[4]);
socket.destroy();
resolve(result);
} else if (code >= 400) {
result.response = response.trim();
result.accepted = false;
socket.destroy();
resolve(result);
}
});
socket.on('timeout', () => {
result.response = 'Connection timeout';
socket.destroy();
resolve(result);
});
socket.on('error', (error) => {
result.response = `Error: ${error.message}`;
socket.destroy();
resolve(result);
});
socket.connect(25, mxServer);
});
}
/**
* Detect if a domain is configured as catch-all
*/
async detectCatchAll(domain) {
// Get MX server
const mxServer = await this.getMXServer(domain);
if (!mxServer) {
return {
isCatchAll: null,
reason: 'Could not resolve MX records',
domain
};
}
// Generate a random non-existent email
const fakeEmail = this.generateRandomEmail(domain);
// Test the fake email
const result = await this.smtpVerify(fakeEmail, mxServer);
return {
isCatchAll: result.accepted,
reason: result.accepted
? 'Server accepts mail for non-existent addresses'
: 'Server rejects non-existent addresses',
domain,
mxServer,
testEmail: fakeEmail,
serverResponse: result.response
};
}
/**
* Verify an email with catch-all detection
*/
async verifyWithCatchAllDetection(email) {
const domain = email.split('@')[1];
// First, detect if domain is catch-all
const catchAllResult = await this.detectCatchAll(domain);
if (catchAllResult.isCatchAll === null) {
return {
email,
valid: null,
catchAll: null,
reason: catchAllResult.reason
};
}
// Get MX server
const mxServer = await this.getMXServer(domain);
// Verify the actual email
const verifyResult = await this.smtpVerify(email, mxServer);
return {
email,
valid: verifyResult.accepted,
catchAll: catchAllResult.isCatchAll,
reason: catchAllResult.isCatchAll
? 'Address accepted but domain is catch-all (deliverability uncertain)'
: verifyResult.accepted
? 'Address verified successfully'
: 'Address rejected by server',
serverResponse: verifyResult.response
};
}
}
// Usage example
async function main() {
const detector = new CatchAllDetector();
// Test catch-all detection
const domains = ['gmail.com', 'example.com', 'company.com'];
for (const domain of domains) {
console.log(`\nTesting domain: ${domain}`);
const result = await detector.detectCatchAll(domain);
console.log(`Is Catch-All: ${result.isCatchAll}`);
console.log(`Reason: ${result.reason}`);
if (result.serverResponse) {
console.log(`Server Response: ${result.serverResponse}`);
}
}
// Verify specific email with catch-all detection
const emailResult = await detector.verifyWithCatchAllDetection('user@example.com');
console.log('\nEmail Verification Result:');
console.log(JSON.stringify(emailResult, null, 2));
}
main().catch(console.error);
Реализация на Python
Вот эквивалентная реализация на Python:
import socket
import dns.resolver
import secrets
import time
from dataclasses import dataclass
from typing import Optional
@dataclass
class CatchAllResult:
is_catch_all: Optional[bool]
reason: str
domain: str
mx_server: Optional[str] = None
test_email: Optional[str] = None
server_response: Optional[str] = None
@dataclass
class VerificationResult:
email: str
valid: Optional[bool]
catch_all: Optional[bool]
reason: str
server_response: Optional[str] = None
class CatchAllDetector:
def __init__(self, timeout: int = 10, from_email: str = 'verify@verify.local',
from_domain: str = 'verify.local'):
self.timeout = timeout
self.from_email = from_email
self.from_domain = from_domain
def generate_random_email(self, domain: str) -> str:
"""Generate a random email address that definitely doesn't exist."""
random_string = secrets.token_hex(16)
timestamp = int(time.time() * 1000)
return f"nonexistent-{random_string}-{timestamp}@{domain}"
def get_mx_server(self, domain: str) -> Optional[str]:
"""Get the primary MX server for a domain."""
try:
records = dns.resolver.resolve(domain, 'MX')
mx_records = sorted(
[(r.preference, str(r.exchange).rstrip('.')) for r in records],
key=lambda x: x[0]
)
return mx_records[0][1] if mx_records else None
except Exception:
return None
def smtp_verify(self, email: str, mx_server: str) -> dict:
"""Perform SMTP verification on an email address."""
result = {'accepted': False, 'response': ''}
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
sock.connect((mx_server, 25))
# Receive greeting
response = sock.recv(1024).decode()
if not response.startswith('220'):
result['response'] = response.strip()
return result
# Send EHLO
sock.send(f'EHLO {self.from_domain}\r\n'.encode())
response = sock.recv(1024).decode()
if not response.startswith('250'):
result['response'] = response.strip()
return result
# Send MAIL FROM
sock.send(f'MAIL FROM:<{self.from_email}>\r\n'.encode())
response = sock.recv(1024).decode()
if not response.startswith('250'):
result['response'] = response.strip()
return result
# Send RCPT TO
sock.send(f'RCPT TO:<{email}>\r\n'.encode())
response = sock.recv(1024).decode()
result['response'] = response.strip()
code = int(response[:3])
result['accepted'] = code in (250, 251)
# Send QUIT
sock.send(b'QUIT\r\n')
sock.close()
except socket.timeout:
result['response'] = 'Connection timeout'
except socket.error as e:
result['response'] = f'Socket error: {str(e)}'
except Exception as e:
result['response'] = f'Error: {str(e)}'
return result
def detect_catch_all(self, domain: str) -> CatchAllResult:
"""Detect if a domain is configured as catch-all."""
# Get MX server
mx_server = self.get_mx_server(domain)
if not mx_server:
return CatchAllResult(
is_catch_all=None,
reason='Could not resolve MX records',
domain=domain
)
# Generate a random non-existent email
fake_email = self.generate_random_email(domain)
# Test the fake email
result = self.smtp_verify(fake_email, mx_server)
return CatchAllResult(
is_catch_all=result['accepted'],
reason='Server accepts mail for non-existent addresses' if result['accepted']
else 'Server rejects non-existent addresses',
domain=domain,
mx_server=mx_server,
test_email=fake_email,
server_response=result['response']
)
def verify_with_catch_all_detection(self, email: str) -> VerificationResult:
"""Verify an email with catch-all detection."""
domain = email.split('@')[1]
# First, detect if domain is catch-all
catch_all_result = self.detect_catch_all(domain)
if catch_all_result.is_catch_all is None:
return VerificationResult(
email=email,
valid=None,
catch_all=None,
reason=catch_all_result.reason
)
# Get MX server
mx_server = self.get_mx_server(domain)
# Verify the actual email
verify_result = self.smtp_verify(email, mx_server)
if catch_all_result.is_catch_all:
reason = 'Address accepted but domain is catch-all (deliverability uncertain)'
elif verify_result['accepted']:
reason = 'Address verified successfully'
else:
reason = 'Address rejected by server'
return VerificationResult(
email=email,
valid=verify_result['accepted'],
catch_all=catch_all_result.is_catch_all,
reason=reason,
server_response=verify_result['response']
)
# Usage example
if __name__ == '__main__':
detector = CatchAllDetector()
# Test catch-all detection
domains = ['gmail.com', 'example.com', 'company.com']
for domain in domains:
print(f"\nTesting domain: {domain}")
result = detector.detect_catch_all(domain)
print(f"Is Catch-All: {result.is_catch_all}")
print(f"Reason: {result.reason}")
if result.server_response:
print(f"Server Response: {result.server_response}")
# Verify specific email with catch-all detection
email_result = detector.verify_with_catch_all_detection('user@example.com')
print("\nEmail Verification Result:")
print(f" Email: {email_result.email}")
print(f" Valid: {email_result.valid}")
print(f" Catch-All: {email_result.catch_all}")
print(f" Reason: {email_result.reason}")
Продвинутые техники обнаружения
Базовое обнаружение catch-all можно улучшить с помощью этих продвинутых техник:
1. Тестирование несколькими проверками
Вместо тестирования только с одним поддельным адресом, протестируйте несколько случайно сгенерированных адресов. Это помогает выявить серверы с непоследовательным поведением:
async detectCatchAllAdvanced(domain, probeCount = 3) {
const results = [];
for (let i = 0; i < probeCount; i++) {
const fakeEmail = this.generateRandomEmail(domain);
const result = await this.smtpVerify(fakeEmail, await this.getMXServer(domain));
results.push(result.accepted);
// Small delay between probes to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 500));
}
// Analyze results
const acceptedCount = results.filter(r => r).length;
if (acceptedCount === probeCount) {
return { isCatchAll: true, confidence: 'high' };
} else if (acceptedCount === 0) {
return { isCatchAll: false, confidence: 'high' };
} else {
return { isCatchAll: null, confidence: 'low', note: 'Inconsistent server behavior' };
}
}
2. Обнаружение на основе паттернов
Некоторые catch-all серверы настроены с паттернами. Тестируйте адреса с различными форматами:
const testPatterns = [
`nonexistent${Date.now()}@${domain}`, // Random with timestamp
`zzz-fake-user-zzz@${domain}`, // Obvious fake pattern
`test.${crypto.randomUUID()}@${domain}`, // UUID format
`admin-backup-${Date.now()}@${domain}` // Administrative-looking
];
3. Анализ кодов ответа
Анализируйте конкретные коды и сообщения ответа SMTP для получения дополнительной информации:
B2B SaaS компания, получающая 10 000 новых лидов ежемесячно, внедрила обнаружение catch-all в процесс регистрации:
Проблема: Многие B2B лиды приходили с доменов компаний, настроенных как catch-all, что усложняло верификацию. Они не могли просто отклонить все catch-all адреса без потери ценных лидов.
Решение:
async function validateB2BLead(email, companyInfo) {
const verification = await verifyEmail(email);
const catchAllResult = await detectCatchAll(email.split('@')[1]);
if (!verification.valid) {
return { accept: false, reason: 'Invalid email' };
}
if (!catchAllResult.isCatchAll) {
return { accept: true, reason: 'Verified deliverable', confidence: 'high' };
}
// Catch-all domain - use company info to validate
const domainMatchesCompany = email.split('@')[1].includes(
companyInfo.name.toLowerCase().replace(/\s+/g, '')
);
if (domainMatchesCompany) {
// Email domain matches company name - likely legitimate
return {
accept: true,
reason: 'Catch-all but matches company domain',
confidence: 'medium',
requireVerification: true
};
}
// Catch-all with unrelated domain
return {
accept: true,
reason: 'Catch-all domain',
confidence: 'low',
requireVerification: true,
sendDoubleOptIn: true
};
}
Результаты:
Показатель принятия лидов сохранился на уровне 95%
Ложное положительное отклонение сократилось на 60%
Показатель подтверждения двойной подписки для catch-all: 72%
Общее качество лидов улучшилось на 25%
Использование BillionVerify для обнаружения Catch-All
Хотя создание собственной системы обнаружения catch-all возможно, использование профессионального сервиса верификации email, такого как BillionVerify, предоставляет значительные преимущества:
Более высокая точность: Наше обнаружение catch-all использует несколько техник верификации и поддерживает обширную базу данных известных catch-all доменов.
Дополнительная аналитика: Помимо обнаружения catch-all, вы получаете обнаружение одноразовых email, идентификацию ролевых адресов и оценку качества.
Управление ограничениями скорости: Мы управляем ограничениями скорости и ротацией IP, обеспечивая стабильную верификацию без блокировок.
Исторические данные: Доступ к историческим данным верификации помогает выявлять паттерны и улучшать принятие решений.
Обновления в реальном времени: Наша база данных catch-all постоянно обновляется по мере изменения конфигураций доменов.
Заключение
Обнаружение catch-all email является критически важным компонентом любой комплексной стратегии верификации email. Хотя эти серверы представляют проблемы для верификации, понимание того, как они работают, и внедрение правильных стратегий обнаружения и обработки позволяет поддерживать высокие показатели доставляемости без потери ценных контактов.
Ключевые выводы из этого руководства:
Catch-all серверы принимают всю почту независимо от того, существует ли конкретный почтовый ящик
Обнаружение включает тестирование с адресами, которые определённо не существуют
Не отклоняйте автоматически catch-all адреса — внедряйте стратегии на основе риска
Используйте данные о вовлечённости для принятия обоснованных решений о catch-all контактах
Рассмотрите профессиональные сервисы такие как BillionVerify для производственных систем
Готовы внедрить обнаружение catch-all в свой процесс? Попробуйте наш инструмент проверки email для тестирования отдельных адресов или изучите BillionVerify API для бесшовной интеграции в ваши приложения.
Правильно обрабатывая catch-all домены, вы улучшите доставляемость email, защитите репутацию отправителя и будете принимать более взвешенные решения о своих контактах email.
Сравните BillionVerify с ZeroBounce по точности и скорости, прежде чем выбирать поставщика верификации.
Команды, использующие Instantly или Smartlead, улучшают доставляемость, очищая списки с BillionVerify перед каждой кампанией.
BillionVerify интегрируется с HubSpot, Mailchimp и ActiveCampaign для автоматического поддержания чистоты списков контактов.