Checking correctness of an email address with a regular expression in Bash
I’m trying to make a Bash script to check if an email address is correct. I have this regular expression:
[a-z0-9!#$%&'*+/=?^_`<|>~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`<|>~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
regex=[a-z0-9!#$%&'*+/=?^_`<|>~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`<|>~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])? i="test@terra.es" if [[ $i=~$regex ]] ; then echo "OK" else echo "not OK" fi
Are you aware of internationalized domain names icann.org/en/topics/idn ? does your regexp match test@fõõ.bâr.com ?
If you read that article you quoted thoroughly, you’ll see that a) regexes will only help you to sort out blatantly illegal addresses, b) you’ll either have false positives and false negatives or a completely unwieldy regex, and c) in the end, you’ll have to actually send an email to that address to check whether it is not only syntactically valid but in fact correct (which no regex can tell you).
8 Answers 8
You have several problems here:
- The regular expression needs to be quoted and special characters escaped.
- The regular expression ought to be anchored ( ^ and $ ).
- ?: is not supported and needs to be removed.
- You need spaces around the =~ operator.
regex="^[a-z0-9!#\$%&'*+/=?^_\`<|>~-]+(\.[a-z0-9!#$%&'*+/=?^_\`<|>~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$" i="test@terra.es" if [[ $i =~ $regex ]] ; then echo "OK" else echo "not OK" fi
I would like to add, however, that doing this in bash is quite, um, suboptimal. But I wanted to highlight how to fix the approach that you had chosen.
Note that @PeterEisentraut’s answer does not work for email addresses that have uppercase characters which are still valid.
You don’t have to create such a complicated regex to check valid email. You can simply split on «@», then check whether there are 2 items, one that is in front of the @, and the other at the back.
i="test@terraes" IFS="@" set -- $i if [ "$" -ne 2 ];then echo "invalid email" fi domain="$2" dig $domain | grep "ANSWER: 0" 1>/dev/null && echo "domain not ok"
To check the domain further, you can use tools like dig to query the domain. It is better than regex because @new.jersey gets matched by regex but its actually not a proper domain.
I actually think this is a much saner approach. think of all the website that disallow : test+marker@domain.com even though this is a perfectly valid email. it should get rid of most fakes and still be ok. you could make it a bit stronger by checking the presence of a ‘.’ in the second element and making sure it separates the second element in 2 subelements. Think international domains for exemple
@Jean: the second element also may contain more than two substrings separated with a dot, so this is just fine, although you could want to allow mails ligḱe user@localhost as well in some cases
Quotes, backticks and others are special characters in shell scripts and need to be escaped if they are used like in the assignment of regex . You can escape special characters with backslashes, or use single quotes around the regex if you leave out the single quote used in it.
I would recommend to use a simpler regular expression like .*@.* because all the complexity is futile. foo@example.com looks perfectly fine and will be accepted by any regular expression, but still it doesn’t exist.
Comming late for the party, but I adapted a script to read a file containing emails and filtering it using RFC822 regex, domain typo lists, mx lookup (thanks to eagle1 here) and ambiguous email filtering.
The script can be used like:
./emailCheck.sh /path/to/emailList
and produces two files, the filtered list and the ambiguous list. Both are already cleared from non RFC822 compliant adresses, email domains that don’t have valid MX domains, and domain typos.
Corrections and comments are welcome 🙂
Bash version less than 3.2:
if [[ "$email" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]$" ]] then echo "Email address $email is valid." else echo "Email address $email is invalid." fi
if [[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]$ ]] then echo "Email address $email is valid." else echo "Email address $email is invalid." fi
The reasons why you shouldn’t use a very specific regex, like you have, are explained here.
In version 3.2 of bash they changed how regexs work. To keep it short, you do not want the quotes on the regex portion of the condition. For your reference stackoverflow.com/questions/218156/bash-regex-with-quotes
The immediate problem with your script is you need to fix the quoting:
regex='[a-z0-9!#$%&'"'"'*+/=?^_`<|>~-]+(?:\.[a-z0-9!#$%&'"'"'*+/=?^_`<|>~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?'
However, this regular expression does not accept all syntactically valid email addresses. Even if it did, not all syntactically valid email addresses are deliverable.
If deliverable addresses are what you care about, then don’t bother with a regular expression or other means of checking syntax: send a challenge to the address that the user supplies. Be careful not to use untrusted input as part of a command invocation! With sendmail, run sendmail -oi -t and write a message to the standard input of the sendmail process, e.g.,
To: test@terra.es.invalid From: no-reply@your.organization.invalid Subject: email address confirmation To confirm your address, please visit the following link: http://www.your.organization.invalid/verify/1a456fadef213443
Проверить существование имейл адресов непосредственно у SMTP сервера
Поступил заказ на изготовление тулзы, которая должна проверить существование имейлов. Для того, чтоб узнать, что ящика нет — устанавливается соединение с нужным smtp-сервером, и говорим, что собираемся отослать письмо такому-то получателю. Ожидается, что в ответ на
rcpt to: recipient@example.com
550 5.1.1 : Recipient address rejected: User unknown in virtual mailbox table
Отслеживать, конечно же, будем код ответа. Если 250 — значит ок (с какой-то долей погрешности), если не 250 — значит считать, что такого пользователя нет. После этого от сервера отключаемся
В исходной хтмл форме будет формироваться десяток возможных вариантов имейла исходя из имени и фамилии пользователя, в идеале надо проверить существование всех вариантов. Предполагается сделать это вебдванольненько, т.е. использовать асинхронные джаваскрипт запрос с группой имейлов, упакованных, скажем, в JSON. А серверная часть должна оптимальным образом без особого палева проверить наличие почтовых адресов и отдать ответ.
А теперь суть вопроса: как лучше лучше всего сделать серверную часть и ее взаимодействие с браузерной? По одному конекту на каждый адрес — глупо. Не хотелось бы таким подозрительным поведением провоцировать бан.
Спросить в пределах одного подключения десяток адресов — отличная идея. Но тогда надо сразу знать все эти десять адресов. Тест гугловых смтп серверов показал, что они отвечают примерно с секундной задержкой. Нехорошо заставлять пользователя ждать целых 10 секунд. Но если приходится, то уж хоть по одному адресу отмечать — прошел он валидацию или нет. Но если получать ответ по каждому имейлу, то тогда придется делать по конекту на каждый имейл.
В общем, непонятна наиболее оптимальная тактика. И не хотелось бы усложнять систему и придумывать себе работу чрезмерно. Хотелось бы просто чтоб заказчику понравилось.
Проверка email адреса
Задание:
Написать программу, которая будет проверять email адрес на валидность. Под правильным email адресом подразумевается строка вида AAA@BBB.CCC где:
AAA — строка минимальной длинны «2», которая может содержать большие и маленькие буквы латинского алфавита и цифры. Допускаются спецсимволы ‘.'(точка), ‘_'(подчеркивание), ‘-‘ (дефис), стоящие внутри строки.
BBB — строка ненулевой длины, которая может содержать большие и маленькие буквы латинского алфавита и цифры.
CCC — строка длинны от 2-х до 4-х символов, которая может содержать большие и маленькие буквы латинского алфавита.
Формат входных данных
Первая строка входных данных содержит натуральное число N — количество email адресов подлежащих проверке (2 ≤ N ≤ 100). Следующие N строк — строки, которые нужно проверить на валидность исходя из вышеперечисленных правил.
Формат результата
Выведите YES, если строка является допустимым email адресом, и NO — в противном случае.
Программа выводит только «NO», не знаю в чем проблема: то ли неправильно составлено регулярное выражение, то ли. Одним словом, буду благодарен за помощь
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#!/bin/bash read n regex="[A-Za-z0-9][\w\-\.]*[A-Za-z0-9]@[\w]+[\.][a-zA-Z]" for((i=n;i>0;i--)) do read var1 flag=0; if [[ "$var1" =~ $regex ]]; then str=$BASH_REMATCH; if [[ $var1 = $str ]];then echo YES; flag=1; fi fi if [[ $flag -eq 0 ]]; then echo NO; fi done
Проверка существования email-адреса
Компьютерное
В этом посте я расскажу, как используя командную строку проверить существует ли определенный адрес email или нет — без отправки письма на этот email. Вам не придется платить за какой-то сервис или отправлять письма. Вы можете это сделать совершенно бесплатно из командной строки столько раз и со столькими адресами сколько вам нужно!
Когда вы отправляете email на адрес user@domain.com, отправляющий почтовый сервер смотрит MX записи на DNS для ‘domain.com’ и если найдена одна или несколько MX записей, отправляющий сервер пытается доставить email на сервер указанный в MX-записи для домена domain.com.
Давайте попробуем проверить, существует ли адрес someuser@gmail.com или нет. Сначала, поищем существуют ли MX-записи для домена получателя, в примере это gmail.com. Мы будем использовать утилиту просмотра DNS которая называется dig она установлена на большинстве Linux систем. В командной строке наберите:
Вывод отобразит что-то вроде такого:
; > DiG 9.8.2rc1-RedHat-9.8.2-0.47.rc1.el6 > gmail.com MX @8.8.8.8 ;; global options: +cmd ;; Got answer: ;; - > >HEADER< < - opcode: QUERY, status: NOERROR, id: 32294 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;gmail.com. IN MX ;; ANSWER SECTION: gmail.com. 3599 IN MX 10 alt1.gmail-smtp-in.l.google.com. gmail.com. 3599 IN MX 20 alt2.gmail-smtp-in.l.google.com. gmail.com. 3599 IN MX 30 alt3.gmail-smtp-in.l.google.com. gmail.com. 3599 IN MX 40 alt4.gmail-smtp-in.l.google.com. gmail.com. 3599 IN MX 5 gmail-smtp-in.l.google.com. ;; Query time: 20 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Fri Aug 26 10:13:19 2016 ;; MSG SIZE rcvd: 150 ;
Как вы можете видеть, выведено несколько записей MX и перед каждой из них стоит цифровое значение. Это приоритет. Чем меньше значение, тем выше приоритет. Отправляющий почтовый сервер сначала пробует отправить email на сервер с самым высоким приоритетом. У нас получается это ‘gmail-smtp-in.l.google.com’
Далее, нам надо подключиться к почтовому серверу ‘gmail-smtp-in.l.google.com’ по 25 порту (SMTP) для подтверждения правильности email адреса someuser@gmail.com. Для этого можно использовать telnet или netcat. Обе утилиты доступны в репозиториях большинства систем Linux.
$ nc gmail-smtp-in.l.google.com 25 # или telent gmail-smtp-in.l.google.com 25 220 mx.google.com ESMTP a12si21630825itb.5 - gsmtp
Для начала диалога с сервером наберите HELO. Некоторые сервера так же принимают приветствие EHLO вместо HELO. После приветствия, вам нужно рассказать с какого вы сервера пришли (допустим с mydomain.com).
HELO mydomain.com 250 mx.google.com at your service
Наберите: mail from: чтобы рассказать серверу от чьего имени вы собираетесь с ним говорить
mail from:myname@mydomain.com; 250 2.1.0 OK v72si21823782itb.85 - gsmtp
Если сервер ответил “250”, значит можно двигаться дальше. Набирайте: rcpt to:
rcpt to:someuser@gmail.com 250 2.1.5 OK v72si21823782itb.85 - gsmtp
Ответ сервера на эту команду и скажет нам - действительно ли существует такой email как “someuser@gmail.com” или нет.
Если ответ будет “250 OK” значит такой адрес существует.
Если же ответ будет “550” значит запрашиваемый вами аккаунт email не существует.
rcpt to:someuser@gmail.com 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 https://support.google.com/mail/answer/6596 y18si12470464ioi.55 - gsmtp
На заметку, если вы будете повторять такие процедуры очень часто и с одного и того же IP вас могут забанить по IP. Используйте с осторожностью.