← Назад к вопросам

Проверка валидного email

2.0 Middle🔥 151 комментариев
#Теория тестирования

Условие

Напишите функцию, которая проверяет, является ли строка валидным email адресом.

Примеры

Вход: "test@example.com" Выход: true

Вход: "invalid-email" Выход: false

Вход: "user@domain" Выход: false

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение: Валидация email адреса

Решение 1: Регулярное выражение (Практичное)

import re

def is_valid_email_regex(email: str) -> bool:
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email) is not None

Плюсы:

  • Простое и понятное
  • Работает для большинства случаев
  • Практично для реальных приложений

Минусы:

  • Regex не идеален для email по RFC
  • Может пропустить или отклонить валидные адреса

Решение 2: RFC 5322 (Более строгое)

import re

def is_valid_email_rfc5322(email: str) -> bool:
    pattern = r'^[a-zA-Z0-9][a-zA-Z0-9._%+-]*@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    
    if not re.match(pattern, email):
        return False
    
    # Дополнительные проверки
    if email.startswith('.') or email.endswith('.'):
        return False
    
    if '..' in email:
        return False
    
    if email.count('@') != 1:
        return False
    
    local, domain = email.rsplit('@', 1)
    
    # Проверяем длину
    if len(local) > 64 or len(domain) > 255:
        return False
    
    return True

Решение 3: Использование встроенной библиотеки

from email.utils import parseaddr
from email.headerregistry import Address

def is_valid_email_builtin(email: str) -> bool:
    try:
        # parseaddr парсит email
        name, parsed_email = parseaddr(email)
        
        # Проверяем что это чистый email
        if parsed_email != email:
            return False
        
        # Базовая валидация
        if '@' not in email:
            return False
        
        local, domain = email.rsplit('@', 1)
        
        if not local or not domain or '.' not in domain:
            return False
        
        return True
    except:
        return False

Решение 4: С помощью email-validator

from email_validator import validate_email, EmailNotValidError

def is_valid_email_validator(email: str) -> bool:
    try:
        # Валидирует и нормализует email
        valid = validate_email(email)
        return True
    except EmailNotValidError:
        return False

Решение 5: Простая проверка (для демонстрации)

def is_valid_email_simple(email: str) -> bool:
    # Базовые проверки
    if not email or email.count('@') != 1:
        return False
    
    local, domain = email.split('@')
    
    # Проверяем части
    if not local or not domain:
        return False
    
    if '.' not in domain:
        return False
    
    # Проверяем что нет подряд идущих точек
    if '..' in email:
        return False
    
    # Проверяем что начало и конец валидны
    if email.startswith('.') or email.endswith('.'):
        return False
    
    if domain.startswith('.') or domain.endswith('.'):
        return False
    
    # Проверяем валидные символы в локальной части
    valid_chars = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._%+-')
    if not all(c in valid_chars for c in local):
        return False
    
    return True

Примеры использования

# Валидные email
valid_emails = [
    "test@example.com",
    "user.name@domain.co.uk",
    "first+last@example.com",
    "user123@test-domain.org",
    "a@b.co",
]

# Невалидные email
invalid_emails = [
    "invalid-email",           # Нет @
    "user@domain",            # Нет точки в домене
    "user@.com",              # Нет домена
    "@example.com",           # Нет локальной части
    "user@@example.com",      # Двойной @
    "user..name@example.com", # Подряд идущие точки
    ".user@example.com",      # Начинается с точки
    "user.@example.com",      # Локаль заканчивается точкой
]

# Тестирование
for email in valid_emails:
    assert is_valid_email_regex(email), f"Неправильно отклонен: {email}"

for email in invalid_emails:
    assert not is_valid_email_regex(email), f"Неправильно одобрен: {email}"

print("Все тесты пройдены!")

Сравнение подходов

ПодходСкоростьТочностьПростотаПрименение
Regex простойБыстро80%ПростаяВеб-формы
RFC 5322Медленно95%СредняяProduction
ВстроеннаяБыстро85%ПростаяPython
email-validatorМедленно99%ПростаяProduction
Простая проверкаБыстро75%Очень простаяДемонстрация

Граничные случаи

test_cases = [
    ("test@example.com", True),
    ("invalid-email", False),
    ("user@domain", False),
    ("", False),
    ("@", False),
    ("user@", False),
    ("@domain.com", False),
    ("user@domain.com", True),
    ("user.name@domain.com", True),
    ("user+tag@domain.co.uk", True),
    ("user..name@domain.com", False),
    ("user.@domain.com", False),
    (".user@domain.com", False),
    ("user@.domain.com", False),
    ("user@@domain.com", False),
    ("user name@domain.com", False),
    ("user@domain..com", False),
]

for email, expected in test_cases:
    result = is_valid_email_regex(email)
    assert result == expected, f"Ошибка для {email}: ожидалось {expected}, получено {result}"

Лучшие практики

  1. На фронтенде: Используйте простую regex для UX
  2. На бэкенде: Используйте более строгую валидацию
  3. На боевом сервере: Отправьте письмо для подтверждения email
  4. В тестах: Используйте известные валидные/невалидные адреса

Для QA автоматизации

Для тестирования функции валидации email:

import pytest

@pytest.mark.parametrize("email,expected", [
    ("test@example.com", True),
    ("invalid-email", False),
    ("user@domain", False),
])
def test_email_validation(email, expected):
    assert is_valid_email_regex(email) == expected

Рекомендуется использовать Решение 1 (Regex) для простоты, или Решение 4 (email-validator) для production.