IsEmail: примеры (JAVA)

Примеры использования проверки e-mail в Java
Раздел: Верификация (валидация), Библиотеки
isEmail(CharSequence email): boolean

Описание функции isEmail

isEmail представляет собой логическую проверку, предназначенную для определения, соответствует ли входная строка формату адреса электронной почты. В Java это не встроенный метод стандартной библиотеки, а концепт, который реализуется несколькими способами: регулярными выражениями, библиотеками вроде Apache Commons Validator, Jakarta Mail или собственными утилитными методами.

Типичная сигнатура и поведение:

boolean isEmail(String email) - простая проверка на соответствие общему синтаксису. При входном значении null возможны варианты поведения: возвращение false или бросание IllegalArgumentException, в зависимости от реализации.

Расширенная сигнатура с опциями:

boolean isEmail(String email, EmailOptions options), где EmailOptions - объект с настройками. Возможные параметры:

  • allowInternational (boolean) - разрешить Unicode в локальной части и в домене (IDN). При false применяется Punycode для доменов.
  • allowQuotedLocal (boolean) - разрешить кавыченую локальную часть, например: "user name"@example.com.
  • allowDomainLiteral (boolean) - разрешить домены в квадратных скобках типа user@[192.168.0.1].
  • allowTopLevelDomain (boolean) - разрешить адреса без точки в домене (иногда используется для локальных сетей).
  • requireMX (boolean) - выполнить DNS-проверку на наличие MX-записи; требует сетевого доступа и может бросать исключения при сетевых ошибках.
  • strict (boolean) - включить строгую валидацию по RFC 5322; строгая валидация обычно сложнее и может отклонять многие практические адреса.

Возвращаемые значения:

  • true - строка валидна как e-mail в рамках выбранных опций.
  • false - строка не соответствует правилам.

Побочные эффекты и исключения:

  • Некоторые реализации могут бросать IllegalArgumentException для недопустимых входных данных или NamingException / собственные исключения при DNS-проверке.
  • Проверка, включающая сетевые запросы, может быть медленнее и небезопасна для вызовов в потоках обслуживания запросов без таймаута.

Короткие примеры использования isEmail

Пример 1. Простая проверка через регулярное выражение (упрощенная, практическая):

public class EmailUtil {
    private static final String SIMPLE_EMAIL = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
    public static boolean isEmail(String email) {
        if (email == null) return false;
        return email.matches(SIMPLE_EMAIL);
    }
    public static void main(String[] args) {
        System.out.println(isEmail("user@example.com"));
        System.out.println(isEmail("user.name+tag@sub.example.co"));
        System.out.println(isEmail("invalid@localhost"));
    }
}
true
true
false

Пример 2. Использование Apache Commons Validator:

import org.apache.commons.validator.routines.EmailValidator;

public class Demo {
    public static void main(String[] args) {
        EmailValidator validator = EmailValidator.getInstance();
        System.out.println(validator.isValid("user@example.com"));
        System.out.println(validator.isValid("user@[192.168.0.1]"));
    }
}
true
true

Пример 3. Проверка через Jakarta Mail (бросает исключение при невалидности):

import jakarta.mail.internet.InternetAddress;

public class MailCheck {
    public static boolean isEmail(String email) {
        try {
            InternetAddress addr = new InternetAddress(email, true);
            addr.validate();
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    public static void main(String[] args) {
        System.out.println(isEmail("quoted\"@example.com"));
        System.out.println(isEmail("plainaddress"));
    }
}
false
false

Похожие функции в Java и особенности

  • Apache Commons EmailValidator - готовая реализация с настройками, надежная для большинства задач. Предпочтительна при отсутствии необходимости сетевой проверки и при желании не писать свою регулярку.
  • Jakarta Mail (InternetAddress) - более строгая проверка синтаксиса, учитывающая много тонкостей RFC. Предпочтительна, если нужна совместимость с почтовыми стандартами и возможна зависимость от почтовой библиотеки.
  • Регулярные выражения (java.util.regex.Pattern) - гибкие, но легко сделать либо слишком строгую, либо слишком слабую проверку. Подходят, когда нужны кастомные правила.
  • javax.validation.constraints.Email - аннотация Bean Validation (Hibernate Validator). Удобна для валидации полей DTO в приложениях с валидацией на уровне модели.

Выбор основывается на простоте, точности и дополнительных требованиях: для быстрой практической проверки - регулярка или Commons; для совместимости с RFC - Jakarta Mail; для интеграции с валидацией модели - аннотация Bean Validation.

Альтернативы в других языках и отличия

PHP:

$emails = ["user@example.com", "bad@localhost"];
foreach ($emails as $e) {
    var_dump(filter_var($e, FILTER_VALIDATE_EMAIL) !== false);
}
bool(true)
bool(false)

Отличие: встроенная фильтрация удобна и стандартна, но не покрывает все требования RFC и не делает DNS-проверок.

JavaScript:

const validator = require('validator');
console.log(validator.isEmail('user@example.com'));
console.log(/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test('user@example.com'));
true
true

Отличие: в Node экосистема предоставляет модуль validator с гибкими опциями; браузерные regex работают локально.

Python:

from email.utils import parseaddr
print(bool(parseaddr('user@example.com')[1]))
# Или с пакетом validate_email
# from validate_email import validate_email
# print(validate_email('user@example.com'))
True

Отличие: стандартный parseaddr парсит, но не валидирует строго; внешние пакеты обеспечивают более строгую проверку и возможную MX-проверку.

SQL (PostgreSQL):

SELECT 'user@example.com' ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$';
 t

Отличие: проверка на уровне БД удобна для целостности данных, но выражения могут быть тяжелыми и не учитывать всех кейсов.

C#:

using System.Net.Mail;

bool IsEmail(string s) {
    try { var m = new MailAddress(s); return true; }
    catch { return false; }
}
Console.WriteLine(IsEmail("user@example.com"));
True

Отличие: встроенный MailAddress делает простую и практическую проверку, похожую по духу на Jakarta Mail.

Go:

package main
import (
    "fmt"
    "net/mail"
)
func main() {
    _, err := mail.ParseAddress("user@example.com")
    fmt.Println(err == nil)
}
true

Отличие: net/mail предоставляет стандартный парсер; для строгой проверки может потребоваться дополнительная логика.

Kotlin:

fun isEmail(s: String?) = s?.matches(Regex("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) ?: false
println(isEmail("user@example.com"))
true

Отличие: Kotlin использует те же Java-библиотеки или regex, плюс удобные расширения.

Типичные ошибки при использовании isEmail

  • Слишком простая регулярка - пропускает некорректные адреса или отвергает допустимые. Пример: отвергается адрес с дефисом в TLD или с новым TLD длиной 1-символной в специальных доменах.
  • Null-значения - отсутствие проверки на null приводит к NPE. Пример:
public boolean isEmail(String s) {
    return s.matches("^.+@.+$"); // NPE если s == null
}
// Вызов: isEmail(null) -> java.lang.NullPointerException
Exception in thread "main" java.lang.NullPointerException
    at ...
  • Перепроверка после нормализации - если перед проверкой выполняется IDN.toASCII для доменов, нужно проверять результат нормализации, иначе возможны пустые или некорректные строки.
  • Сетевые проверки без таймаута - DNS или SMTP проверки могут блокировать приложение. Пример: вызов requireMX без таймаута.
  • Ожидание абсолютной точности - даже строгая проверка синтаксиса не гарантирует существование почтового ящика.

Изменения и эволюция

В Java как языке не появилось встроенной функции isEmail, но экосистема развивалась:

  • Jakarta Mail заменил javax.mail после переноса пакета; поведение InternetAddress осталось схожим, но потребовалось обновление зависимостей и импортов.
  • Поддержка международных адресов (RFC 6530 и последующие) подтолкнула библиотеки к добавлению опций для Unicode в локальной части и к использованию Punycode для доменов.
  • Apache Commons Validator обновлялся с учётом практических случаев и расширяемости, но полная совместимость с RFC 5322 по-прежнему сложна.

Рекомендуется следить за версиями библиотек и их билдами для корректной поддержки новых правил и IDN.

Расширенные и редкие примеры использования

Пример A. Нормализация IDN и проверка с DNS MX:

Пример java
import java.net.IDN;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;

public class Advanced {
    public static boolean isEmailWithMx(String email) {
        if (email == null || !email.contains("@")) return false;
        String[] parts = email.split("@", 2);
        String domain = parts[1];
        try {
            String ascii = IDN.toASCII(domain);
            Hashtable env = new Hashtable<>();
            env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
            DirContext ctx = new InitialDirContext(env);
            javax.naming.directory.Attributes attrs = ctx.getAttributes(ascii, new String[]{"MX"});
            return attrs.get("MX") != null;
        } catch (Exception e) {
            return false;
        }
    }

    public static void main(String[] args) {
        System.out.println(isEmailWithMx("user@пример.рф"));
    }
}
false   

Комментарий: пример сочетает IDN.toASCII и вызов DNS через JNDI. DNS-запросы требуют сетевого доступа и могут возвращать непредсказуемый результат.

Пример B. Асинхронная проверка в веб-приложении (псевдокод):

Пример java
// Используется ExecutorService для выполнения проверки с таймаутом
Future f = executor.submit(() -> isEmailWithMx(email));
try {
    boolean ok = f.get(3, TimeUnit.SECONDS);
} catch (TimeoutException te) {
    // считаем невалидным или откладываем проверку
}
(зависит от выполнения задачи, возможен TimeoutException)

Пример C. Интеграция с Bean Validation (кастомный валидатор):

Пример java
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(validatedBy = EmailConstraintValidator.class)
public @interface ValidEmail {
    String message() default "Неверный email";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class EmailConstraintValidator implements ConstraintValidator {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value == null || EmailUtil.isEmail(value);
    }
}

// Использование в DTO
public class UserDto {
    @ValidEmail
    private String email;
}
(валидация происходит при запуске Bean Validation, результат зависит от входных данных)

Пример D. Проверка через SMTP (проверка пользователя на стороне почтового сервера) - демонстрация рисков:

Пример java
// Описательно: попытка установить соединение с mx-сервером и выполнить EHLO + RCPT TO
// Часто запрещается и может считаться спам-активностью
(не рекомендуется выполнять без разрешения; результаты зависят от политики сервера)

Пример E. Кастомные правила для корпоративной политики:

Пример java
// Внутренняя компания позволяет только домены вида @company.local или @partner.com
public static boolean isCompanyEmail(String s) {
    return s != null && (s.endsWith("@company.local") || s.endsWith("@partner.com"));
}
true/false в зависимости от входа

Комментарий: расширенные сценарии показывают, что помимо синтаксиса часто требуется нормализация, проверка домена и учёт политик безопасности и конфиденциальности. Сетевые проверки делают валидацию более точной, но добавляют риски и задержки.

джава isEmail function comments

En
IsEmail Checks if a CharSequence is a valid email address