Regex email: walidacja adresu e-mail w JavaScript, PHP i HTML

Gotowy do skopiowania regex email, sprawdzony na realnych przypadkach, z funkcją JavaScript, odpowiednikiem w PHP i atrybutem HTML: co weryfikuje, co przepuszcza i jak pójść dalej.

Regex e-mail: walidacja adresu w JavaScripcie i w PHP
Szybka odpowiedź

Aby sprawdzić format adresu e-mail, przetestuj go poniższym wyrażeniem regularnym (test() w JavaScripcie, preg_match() w PHP). Przyjmuje prenom.nom+tag@sous.domaine.fr, a odrzuca podwojone kropki, spacje i domeny bez rozszerzenia. Nie gwarantuje, że skrzynka istnieje: do tego trzeba wysłać wiadomość albo odpytać domenę.

Regex email robi jedną rzecz: sprawdza, czy ciąg znaków ma postać adresu poczty elektronicznej. To niewiele, a jest niezbędne w każdym formularzu rejestracji, kontaktu czy zamówienia. Oto wyrażenie regularne, którego używam od lat, w wersji dla JavaScriptu, PHP i HTML-a, a przede wszystkim szczegółowy opis tego, co przyjmuje, a co odrzuca.

Regex email gotowy do skopiowania

javascript
^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$

Czytany od lewej do prawej:

  • ^ i $: cały ciąg musi być adresem, a nie tylko go zawierać.
  • [^<>()[\]\\.,;:\s@"]+: część lokalna (przed @) składa się z dozwolonych znaków, bez spacji i zastrzeżonej interpunkcji. Grupy rozdzielone kropką (prenom.nom) są przyjmowane, podwojona kropka już nie.
  • |(".+"): alternatywa w cudzysłowie, przewidziana w normie, dopuszcza "jean dupont"@example.com.
  • @, a po nim domena: albo adres IP w nawiasach kwadratowych ([192.168.1.1]), albo etykiety alfanumeryczne rozdzielone kropkami i zakończone rozszerzeniem o długości co najmniej dwóch liter.
Historia

Ta reguła zastąpiła w październiku 2022 roku wersję, w której podczas migracji serwisu w 2021 roku zgubiły się odwrotne ukośniki. Jeśli skopiowałeś tamtą, wymień ją: przepuszczała źle sformowane adresy.

Co regex sprawdza, a czego nie sprawdza

Poniższa tabela to rzeczywisty wynik test() w Node.js 22 i preg_match() w PHP 8.5 dla szesnastu adresów. Oba silniki wydają ten sam werdykt.

Testowany adres Wynik Dlaczego
jean.dupont@example.com przyjęty przypadek standardowy
jean+news@sub.example.co.uk przyjęty znak + i subdomeny są poprawne
JEAN@EXAMPLE.COM przyjęty flaga i ignoruje wielkość liter
"jean dupont"@example.com przyjęty część lokalna w cudzysłowie, przewidziana w RFC 5322
jean@[192.168.1.1] przyjęty domena w postaci adresu IP
jéan@exemple.fr przyjęty część lokalna dopuszcza znaki spoza ASCII
jean@localhost odrzucony brak rozszerzenia po kropce
jean@example odrzucony ten sam powód
jean..dupont@example.com odrzucony podwojona kropka w części lokalnej
jean@exa_mple.com odrzucony podkreślenie nie jest dozwolone w nazwie domeny
jean@exemple.café odrzucony rozszerzenie ze znakiem diakrytycznym: zobacz ograniczenia
a@b.c odrzucony rozszerzenie z jednej litery
@example.com odrzucony pusta część lokalna
jean@.com odrzucony pusta domena przed rozszerzeniem
jean dupont@example.com odrzucony spacja
jean@example.com (spacja na końcu) odrzucony kotwica $ odrzuca każdy znak po rozszerzeniu: pamiętaj o trim()

Czego żaden regex nie sprawdzi: że domena istnieje, że przyjmuje pocztę i że skrzynka działa. personne@gmail.com ma nienaganną postać i prawdopodobnie nic nie odbiera.

Wersja JavaScript

Funkcja przyjmuje adres jako parametr, usuwa otaczające spacje i zwraca true albo false. Flaga i sprawia, że porównanie nie rozróżnia wielkości liter.

validateEmail.js
/**
 * Sprawdza format adresu e-mail.
 * @param {string} email
 * @returns {boolean}
 */
function validateEmail(email) {
  const emailReg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i;
  return emailReg.test(String(email).trim());
}

console.log(validateEmail('jean.dupont@example.com')); // true
console.log(validateEmail('jean..dupont@example.com')); // false
console.log(validateEmail(' jean@example.com '));      // true, dzięki trim

W formularzu

Typowe zastosowanie: zablokować wysyłkę i pokazać komunikat, dopóki adres jest źle sformowany.

formulaire.js
const form = document.querySelector('#inscription');
const champ = document.querySelector('#email');
const erreur = document.querySelector('#email-erreur');

form.addEventListener('submit', (event) => {
  if (!validateEmail(champ.value)) {
    event.preventDefault();
    erreur.textContent = 'Adresse e-mail invalide';
    champ.setAttribute('aria-invalid', 'true');
    champ.focus();
  }
});

Pole błędu to widoczny element obok pola formularza, a nie okno alert(): użytkownik nie traci kontekstu i może od razu poprawić wpis.

Wersja PHP

Walidacja po stronie klienta pomaga przy wypełnianiu, ale nie jest zabezpieczeniem. Serwer musi powtórzyć kontrolę: JavaScript da się wyłączyć, a formularz wywołać bezpośrednio. Ten sam regex działa z preg_match(), z dokładnością do cudzysłowów.

isValidEmail.php
/**
 * Sprawdza format adresu e-mail.
 */
function isValidEmail(string $email): bool
{
    $pattern = '/^(([^<>()[\]\\\\.,;:\s@"]+(\.[^<>()[\]\\\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i';

    return preg_match($pattern, trim($email)) === 1;
}

var_dump(isValidEmail('jean.dupont@example.com')); // bool(true)
var_dump(isValidEmail('jean@localhost'));          // bool(false)

Zwróć uwagę na podwójne escapowanie odwrotnych ukośników w łańcuchu PHP w apostrofach: \\\\ w kodzie daje \\ we wzorcu, co dla silnika wyrażeń regularnych oznacza „dosłowny odwrotny ukośnik”.

Regex czy filter_var?

PHP udostępnia filter_var($email, FILTER_VALIDATE_EMAIL), które trzyma się normy bliżej. Oba podejścia są poprawne; nie rozstrzygają jednak dokładnie tak samo:

Adres Regex z artykułu filter_var
a@b.c odrzucony przyjęty
"jean dupont"@example.com przyjęty odrzucony
jéan@exemple.fr przyjęty odrzucony bez FILTER_FLAG_EMAIL_UNICODE, przyjęty z tą flagą
jean+news@sub.example.co.uk przyjęty przyjęty

W formularzu publicznym filter_var z flagą Unicode jest dobrym wyborem domyślnym; regex pozostaje przydatny, gdy chcesz mieć dokładnie tę samą regułę w JavaScripcie i w PHP.

Wersja HTML

Przeglądarka potrafi już zweryfikować e-mail: type="email" blokuje wysłanie formularza przy złym formacie i wyświetla własny komunikat. Atrybut pattern pozwala dodać ostrzejszą regułę, na przykład tę z artykułu.

formulaire.html
<label for="email">Adresse e-mail</label>
<input
  id="email"
  name="email"
  type="email"
  required
  autocomplete="email"
  pattern="(([^<>\(\)\[\]\\.,;:\s@&quot;]+(\.[^<>\(\)\[\]\\.,;:\s@&quot;]+)*)|(&quot;.+&quot;))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))"
  title="Une adresse de la forme prenom.nom@domaine.fr"
>

Cztery szczegóły: pattern jest niejawnie zakotwiczony, nie należy więc pisać ^ ani $; cudzysłowy we wzorcu zapisuje się jako &quot;, żeby nie zamknąć atrybutu; przeglądarki kompilują pattern z flagą v, która wymaga escapowania nawiasów okrągłych i kwadratowych wewnątrz klasy znaków (\(\)\[\]), inaczej wzorzec jest po cichu ignorowany; a walidację HTML obchodzi się jedną linijką w konsoli. Poprawia komfort użytkownika, ale nie zastępuje kontroli na serwerze.

Przypadki brzegowe, które warto znać

  • Znak +: jean+boutique@gmail.com to poprawny adres, którego wiele osób używa do sortowania poczty. Regex, który go odrzuca, kosztuje rejestracje.
  • Długie rozszerzenia: .photography, .paris, .technology istnieją. Dlatego wzorzec kończy się na [a-zA-Z]{2,}, a nie na zamkniętej liście rozszerzeń.
  • Znaki diakrytyczne: część lokalna je przyjmuje; domena w tym wyrażeniu już nie (domeny internacjonalizowane zapisuje się w rzeczywistości w Punycode, xn--…, zanim zostaną rozwiązane).
  • Otaczające spacje: kopiowanie z arkusza kalkulacyjnego często dokłada spację na końcu. Wywołaj trim() przed testem, tak jak robią to obie funkcje powyżej.
  • Wielkość liter: domena jej nie rozróżnia; część lokalna teoretycznie tak, ale żaden popularny dostawca nie robi tej różnicy. Porównywanie małymi literami to oczekiwane zachowanie.

Przetestuj regex przed wdrożeniem

Zestaw testowy jest wart więcej niż ponowne przeczytanie kodu. W JavaScripcie wystarczy pętla po znanych adresach:

test.js
const cas = {
  'jean.dupont@example.com': true,
  'jean+news@sub.example.co.uk': true,
  'jean@localhost': false,
  'jean..dupont@example.com': false,
  'jean dupont@example.com': false,
};

for (const [email, attendu] of Object.entries(cas)) {
  const ok = validateEmail(email) === attendu;
  console.log(`${ok ? 'OK ' : 'KO '} ${email}`);
}

Do analizy wzorca regex101 koloruje każdą grupę i tłumaczy, co przechwytuje. Wybierz odmianę ECMAScript dla JavaScriptu i PCRE2 dla PHP: obie przyjmują ten regex bez zmian.

Krok dalej: sprawdzić, czy adres istnieje

Gdy postać jest poprawna, trzy dodatkowe kontrole ograniczają liczbę fałszywych adresów, od najtańszej do najpewniejszej:

  1. Odrzucanie domen jednorazowych (adresów tymczasowych zakładanych po to, by obejść rejestrację) na podstawie utrzymywanej listy.
  2. Odpytanie rekordów MX domeny po stronie serwera: domena bez serwera poczty nigdy nie odbierze wiadomości. W PHP checkdnsrr($domaine, 'MX') odpowiada w jednej linijce.
  3. Wysłanie e-maila potwierdzającego z linkiem do kliknięcia. To jedyny dowód, że ktoś czyta tę skrzynkę, i tak robią wszystkie poważne serwisy.

Dwie pierwsze kontrole stosuję na publicznych formularzach Foliade; trzecia pozostaje punktem odniesienia wszędzie tam, gdzie zakładane jest konto.

Pozostałe wyrażenia regularne do walidacji

To samo podejście, inne formaty: walidacja daty, adresu IP, kodu pocztowego albo hasła.

Częste błędy

Pominięcie kotwic ^ i $ Bez nich test() przyjmuje „bonjour jean@example.com merci”, bo poprawny adres znajduje się gdzieś w ciągu. Funkcja z tego artykułu kotwiczy wyrażenie na obu końcach.
Walidacja tylko po stronie klienta JavaScript da się wyłączyć i obejść. Ta sama kontrola musi istnieć na serwerze, tutaj w PHP, zanim cokolwiek zostanie zapisane lub wysłane.
Przekonanie, że poprawny adres istnieje Regex sprawdza postać, a nie skrzynkę. „nimportequoi@gmail.com” przechodzi. Dopiero e-mail potwierdzający dowodzi, że adres odbiera pocztę.
Odrzucanie prawidłowych adresów Zbyt surowe wyrażenia odrzucają znak „+” (jean+newsletter@…) albo nowe, długie rozszerzenia w rodzaju .photography. Zawsze testuj na realnych adresach, zanim zaostrzysz regułę.

JavaScriptPHP

Damien Flandrin Web developer od 2010 roku, twórca Gekkode i Email Impact. Każdy artykuł jest sprawdzany na prawdziwym projekcie przed publikacją. Kontakt
Newsletter

Nowe testy, poradniki i projekty — e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.