Комментарии 27
Да, проверять регуляркой действительно нужно.
Странно, я постоянно читаю, что проверять регуляркой НЕ нужно https://habr.com/post/175375/
Без него как-бы никуда. Например, видел ошибки когда точку путают с запятой.
А смысл? Если юзер указал некорректный домен, то отправленное письмо не придёт никуда — оно вообще не отправится дальше вашего собственного SMTP, который вас банить не должен. Подозреваю, что проблему вызвала попытка отправлять почту через SMTP gmail или подобного сервиса… ну, тут скорее ССЗБ и проблема решается использованием собственного SMTP, а не валидацией MX.
Есть проблема, что Google быстро начнет банить ваш собственный SMTP за рассылку похожих писем. Собственно я сам с таким столкнулся.
А скорее всего — по хорошему нужно делать и то, и другое…
Google обычно банит не сам, а используя информацию сторонних сервисов вроде spamhaus.org. При корректной настройке своего SMTP (включая reverse DNS, SPF, etc.) и рассылке легальных писем а не реального спама обычно это проблема решаемая.
Фильтр же спама видел что с нашего email-а идёт ряд писемю… и при этом немалое их количество валится на несуществующие email-адреса.
В общем почтовый адрес периодически подпадал под спам.
и не получить отлуп от почтового сервераИ получить от пользователя желаемую реакцию, например, переход по url-у.
А отсутствие отлупа не означает отсутствия ящика. Например, корпоративные сервера нередко настраивают так, что они принимают всю входящую почту подряд, потом сортируют по ящикам, а лишнее удаляют или отправляют в дефолтный ящик.
Единственный надёжный способ проверить существование адреса электронной почты это отправка туда письма с кодом подтверждения. Наличие MX у домена (по хорошему надо проверять ещё и его разрешение в IP или, что лучше, наличие слушающего по этому адресу 25 порта) не гарантирует существование / функционирование ящика.
Всё остальное компромисс.
domain = invite.email.split('@').last.mb_chars.downcase.to_s.force_encoding("UTF-8")
#На случай, если домен русскоязычный. Точнее уже не совсем помню зачем преобразовывал в UTF-8, но видимо нечто вылетало
Без mb_chars не будет downcase для русских символов работать. Скорее всего после этого преобразование в обычную рубишную строку обратно.
Случай первый:
RFC 974 определяет порядок маршрутизации почты:
There is one other special case. If the response contains an answer
which is a CNAME RR, it indicates that REMOTE is actually an alias
for some other domain name. The query should be repeated with the
canonical domain name.
В случае, если домен является алиасом, ваш код посчитает, что это невалидный домен.
Случай второй:
Раздел 5 RFC5321 определяет корректное поведение отправителя почты:
The lookup first attempts to locate an MX record associated with the
name. If a CNAME record is found, the resulting name is processed as
if it were the initial name. If a non-existent domain error is
returned, this situation MUST be reported as an error. If a
temporary error is returned, the message MUST be queued and retried
later (see Section 4.5.4.1). If an empty list of MXs is returned,
the address is treated as if it was associated with an implicit MX
RR, with a preference of 0, pointing to that host. If MX records are
present, but none of them are usable, or the implicit MX is unusable,
this situation MUST be reported as an error.
То есть в случае отсутствия MX-записи доставка нормальным образом по стандарту происходит по A-записи домена.
Кроме того, почта может быть доставлена по SRV-записям, но предложенный Вами код этого конечно же не учитывает.
Вообще говоря, домены электронной почты не обязаны быть доступны постоянно. Стандарт предлагает такую стратегию доставки:
The sender MUST delay retrying a particular destination after one
attempt has failed. In general, the retry interval SHOULD be at
least 30 minutes; however, more sophisticated and variable strategies
will be beneficial when the SMTP client can determine the reason for
non-delivery.
Retries continue until the message is transmitted or the sender gives
up; the give-up time generally needs to be at least 4-5 days. It MAY
be appropriate to set a shorter maximum number of retries for non-
delivery notifications and equivalent error messages than for
standard messages. The parameters to the retry algorithm MUST be
configurable.
То есть чтобы убедиться, что домен мёртвый, его нужно наблюдать хотя бы 4-5 дней.
В общем, такой способ проверки по большому счёту — мусор. Сложившийся стандарт в индустрии по этому вопросу — отправить письмо с подтверждением адреса и до подтверждения не включать в списки рассылок.
Но вы натолкнули меня на мысль: отсутствие MX-записи по факту ещё не означает полный отлуп (хоть в немалом количестве случае это, скорее всего и будет), но является поводом призадуматься.
Поэтому да, логичнее не увидев MX-записи, посмотреть в A и в CNAME — если не будет и их — тогда это гарантированный отлуп.
Если есть CNAME — берём адрес или домен из него. и Повторяем цикл.
Как только по циклу дошли до ip-адреса — смотрим наличие 25-го порта. Если он открыт и представляется — тогда ок, почта есть.
Если нет — отлуп.
Хотя да, думаю что вы правы — это довольно геморройный уже получается с точки зрения написания способ проверки.
Но по крайней мере можно сказать одно: нет mx, cname и a-записей — это однозначный отлуп и почты наверняка нет.
Всё равно нужно юзеру скинуть письмо со ссылкой для подтверждения для того, чтобы убедиться, что помимо домена ещё и сам ящик существует, и что именно юзер получает письмо из этого ящика. В противном случае будут отправки на неверный адрес и рост спам-рейтинга. Это даже хуже попыток отправки на неверный домен.
И по итогу всё решит подтвердил ли юзер по ссылке свой адрес или нет.
Есть ещё вот какой неприятный момент: как вызывать эту функцию получения значений записей из DNS. Эта функция в PHP не имеет настраиваемых ограничений по таймауту и сколько она проработает в итоге зависит от платформы и конфигурации системного резолвера. Может полминуты запросто, если нэймсервер домена просто молчит. Возникает ситуация, что можно случайно или умышленно создать ситуацию, когда все воркеры PHP будут застопорены ожиданием какого-нибудь кривого или заблокированного РКН домена.
Это, конечно, можно решить, если такие запросы прогонять через очередь и их результаты кое-как кэшировать, однако это становится уже громоздко и всё ещё не нужно ни для чего.
Из этого можно сделать вывод что для спаммеров не представляет никакого труда использовать реальные адреса, если нужно — возможно, угнанные, хакнутые, или просто созданные массово с нужной целью.
Что касается регулярок — помню был у клиента адрес типа ..xx|zz..@ — и он оказался работающим (попал в базу до того как email стал проверяться на фронтэнде и прошел валидацию через отправку кода).
Так что, как уже говорили раньше, единственный способ убедится в реальности адреса — это получить от пользователя подтверждение после отправки ему кода валидации или URL (причём последний должен быть с явным подтверждением после нажатия, или его могут случайно «подтвердить» антивирусы и/или антиспамы).
Единственное что можно улучшить — это интегрировать валидацию в процесс регистрации (или смены адреса), т.е. делать её немедленно после подтверждения email, и говорить пользователю если адрес получил отлуп. Но этот путь тернист, ибо ведет к потенциальной DoS, а также может дать сбой если сервер временно недоступен.
This function should not be used for the purposes of address verification. Only the mailexchangers found in DNS are returned, however, according to » RFC 2821 when no mail exchangers are listed, hostname itself should be used as the only mail exchanger with a priority of 0.
Почему валидации email регуляркой недостаточно. Проверка MX-записей с примерами на PHP и Ruby