Время прочтения
5 мин
Просмотры 118K
От переводчика: прочитав статью, начал было отвечать в комментариях, но решил, что текст, на которую я собирался ссылаться, достоин отдельной публикации. Встречайте!
Если вы знаете, как валидировать email-адрес, поднимите руку. Те из вас, кто поднял руку — опустите её немедленно, пока вас кто-нибудь не увидел: это достаточно глупо — сидеть в одиночестве за клавиатурой с поднятой рукой; я говорил в переносном смысле.
До вчерашнего дня я бы тоже поднял руку (в переносном смысле). Мне нужно было проверить валидность email-адреса на сервере. Я это уже делал несколько сот тысяч раз (не шучу — я считал) при помощи классного регулярного выражения из моей личной библиотеки.
В этот раз меня почему-то потянуло ещё раз осмыслить мои предположения. Я никогда не читал (и даже не пролистывал) RFC по email-адресам. Я попросту основывал мою реализацию на основе того, что я подразумевал под корректным email-адресом. Ну, вы в курсе, что обычно говорят о том, кто подразумевает. [прим. перев. Автор имеет в виду игру слов: «when you assume, you make an ass out of you and me» — «когда вы (что-то) подразумеваете, вы делаете /./удака из себя и из меня»]
И обнаружил кое-что занимательное: почти все регулярные выражения, представлены в интернете как «проверяющие корректность email-адреса», излишне строги.
Оказывается, что локальная часть email-адреса — то, что перед знаком «@» — допускает гораздо более широкое разнообразие символов, чем вы думаете. Согласно разделу 2.3.10 RFC 2821, который определяет SMTP, часть перед знаком «@» называется локальной частью (часть после знака — это домен получателя) и предназначена для интерпретации исключительно сервером получателя.
Следовательно — и благодаря длинной череде проблем, вызванных промежуточными хостами, пытавшимися оптимизировать передачу путём изменения их [адресов — перев.], локальная часть ДОЛЖНА быть интерпретирована (и ей должен быть назначен семантический смысл) исключительно сервером, указанным в доменной части адреса.
Раздел 3.4.1 RFC 2822 описывает дополнительные детали спецификации email-адреса (выделено мной — авт.).
Адресная спецификация представляет собой определённый идентификатор в сети Internet, содержащий локально интерпретируемую строку, за которой следует знак «эт» («@», ASCII-код 64), за которым, в свою очередь, следует домен сети Internet. Локально интерпретируемая строка представляет собой либо обрамлённую кавычками строку, либо точечный атом.
Точечный атом — это набор атомов, разделённых точками. В свою очередь, атом определён в разделе 3.2.4 как набор алфавитно-цифровых символов и может включать в себя любые из нижеследующих символов (знаете, те самые, которыми обычно заменяют мат)…
! $ & * - = ^ ` | ~ # % ' + / ? _ { }
Более того, вполне допустимо (хотя не рекомендуется и редко где применяется) иметь закавыченные локальные части, в которых допустимы почти любые символы. Закавычивание может производится либо при помощи символа обратной черты, либо путём обрамления локальной части двойными кавычками.
RFC 3696, Application Techniques for Checking and Transformation of Names, был написан автором протокола SMTP (RFC 2821) как человекочитаемое руководство по эксплуатации SMTP. В третьем разделе он приводит примеры корректных email-адресов.
Это таки корректные email-адреса!
"Abc@def"@example.com"Fred Bloggs"@example.com"Joe\Blow"@example.com"Abc@def"@example.comcustomer/department=shipping@example.com$A12345@example.com!def!xyz%abc@example.com_somename@example.com
(Аплодисменты автору RFC за использование моей любимой версии Васи Пупкина — Joe Blow.)
Ну-ка, прогоните их через ваш любимый валидатор. Ну как, много прошло?
По приколу я решил попробовать написать регулярное выражение (спасибо, мне уже доложили, теперь у меня две проблемы), через которое они все прошли бы. Вот оно.
^(?!.)("([^"r\]|\["r\])*"|([-a-z0-9!#$%&'*+/=?^_`{|}~] |(?@[a-z0-9][w.-]*[a-z0-9].[a-z][a-z.]*[a-z]$
Учтите, что это выражение подразумевает, что чувствительность к регистру выключена (RegexOptions.IgnoreCase в .NET). Согласен, весьма уродливое выражение.
Я написал юнит-тест, чтобы продемонстрировать все случаи, которые оно покрывает. Каждая строка содержит email-адрес и флаг — является он корректным или нет.
[RowTest]
[Row(@"NotAnEmail", false)]
[Row(@"@NotAnEmail", false)]
[Row(@"""test\blah""@example.com", true)]
[Row(@"""testblah""@example.com", false)]
[Row(""test\rblah"@example.com", true)]
[Row(""testrblah"@example.com", false)]
[Row(@"""test""blah""@example.com", true)]
[Row(@"""test""blah""@example.com", false)]
[Row(@"customer/department@example.com", true)]
[Row(@"$A12345@example.com", true)]
[Row(@"!def!xyz%abc@example.com", true)]
[Row(@"_Yosemite.Sam@example.com", true)]
[Row(@"~@example.com", true)]
[Row(@".wooly@example.com", false)]
[Row(@"wo..oly@example.com", false)]
[Row(@"pootietang.@example.com", false)]
[Row(@".@example.com", false)]
[Row(@"""Austin@Powers""@example.com", true)]
[Row(@"Ima.Fool@example.com", true)]
[Row(@"""Ima.Fool""@example.com", true)]
[Row(@"""Ima Fool""@example.com", true)]
[Row(@"Ima Fool@example.com", false)]
public void EmailTests(string email, bool expected)
{
string pattern = @"^(?!.)(""([^""r\]|\[""r\])*""|"
+ @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!.).)*)(?<!.)"
+ @"@[a-z0-9][w.-]*[a-z0-9].[a-z][a-z.]*[a-z]$";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
Assert.AreEqual(expected, regex.IsMatch(email)
, "Problem with '" + email + "'. Expected "
+ expected + " but was not that.");
}
Прежде, чем вы назовёте меня жутким занудой и педантом (может, вы и правы, но всё равно погодите), я не думаю, что настолько глубокая проверка email-адресов абсолютно необходима. Большинство email-провайдеров имеют более строгие требования к email-адесам. Например, Yahoo требует, чтобы адрес начинался с буквы. Похоже, что имеется стандартизированный более строгий набор правил, которому следует большинство email-провайдеров, но насколько мне известно, он нигде не задокументирован.
Думаю, я создам email-адрес типа phil.h@@ck@haacked.com и начну жаловаться в техподдержку на сайтах, которые требуют ввода email-адреса, но не позволяют мне создать учётную запись с этим адресом. Люблю шалить!
Мораль заключается в том, что полезно время от времени бросать вызов предрассудкам и предположениям, а также никогда не подпускать меня к RFC.
P.S. Исправил несколько ошибок, которые я сделал в моём прочтении RFC. Видите? Даже прочитав RFC, я всё ещё не уверен в том, что же я, блин, делаю! Что ещё раз подтверждает тезис о том, что программисты — не читатели.
It is very difficult to validate Email correctly simply using HTML5 attribute «pattern». If you do not use a «pattern» someone@ will be processed. which is NOT valid email.
Using pattern="[a-zA-Z]{3,}@[a-zA-Z]{3,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}" will require the format to be someone@email.com however if the sender has a format like someone@email.net.au (or similar) will not be validated to fix this you could put pattern="[a-zA-Z]{3,}@[a-zA-Z]{3,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}" this will validate «.com.au or .net.au or alike.
However using this, it will not permit someone@email.com to validate. So as far as simply using HTML5 to validate email addresses is still not totally with us. To Complete this you would use something like this:
<form>
<input id="email" type="text" name="email" pattern="[a-zA-Z]{3,}@[a-zA-Z]{3,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}" required placeholder="Enter you Email">
<br>
<input type="submit" value="Submit The Form">
</form>
or:
<form>
<input id="email" type="text" name="email" pattern="[a-zA-Z]{3,}@[a-zA-Z]{3,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}[.]{1}[a-zA-Z]{2,}" required placeholder="Enter you Email">
<br>
<input type="submit" value="Submit The Form">
</form>
However, I do not know how to validate both or all versions of email addresses using HTML5 pattern attribute.
В число таких факторов, входит отправка писем только на рабочие, действующие email адреса. Такие email должны быть проверены по целому ряду требований. В этой статье я расскажу вам о валидации баз email для рассылок.
Содержание
Необходимость email валидации
Большинство email баз для рассылки содержит устаревшие данные. Это могут быть непроверенные, неработающие, заблокированные, поддельные, одноразовые, переполненные адреса и т.д.
Купленные базы быстро устаревают и часто содержат некачественные email, большая часть из которых уже не существует. И количество их может достигать 40%, в зависимости от качества базы.
Рассылка по базам без проверки на валидность чревата последствиями — от попадания писем в спам и падения рейтинга домена, до полной его блокировки почтовыми провайдерами.
Так же можно хорошо сэкономить на рассылке. Ведь зачем платить за отправку писем на невалидные адреса, которые однозначно не получат письма и которые можно сразу отфильтровать. Учитывая недешевый прайс сервисов массовой рассылки, проверка email базы и экономия на количестве адресатов вполне имеет место быть.
Заказ валидации email
Услуга проверки баз на валидность довольно востребована, поэтому в наше время найти исполнителя несложно. Вопрос только в цене.
Веб-студии, как правило, берут дорого, так как им нужно оплачивать не только зарплаты работников, но еще и аренду, налоги и т.д.
Существует масса специализированных сервисов проверки email, например: zerobounce, myemailverifier. На мой взгляд — оптимальное соотношение цена / качество.
Дешевле всего будет заказать у фрилансеров, например на кворке. Качество валидации не уступает веб-студиям, а порой результат даже превосходит. Нужно только тщательно подходить к выбору исполнителя.
В любом случае, важно получить отчет валидации по каждому email адресу. И чем подробнее он будет, тем лучше.
Самостоятельная валидация
Самым бюджетным, но и самым трудозатратным вариантом проверки является самостоятельная валидация баз. Для этого нужно знать, каким критериям должен соответствовать рабочий email адрес. Разберем основные из них:
Советы валидации email
1. Валидация синтаксиса
Каждый почтовый адрес должен соответствовать определенному формату, содержащему имя, домен и знак «@». Эффективным способом такой проверки является применение регулярных выражений в соответствии с современными стандартами.
Однако, важно понимать, что проверка на синтаксис ничего не скажет о том, существует ли этот email и домен, используемый в адресе на самом деле. В то же время, она позволяет отсеять большое количество невалидных email с минимальными затратами на серверные ресурсы.
2. Проверка DEA (одноразовый email)
DEA (Disposable email address) — это временная электронная почта, которая создается для того, чтобы не использовать свой настоящий email-адрес на ресурсах в интернете по разным причинам. Такая почта не требует регистрации, анонимна и удаляется сразу же после использования.
Одноразовые почтовые ящики создаются, например, для регистрации на сомнительных сайтах, для получения какой-то одноразовой услуги по email подписке и т.д. В таких случаях, человек может полагать, что на его email будут приходить тонны спама, поэтому использует DEA email.
Валидация по DEA-критерию заключается в проверке на принадлежность домена email общеизвестным поставщикам одноразовых адресов электронной почты.
3. Проверка записей DNS, MX
Следующим этапом валидации является выполнение запроса, на получение DNS записей.
MX-запись в DNS направляет письма на почтовый сервер и указывает как письма должны маршрутизироваться в соответствии с SMTP или стандартным протоколом передачи почты.
Проверка наличия DNS и MX-записей является первым сигналом того, что сервер работает и обслуживает входящие запросы для домена электронного адреса. Результатом является успешное определение IP-адреса почтового сервера с помощью записей MX.
4. SMTP-сервер
SMTP-сервер необходим для проверки корректности соединения с почтовым сервером, для разрешения на отправку сообщений, для непосредственной отправки сообщения и подтверждения доставки письма.
В нашем случае, для валидации email, достаточно будет проверить правильность установки безошибочного соединения с SMTP-сервером без фактической отправки электронного письма. Успешным результатом проверки SMTP является факт того, что почтовый сервер работает и готов принимать письма.
5. Проверка активности email
Почтовые ящики могут быть заблокированы провайдерами по множеству причин. Это подозрительная активность, подбор паролей, попытка входа из нового браузера или места, частая рассылка однотипных сообщений, блокировка по запросу гос. органов и ведомств и т.д.
Как правило, такие email встречаются не так часто, но для лучшего результата их хорошо было бы проверить и исключить.
Понять, что email отключен можно по ответам SMTP-сервера. Обычно в ошибках встречаются такие упоминания, как «disabled», «discontinued».
6. Переполнение почтового ящика
При отправке электронных писем на некоторые email-адреса в ответ можно получить автоматические сообщения о нехватке места на сервере или о том, что текущему адресату приходит слишком много писем. Такие почтовые ящики гарантированно заброшены и нет смысла отправлять на них письма.
Методом валидации таких email является анализ ошибочных ответов SMTP-сервера на наличие вхождений «full», «insufficient», «over quota», «too many messages» и т.д.
7. Валидация Catch-all адресов
Catch-all — это email адрес, принимающий все сообщения, адресованные на неправильный адрес электронной почты домена.
Проверить факт того, является ли текущий email catch-all-адресом или нет можно с помощью SMTP-диалога и отправки сообщения на заведомо несуществующий, сгенерированный почтовый адрес в почтовом домене.
8. Ролевой аккаунт
Ролевые учетные записи — это адреса электронной почты, которые не связаны с конкретным человеком, а скорее с компанией, отделом, должностью или группой. Как правило, они не предназначены для личной переписки. Часто они начинаются на info, admin, support и т.д.
Отправка сообщений на такие email ставится под вопрос. Обычно, их не используют для подписок и вероятность того, что кто-то пометит письмо как спам высока. Так же ролевые email используют в качестве «приманки» для поимки спамеров такие сервисы, как Spamhaus.
Проверка email на валидность в этом случае выполняется методом сравнения текущего имени в адресе email со списком часто-встречающихся имен ролевых учетных записей.
9. Проверка наличия в черном списке
Черный список электронной почты — это база email, IP-адресов и доменных имен, которые были зафиксированы в рассылке спама. Одним из самых известных является составной список от Spamhaus.
Для предотвращения спама, черные списки используются многими поставщиками услуг, в число которых входят Google и Microsoft.
Проверка наличия email в черном списке является важнейшей частью определения валидности баз email для рассылок.
10. Повторная валидация
Зачастую, возникает ситуация, когда почтовый сервер перегружен и недоступен. Об этом свидетельствует ошибка, связанная с временем соединения с SMTP-сервером.
Такие проверки нужно идентифицировать и запускать повторно через некоторое время. Как показывает практика, наиболее достоверный результат валидации можно получить, выполнив не менее 3-х проверок.
Заключение
Это были основные методы проверки email на валидность, на которые следует обратить внимание. Придерживаясь этих рекомендаций вы сможете получить качественные базы с рабочими, валидными email адресами для успешного маркетинга.
С вами был Дмитрий. Успехов!
You will learn how to do email validation in Angular and Typescript applications with input forms.
Email validation is one of the basic validation to avoid invalid emails.
- VueJS Input type url validation
- ReactJS Input type url validation
In Angular, validations can be done using two approaches.
-Reactive forms
- Template Driven Forms
email pattern validation implemented with multiple approaches
We already have a pre-created angular application — angular-form-validations.
Angular Email Validation reactive forms
Email Validations are implemented in Reactive forms using in-built Angular directives.
For Angular applications to use reactive forms,
In app.module.ts, first import the FormsModule and ReactiveFormsModule modules.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Let’s create a new component reactive-email-validation using the ng g component command.
A:workangular-form-validations>ng g component reactive-email-validation
CREATE src/app/reactive-email-validation/reactive-email-validation.component.html (40 bytes)
CREATE src/app/reactive-email-validation/reactive-email-validation.component.spec.ts (747 bytes)
CREATE src/app/reactive-email-validation/reactive-email-validation.component.ts (350 bytes)
CREATE src/app/reactive-email-validation/reactive-email-validation.component.scss (0 bytes)
UPDATE src/app/app.module.ts (973 bytes)
To begin, an HTML template component is constructed in Angular to display the input form with an email field.
- Define the form element with
FormGroup directivewith emailForm binding - Inside the form, define the input element with
formControlNamename email - validation errors are bound and available with
emailForm.controls[email] - Validation check added for input box is not empty(errors.required) and focus is in it(touched)
- if bound errors contains required, display the error message ‘Email is required
- if errors contain the pattern, display the error message ‘Invalid Email’.
<p>Angular Email Validation with Reactive form!</p>
<div>
<h2>{{ heading | titlecase }}</h2>
<form [formGroup]="emailForm">
<input type="text" formControlName="email" />
<div *ngIf="!emailForm.controls['email'].valid && emailForm.controls['email'].touched">
<div *ngIf="emailForm.controls['email'].errors?['required']" style=" background-color: red">
Email is required
</div>
<div *ngIf="emailForm.controls['email'].errors?['required']" style="background-color: red">
Invalid Email
</div>
</div>
</form>
<button type="submit ">Submit</button>
</div>
Next, In the application controller component, define the logic for regex pattern validation.
- Declared emailForm of type
FormGroupwhich already has a binding to form element. - Defined the
email regular expression patterninto variable - In the constructor, initialized emailForm with a new FormControl element ie email
- these email form control will be bound with the input element in the HTML template
Validators.requiredadded for not empty validation checkValidators.patternadded for email regular expression- These validations are checked with
blurevent `updateOn: blur’ property
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-email-validation',
templateUrl: './reactive-email-validation.component.html',
styleUrls: ['./reactive-email-validation.component.scss']
})
export class ReactiveEmailValidationComponent {
heading = 'angular Email pattern validation with examples';
emailForm: FormGroup;
myusername: string = '';
emailRegex =
'^[a-z0-9._%+-][email protected][a-z0-9.-]+.[a-z]{2,4}$';
constructor() {
this.emailForm = new FormGroup({
email: new FormControl('', {
validators: [Validators.required, Validators.pattern(this.emailRegex)],
updateOn: 'blur',
}),
});
}
submit() {
console.log(this.emailForm.value);
}
get validator() {
return true;
}
}
Angular email template-driven form validation using html5
In modern browsers, the Easy approach is to do email pattern validation with inbuilt html5 language.
Another way to do email validation is to define the input type=email in the HTML element. However, this supports html5 only and modern browsers.
Input is defined with the following attributes
<input type="email" name="email" id="email" placeholder="[email protected]" [(ngModel)]="email" [ngModelOptions]="{ updateOn: 'blur' }" #emailerror="ngModel" pattern="^[a-z0-9._%+-][email protected][a-z0-9.-]+.[a-z]{2,4}$ " required />
type=email is an input textbox, that accepts email only
pattern attribute value is a regular expression pattern for email values
NgModel directive is to support two-way binding from view to controller and vice versa
The ngModelOptions directive enables to change of the behavior of the ngModel value, this will be fired with the updateon:blur event.
Following is a complete code
<div>
<input type="email" name="email" id="email" placeholder="[email protected]" [(ngModel)]="email" [ngModelOptions]="{ updateOn: 'blur' }" #emailerror="ngModel" pattern="^[a-z0-9._%+-][email protected][a-z0-9.-]+.[a-z]{2,4}$ " required />
<div *ngIf="emailerror.invalid && (emailerror.dirty || emailerror.touched)">
<div *ngIf="emailerror.errors.required">
<span style="background-color: red">Email is required </span>
</div>
<div *ngIf="emailerror.errors.pattern">
<span style="background-color: red">Invalid EmailL </span>
</div>
</div>
</div>
In the component, just declare the input element’s name here with a default value.
import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
heading = 'angular html5 Email pattern validation example';
email: string = '';
}
Typescript email regexp validation
Sometimes, We want to do a validation typescript file.
- It uses the same above regular expression pattern for email validation
- RegExp object is created with regex
pattern. testchecked against supplied email and return true-valid
public isValidEmail(emailString: string): boolean {
try {
let pattern = new RegExp("^[a-z0-9._%+-][email protected][a-z0-9.-]+.[a-z]{2,4}$");
let valid = pattern.test(emailString);
return valid;
} catch (TypeError) {
return false;
}
}
}
}
console.log(this.isValidEmail('[email protected]')); // true
console.log(this.isValidEmail('abc')); // false
a
Conclusion
In this post, You learned
- Angular email pattern validation example with reactive forms
- HTML 5 input type email form validation
- Typescript email validation
2. Service Description
The email validation service provides full validation of an email address via the following stages:
1. Checks that the provided Email Address conforms to the valid syntax required for an email address
2. Validates Domain and runs a DNS check, recognising common mispellings and return a suggested spelling if necessary
3. Real-time checks to assess the validity of the domain, whether the catch-all domain is specified and whether the email is deliverable.
For further advice on how to approach email validation head to Understanding Email Validation
3. Input Criteria
Method: ExecuteCapture
The ExecuteCapture method is used to access the Email Validation product and services by specifying the corresponding profile.
3.1 Input Details
Type: ExecuteCaptureRequest
| Field Name | Type | Description |
|---|---|---|
| securityHeader | SecurityHeader | The username used to access the system including domain name (e.g. [email protected]) |
| profileRequest | ProfileRequestCapture | Details of the request |
In the profileRequest element, the profileGuid should be specified as:
| Profile | GUID |
| Email Validation | 20B3F459-7D04-42AD-B7E2-AA1D5FE07E82 |
3.2 Email Validation Input XML
The following XML sample demonstrates a request data object containing an email address for validation.
<!-- Request Input Data - Email and Telephone -->
<req:requestData>
<!-- Email Input Data -->
<req:email>[email protected]</req:email>
</req:requestData>
"requestData": {
"email": ["[email protected]"]
}
}
3.3 Email Validation Additional Options
Email Validation options can be specified by providing the key value pairs specified below to the ProfileRequestCaptureData → additionalData property.
ExecuteCapture → ProfileRequestCapture → ProfileRequestCaptureData → additionalData
Type: IdmDataArrayAdditionalData
| Key Mnemonic | Key Value | Description |
|---|---|---|
| EMAIL_TIMEOUT | Timeout Value in milliseconds (200 < EMAIL_TIMEOUT < 30000) | This value specifies how long the service is allowed to wait for all real-time network level checks to finish. Real-time checks consist primarily of DNS and SMTP level verification. Timeout time is in milliseconds. A minimum value of 200ms is required. |
NOTE: If no email validation timeout value is specified in the additionalItems list, or the value is not a valid positive number, the service will default to using a value of 30 seconds
If a value of less that 200 is speified, the service will set the timeout at 200 mS
If a value of greater then 30000 mS (30 seconds) is specified the service will set the timeout at 30000 mS
The following XML sample demonstrates setting the email validation timeout vale to 10 seconds.
<req:additionalData>
<data:item>
<data:key>EMAIL_TIMEOUT</data:key>
<data:value>10000</data:value>
</data:item>
</req:additionalData>
{
"additionalData": {
"item": {
"key": "EMAIL_TIMEOUT",
"value": "10000"
}
}
}
4. Output Format
The results of the GB Email Verification Service search are returned in a ProfileResponseDetails structure with a responseType of ‘VALIDATE’.
The ProfileResponseDetails structure contains a single data structure which holds an array of records containing the returned validation data per input number.
ExecuteCaptureResponse → ProfileResponse [0] → ProfileResponseDetails [0] → ValidateResponse → ValidateResponseData
The returned data structure is detailed below:
Type:
| Field Name | Type | Description |
|---|---|---|
| input | String | The input Email Address |
| status | Enumeration | SUCCESS if the validation has taken place, FAILURE otherwise |
| validationCodes | IdmDataArrayAdditionalData | Array of key value pairs containing the validation response codes for the input |
4.1 Sample Output XML
Search XML requesting more data:
The following output XML demonstrates the ProfileResponse for the Email Address Component. The component name is Email Validation and the response type is VALIDATE.
The validation results for each email Address will be returned in the same order as input. The array of ValidateResponse data structures contain the individual response details. A series of key value pair response codes are returned for each address, which contain data supplier specific summaries of the input.
<!-- Email Component Response -->
<req:profileResponse>
<req:transactionGuid>1d39bec2-7f7e-42b9-bdfd-3909bf20f44d</req:transactionGuid>
<req:componentName>EMail Validation</req:componentName>
<req:componentStatus>SUCCESS</req:componentStatus>
<req:componentAction>match</req:componentAction>
<req:responseType>VALIDATE</req:responseType>
<req:notes>[]</req:notes>
<!-- Billing Invoice -->
<req:invoice>
<req:invoiceList>
<req:invoiceGuid>F7210D60-F4BF-4024-82ED-75A8EB5C0681</req:invoiceGuid>
<req:billingInformationGuid>477B8BFB-B3EA-4FA5-9015-431047E046EC</req:billingInformationGuid>
<req:billingPoints>21</req:billingPoints>
<req:creditsUsed>1</req:creditsUsed>
<req:dataSetInvoices>
<req:dataSetCode>EMAIL</req:dataSetCode>
<req:billingPoints>1</req:billingPoints>
<req:recordsReturned>1</req:recordsReturned>
<req:dataLicenceGuid>477B8BFB-B3EA-4FA5-9015-431047E046EC</req:dataLicenceGuid>
</req:dataSetInvoices>
</req:invoiceList>
</req:invoice>
<!-- Response Data -->
<req:validateResponse>
<req:recordsReturned>1</req:recordsReturned>
<req:responseCount>1</req:responseCount>
<!-- Response per Input Email -->
<req:response>
<req:input>[email protected]</req:input>
<req:status>SUCCESS</req:status>
<req:validationCodes>
<data:item>
<data:key>IsSyntaxGood</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>SyntaxErrorPosition</data:key>
<data:value>-1</data:value>
</data:item>
<data:item>
<data:key>IsDomainSpecificSyntaxGood</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>DomainSpecificSyntaxErrorPosition</data:key>
<data:value>-1</data:value>
</data:item>
<data:item>
<data:key>IsDNSGood</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>IsSMTPServerGood</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>IsSMTPMailBoxGood</data:key>
<data:value>unknown</data:value>
</data:item>
<data:item>
<data:key>IsCatchAllDomain</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsRecognisedTLD</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>IsCountrySpecific</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>IsAlias</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsFree</data:key>
<data:value>Unknown</data:value>
</data:item>
<data:item>
<data:key>IsEstablished</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsVulgar</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsSMSDomain</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsRole</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsGood</data:key>
<data:value>Unknown</data:value>
</data:item>
<data:item>
<data:key>IsDeliverable</data:key>
<data:value>unknown</data:value>
</data:item>
<data:item>
<data:key>IsBusinessAddress</data:key>
<data:value>Unknown</data:value>
</data:item>
<data:item>
<data:key>IsBogus</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>Box</data:key>
<data:value>first.lastname</data:value>
</data:item>
<data:item>
<data:key>Domain</data:key>
<data:value>company.co.uk</data:value>
</data:item>
<data:item>
<data:key>TopLevelDomain</data:key>
<data:value>.uk</data:value>
</data:item>
<data:item>
<data:key>TopLevelDomainDescription</data:key>
<data:value>United Kingdom</data:value>
</data:item>
<data:item>
<data:key>NoMXRecords</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>BogusSMSAddress</data:key>
<data:value>Unknown</data:value>
</data:item>
<data:item>
<data:key>Garbage</data:key>
<data:value>Unknown</data:value>
</data:item>
<data:item>
<data:key>MailBoxIsFull</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>MailBoxIsBusy</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>DisposableEmail</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>SpamTrap</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>KnownSpammer</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>BlackListedDomain</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>KnownComplainer</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>KnownGreylister</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>OptinRequired</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>IsWhiteListOnly</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>ConnectionRefused</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>EmailIsBad</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>Bot</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>GreyListTactic</data:key>
<data:value>true</data:value>
</data:item>
<data:item>
<data:key>MailServerTemporarilyUnavailable</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>ServerConnectTimeout</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>MailBoxTimeout</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>TemporaryReject</data:key>
<data:value>false</data:value>
</data:item>
<data:item>
<data:key>MisspelledDomain</data:key>
<data:value>False</data:value>
</data:item>
</req:validationCodes>
</req:response>
</req:validateResponse>
</req:profileResponse>
{
"profileHeader": {
"profileGuid": "20B3F459-7D04-42AD-B7E2-AA1D5FE07E82",
"profileName": "Email",
"transactionGuid": "076B89EA-F6D6-4A3C-ABA5-38CCC89F3C4F",
"transactionTimeStamp": 1433167116839,
"profileStatus": "SUCCESS",
"remarks": null
},
"profileResponseDetails": [ {
"transactionGuid": "a3c9c522-0a44-4e75-93fc-af1052520233",
"componentName": "EMail Validation",
"componentStatus": "SUCCESS",
"componentAction": "match",
"responseType": "VALIDATE",
"notes": "[]",
"invoice": {
"invoiceList": [ {
"invoiceGuid": "109A0D0F-0769-49F0-95CC-7CD123EEF4F5",
"billingInformationGuid": "477B8BFB-B3EA-4FA5-9015-431047E046EC",
"dataLicenceDescription": null,
"billingPoints": 1,
"creditsUsed": 1,
"dataSetInvoices": [ {
"dataSetCode": "EMAIL",
"billingPoints": 1,
"recordsReturned": 1,
"dataLicenceGuid": "477B8BFB-B3EA-4FA5-9015-431047E046EC"
}]
}],
"tmp": null
},
"captureResponse": null,
"validateResponse": {
"resultStatus": null,
"recordsReturned": 1,
"responseCount": 1,
"response": [ {
"input": "[email protected]",
"status": "SUCCESS",
"validityFlag": "VALID",
"validationCodes": {
"item": [
{
"key": "IsSyntaxGood",
"value": "true"
},
{
"key": "SyntaxErrorPosition",
"value": "-1"
},
{
"key": "IsDomainSpecificSyntaxGood",
"value": "true"
},
{
"key": "DomainSpecificSyntaxErrorPosition",
"value": "-1"
},
{
"key": "IsDNSGood",
"value": "true"
},
{
"key": "IsSMTPServerGood",
"value": "true"
},
{
"key": "IsSMTPMailBoxGood",
"value": "Unknown"
},
{
"key": "IsCatchAllDomain",
"value": "TRUE"
},
{
"key": "IsRecognisedTLD",
"value": "true"
},
{
"key": "IsCountrySpecific",
"value": "false"
},
{
"key": "IsAlias",
"value": "false"
},
{
"key": "IsFree",
"value": "Unknown"
},
{
"key": "IsEstablished",
"value": "false"
},
{
"key": "IsVulgar",
"value": "false"
},
{
"key": "IsSMSDomain",
"value": "false"
},
{
"key": "IsRole",
"value": "false"
},
{
"key": "IsGood",
"value": "Unknown"
},
{
"key": "IsDeliverable",
"value": "Unknown"
},
{
"key": "IsBusinessAddress",
"value": "Unknown"
},
{
"key": "IsBogus",
"value": "false"
},
{
"key": "Box",
"value": "first.lastnam"
},
{
"key": "Domain",
"value": "company.co.uk"
},
{
"key": "TopLevelDomain",
"value": ".uk"
},
{
"key": "TopLevelDomainDescription",
"value": "commercial"
},
{
"key": "NoMXRecords",
"value": "false"
},
{
"key": "BogusSMSAddress",
"value": "Unknown"
},
{
"key": "Garbage",
"value": "Unknown"
},
{
"key": "MailBoxIsFull",
"value": "false"
},
{
"key": "MailBoxIsBusy",
"value": "false"
},
{
"key": "DisposableEmail",
"value": "false"
},
{
"key": "SpamTrap",
"value": "false"
},
{
"key": "KnownSpammer",
"value": "false"
},
{
"key": "BlackListedDomain",
"value": "false"
},
{
"key": "KnownComplainer",
"value": "false"
},
{
"key": "KnownGreylister",
"value": "false"
},
{
"key": "OptinRequired",
"value": "false"
},
{
"key": "IsWhiteListOnly",
"value": "false"
},
{
"key": "ConnectionRefused",
"value": "false"
},
{
"key": "EmailIsBad",
"value": "false"
},
{
"key": "Bot",
"value": "false"
},
{
"key": "GreyListTactic",
"value": "false"
},
{
"key": "MailServerTemporarilyUnavailable",
"value": "false"
},
{
"key": "ServerConnectTimeout",
"value": "false"
},
{
"key": "MailBoxTimeout",
"value": "false"
},
{
"key": "TemporaryReject",
"value": "false"
},
{
"key": "MisspelledDomain",
"value": "False"
}
],
"tmp": null
}
}]
},
"verifyResponse": null,
"traceResponse": null
}]
}
4.2 Detailed Email Responses
Below we list al the fields that are returned by the email validation service, with a brief description of what these represent.
We also provide further details of what these fields mean to guide your interpretation of these results. This can be found in Email Response Fields — Further Details
| Field Name | Description |
|---|---|
| IsSyntaxGood | Syntax meets standards. (true/false) |
| SyntaxErrorPosition | Position Syntax fails. (-1 for no failure) |
| IsDomainSpecificSyntaxGood | Domain Syntax meets standards. |
| DomainSpecificSyntaxErrorPosition | Position Domain Syntax fails. (-1 for no failure) |
| IsDNSGood | Indicates if the domain is registered and has at least one MX record.(true/false) |
| IsSMTPServerGood | Indicates if the email’s mail server is operational. (true/false/unknown) |
| IsSMTPMailBoxGood | Indicates if the mail server will accept mail to the specific box. (true/false/unknown) |
| IsCatchAllDomain | Indicates if the mail server will accept mail to any box in that domain. (true/false/unknown) |
| IsRecognisedTLD | Is the top level domain recognized by ICANN. (true/false) |
| IsCountrySpecific | Indicates if the TLD represents a specific country. For example .us implies United States. (true/false) |
| IsAlias | Indicates if the email matches alias rules for different sites. For example, any email with a «+» in it at gmail.com is an alias. An alias may also indicate that the email is disposable, for example [email protected] (true/false/unknown) |
| IsFree | Indicates if the domain of the email is a public-register domain, where users can sign up for email accounts for free. (true/false/unknown) |
| IsEstablished | Indicates if the email is known within large lists of bulk-marketing lists. (true/false/unknown) |
| IsVulgar | Indicates if the email address contains obvious vulgar words.(true/false) |
| IsSMSDomain | Indicates if the domain is a known Mail-to-SMS Gateway. (true/false) |
| IsRole | Indicates if the email address appears to be a role that is designed to be anonymously managed by one or more persons. (true/false) |
| IsGood | An estimate on the validity of the email address. 0 = Email is Good 1 = Email is Probably Good 2 = Unknown 3 = Email is Probably Bad 4 = Email is Bad |
| IsDeliverable | Indicates if the mail server will accept mail for the given email address. (true/false/unknown) |
| IsBusinessAddress | Indicates if the email address appears to be work related. (true/false) |
| IsBogus | Indicates if the email is obviously bogus : such as [email protected], [email protected], or [email protected] etc. (true/false) |
| Box | The part to the left of the ‘@’ symbol. Also known as the local part or the username. |
| Domain | The part to the right of the ‘@’ symbol. The location to which the email address will be sent. |
| TopLevelDomain | The part after the rightmost ‘.’ |
| TopLevelDomainDescription | Description of the Top Level Domain. |
| NoMXRecords | Indicates that the registered DNS does not have an MX record. |
| BogusSMSAddress | Indicates if the email address is believed to be a bogus SMS domain address. |
| Garbage | Indicates if the email address is believed to contain garbage-like keyboard strokes and/or garbage-like characters. |
| MailBoxIsFull | Indicates if the mailbox is currently full and unable to receive any new messages. |
| MailBoxIsBusy | Indicates if the mailbox is reported by the hosting mail server as being busy and unable to currently accept new messages. |
| DisposableEmail | Indicates if the email address is believed to be disposable. Disposable email address are generally only valid for a short period of time before they are disposed and are then no longer valid. |
| SpamTrap | Indicates if the mailbox is believed to be a spam trap. |
| KnownSpammer | Indicates if the email address is known to have participated in spam-like activities. |
| BlackListedDomain | Indicates if the domain was found to be in one or more blacklists. |
| KnownComplainer | Indicates if the email address has been identified as a known complainer of receiving unsolicited mail. |
| KnownGreylister | Indicates if the mail server is known to commonly use greylisting techniques. |
| OptinRequired | Indicates if the mail server requires opting-in to send and receive messages. |
| IsWhiteListOnly | Indicates if the mail server only relays messages for users that are whitelisted. |
| ConnectionRefused | Indicates if the mail server refuses to accept an SMTP connection. |
| EmailIsBad | Indicates that the email address failed a critical check, such as SMTP verification. |
| Bot | Indicates that the email address has been reported as being a known bot. |
| GreyListTactic | Indicates if the mail server responded with a known greylist tactic. |
| MailServerTemporarilyUnavailable | Indicates that the mail server may be temporarily unavailable or too busy to respond. |
| ServerConnectTimeout | Indicates that a connection to the recipient mail server could not be established. |
| MailBoxTimeout | Indicates that the connection to the mail server timed out when trying to verify the email address. |
| TemporaryReject | Indicates that the email address was temporarily rejected by the mail server. This is also known as a soft-bounce and the rejection is not permanent. There are many reasons for why a mail server may respond with a temporary reject. The mailbox or server may be busy, unavailable, or using a greylist. When a mail server does this it typically wants you to wait at least 15 minutes and then try again later. |
| MisspelledDomain | Indicates if the email domain appears to be misspelt. (true/false) |
| MisspelledSuggestion | Suggest Correct Domain Spelling. |
4.3 Error in the Validation Process
As the Validation process involves several steps, it’s possible that one of these steps might fail for some reason. In this case, the response will be a valid response but there will be some Validation Codes indicating the problem.
Sample XML and JSON Response with some Validation Problem:
<req:profileResponse>
<req:transactionGuid>1d39bec2-7f7e-42b9-bdfd-3909bf20f44d</req:transactionGuid>
<req:componentName>EMail Validation</req:componentName>
<req:componentStatus>SUCCESS</req:componentStatus>
<req:componentAction>match</req:componentAction>
<req:responseType>VALIDATE</req:responseType>
<req:notes>[]</req:notes>
<!-- Billing Invoice -->
<req:invoice>
<req:invoiceList>
<req:invoiceGuid>F7210D60-F4BF-4024-82ED-75A8EB5C0681</req:invoiceGuid>
<req:billingInformationGuid>477B8BFB-B3EA-4FA5-9015-431047E046EC</req:billingInformationGuid>
<req:billingPoints>21</req:billingPoints>
<req:creditsUsed>1</req:creditsUsed>
<req:dataSetInvoices>
<req:dataSetCode>EMAIL</req:dataSetCode>
<req:billingPoints>1</req:billingPoints>
<req:recordsReturned>1</req:recordsReturned>
<req:dataLicenceGuid>477B8BFB-B3EA-4FA5-9015-431047E046EC</req:dataLicenceGuid>
</req:dataSetInvoices>
</req:invoiceList>
</req:invoice>
<!-- Response Data -->
<req:validateResponse>
<req:recordsReturned>1</req:recordsReturned>
<req:responseCount>1</req:responseCount>
<!-- Response per Input Email -->
<req:response>
<req:input>[email protected]</req:input>
<req:status>FAILURE</req:status>
<req:validityFlag>UNKNOWN</req:validityFlag>
<req:validationCodes>
<data:item>
<data:key>ErrorDescription</data:key>
<data:value>Call to mail server timeout</data:value>
</data:item>
<data:item>
<data:key>ErrorDescriptionCode</data:key>
<data:value>BE070001</data:value>
</data:item>
<data:item>
<data:key>MisspelledDomain</data:key>
<data:value>False</data:value>
</data:item>
</req:validationCodes>
</req:response>
</req:validateResponse>
</req:profileResponse>
{
"profileHeader": {
"profileGuid": "20B3F459-7D04-42AD-B7E2-AA1D5FE07E82",
"profileName": "Email",
"transactionGuid": "076B89EA-F6D6-4A3C-ABA5-38CCC89F3C4F",
"transactionTimeStamp": 1433167116839,
"profileStatus": "SUCCESS",
"remarks": null
},
"profileResponseDetails": [ {
"transactionGuid": "a3c9c522-0a44-4e75-93fc-af1052520233",
"componentName": "EMail Validation",
"componentStatus": "SUCCESS",
"componentAction": "match",
"responseType": "VALIDATE",
"notes": "[]",
"invoice": {
"invoiceList": [ {
"invoiceGuid": "109A0D0F-0769-49F0-95CC-7CD123EEF4F5",
"billingInformationGuid": "477B8BFB-B3EA-4FA5-9015-431047E046EC",
"dataLicenceDescription": null,
"billingPoints": 1,
"creditsUsed": 1,
"dataSetInvoices": [ {
"dataSetCode": "EMAIL",
"billingPoints": 1,
"recordsReturned": 1,
"dataLicenceGuid": "477B8BFB-B3EA-4FA5-9015-431047E046EC"
}]
}],
"tmp": null
},
"captureResponse": null,
"validateResponse": {
"resultStatus": null,
"recordsReturned": 1,
"responseCount": 1,
"response": [ {
"input": "[email protected]",
"status": "SUCCESS",
"validityFlag": "UNKNOWN",
"validationCodes": {
"item": [
{
"key": "ErrorDescription",
"value": "Call to mail server timeout"
},
{
"key": "ErrorDescriptionCode",
"value": "BE070001"
},
{
"key": "MisspelledDomain",
"value": "False"
}
],
"tmp": null
}
}]
},
"verifyResponse": null,
"traceResponse": null
}]
}
5. Error Information
Information on possible error codes is given here: Error Code Information
Предположим, у вас есть простая задача — создать форму, которая даст пользователю возможность подписаться на e-mail оповещения. Разумеется, вам необходимо предотвратить ввод в эту форму всякого мусора, при этом не должно получаться так, чтобы валидный адрес вдруг был забракован системой.
Как же выглядит e-mail адрес? Интуитивно можно предположить, что так:
// Пример адреса:
johndoe@example.com
// В виде составных частей:
${MAILBOX}@${SUBDOMAIN}.${TLD}
// Регулярка, которую можно было бы использовать
[a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+
Выглядит хорошо, но это совершенно не тот случай, когда стоит доверять интуиции. Доверять следует спецификации. А спецификация говорит нам следующее:
// Пропущен домен? Всё нормально, письмо уйдёт на локаль!
john-doe
// Да, это тоже валидно, но такого ящика не существует с вероятностью 99%
john-doe@com
// И это валидно, но доменов из одной буквы не существует
john-doe@example.c
// Оу, мы кажется забыли про субдомены. Мы же не можем просто забыть про .co.uk?
john@doe.example.com
// Да, IP адрес в качестве сервера это тоже нормально
john@[192.168.1.1]
// По спецификации подходит, но такой домен не может быть зарегистрирован
john@-doe.com
// А ещё можно делать так:
john.doe@example.com
// Но нельзя так:
john..doe@eaxmple.com
.john@example.com
john.@example.com
Конечно, и тут можно обойтись с помощью регулярного выражения:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[x01-x08x0bx0cx0e-x1fx21x23-x5bx5d-x7f]|\[x01-x09x0bx0cx0e-x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[x01-x08x0bx0cx0e-x1fx21-x5ax53-x7f]|\[x01-x09x0bx0cx0e-x7f])+)])
Но с этим есть несколько проблем:
- Как вы будете проверять правильность этого монстра? Такие регулярные выражения переходят «из уст в уста» на форумах, и каждый добавляет в них функциональность до тех пор, пока работа с выражением становится невозможной. И это именно тот случай.
- Я бы не сказал, что регулярные выражения такой длины эффективнее, чем другие методы. Чем длиннее выражение, тем дольше оно будет компилироваться (сравнение всегда происходит за O(n)).
- С помощью регулярного выражения можно сделать только проверку на соответствие. Выполнить проверку на то, находится ли домен в чёрном списке, у вас уже, увы, не получится.
Давайте пойдём другим путём
Вот основа нашей проверки:
char[] input; // Строка, которую нужно проверить
int index = 0; // Итератор для input
char ch; // Текущий символ (input[index])
int state = 0; // Состояние проверки (-1 для ошибки)
while (index <= input.length && state != -1) {
if (index == input.length) {
ch = ''; // Символ, по которому проверка прекращается
}
else {
ch = input[index];
}
switch (state) {
// case 0: {...
}
index++;
}
А вот диаграмма, описывающая алгоритм, по которому наша программа будет работать:
Если вы заметили, что тут не все правила соблюдаются — не волнуйтесь, мы вернёмся к этому позже. Если вы не заметили, и вообще не понимаете, что тут происходит, то сейчас объясню.
Вершина графа — состояние проверки. Ребро графа — прочитанный символ. Если в результате считывания символа невозможно перейти ни по одному ребру, значит, адрес не валиден. Вот, например, как будет реализована первая часть этого алгоритма:
case 0: {
if (ch >= 'a' && ch <= 'z') {
count++;
break; // State stays the same
}
if (ch == '') {
state = 1; // EOL
break;
}
state = -1; // Error
break;
}
Теперь о проверках, которые мы сделаем, после того, как код пройдёт по этой диаграмме:
public class Validator {
public static boolean isValid(final char[] input) {
int state = 0;
char ch;
int index = 0;
String local = null;
ArrayList<String> domain = new ArrayList<String>();
// Код проверки по диаграмме
// [..]
// Не прошло валидацию
if (state != 6)
return false;
// Домен должен быть по меньшей мере второго уровня
if (domain.size() < 2)
return false;
// RFC 5321 ограничивает длину имени ящика до 64 символов
if (local.length() > 64)
return false;
// RFC 5321 ограничивает длину адреса до 254 символов
if (input.length > 254)
return false;
// Доменная зона должна состоять только из букв и быть по меньше мере два символо длинной
index = input.length - 1;
while (index > 0) {
ch = input[index];
if (ch == '.' && input.length - index > 2) {
return true;
}
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) {
return false;
}
index--;
}
return true;
}
}
Собираем всё вместе
public class EmailValidator {
public static boolean isValid(final char[] input) {
if (input == null) {
return false;
}
int state = 0;
char ch;
int index = 0;
int mark = 0;
String local = null;
ArrayList<String> domain = new ArrayList<String>();
while (index <= input.length && state != -1) {
if (index == input.length) {
ch = ''; // Так мы обозначаем конец нашей работы
}
else {
ch = input[index];
if (ch == '') {
// символ, которым мы кодируем конец работы, не может быть частью ввода
return false;
}
}
switch (state) {
case 0: {
// Первый символ {atext} -- текстовой части локального имени
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || ch == '_' || ch == '-'
|| ch == '+') {
state = 1;
break;
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 1: {
// Остальные символы {atext} -- текстовой части локального имени
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || ch == '_' || ch == '-'
|| ch == '+') {
break;
}
if (ch == '.') {
state = 2;
break;
}
if (ch == '@') { // Конец локальной части
local = new String(input, 0, index - mark);
mark = index + 1;
state = 3;
break;
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 2: {
// Переход к {atext} (текстовой части) после точки
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9') || ch == '_' || ch == '-'
|| ch == '+') {
state = 1;
break;
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 3: {
// Переходим {alnum} (домену), проверяем первый символ
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'Z')) {
state = 4;
break;
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 4: {
// Собираем {alnum} --- домен
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'Z')) {
break;
}
if (ch == '-') {
state = 5;
break;
}
if (ch == '.') {
domain.add(new String(input, mark, index - mark));
mark = index + 1;
state = 5;
break;
}
// Проверка на конец строки
if (ch == '') {
domain.add(new String(input, mark, index - mark));
state = 6;
break; // Дошли до конца строки -> заканчиваем работу
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 5: {
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'Z')) {
state = 4;
break;
}
if (ch == '-') {
break;
}
// Если встретили неправильный символ -> отмечаемся в state об ошибке
state = -1;
break;
}
case 6: {
// Успех! (На самом деле, мы сюда никогда не попадём)
break;
}
}
index++;
}
// Остальные проверки
// Не прошли проверку выше? Возвращаем false!
if (state != 6)
return false;
// Нам нужен домен как минимум второго уровня
if (domain.size() < 2)
return false;
// Ограничения длины по спецификации RFC 5321
if (local.length() > 64)
return false;
// Ограничения длины по спецификации RFC 5321
if (input.length > 254)
return false;
// Домен верхнего уровня должен состоять только из букв и быть не короче двух символов
index = input.length - 1;
while (index > 0) {
ch = input[index];
if (ch == '.' && input.length - index > 2) {
return true;
}
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) {
return false;
}
index--;
}
return true;
}
}
Перевод статьи «Validating Email Addresses with a Regex? Do yourself a favor and don’t»
Статья написана студентом Хекслета. Мнение автора может не совпадать с позицией редакции
Рассказываю, как с помощью регулярного выражения осуществить валидацию адреса электронной почты.
Задача:
Есть текстовое поле, куда пользователь должен вводить E-mail.
- Если поле проходит валидацию — оно должно иметь зеленую подсветку;
- Если нет — красную.
Первым делом добавляем input в HTML. Здесь все просто:
input(type='email' placeholder='E-mail')
Для простоты восприятия предположим, что больше на странице ничего нет, поэтому не станем добавлять лишние атрибуты.
Так как подсветка должна меняться в реальном времени, добавим «слушатель» на input:
const input = document.querySelector('input');
input.addEventListener('input', onInput);
Функция onInput будет менять цвет css-свойства border на зеленый, если введенный в input текст валиден, или на красный — если нет.
const EMAIL_REGEXP = /^(([^<>()[].,;:s@"]+(.[^<>()[].,;:s@"]+)*)|(".+"))@(([^<>()[].,;:s@"]+.)+[^<>()[].,;:s@"]{2,})$/iu;
const input = document.querySelector('input');
function onInput() {
if (isEmailValid(input.value)) {
input.style.borderColor = 'green';
} else {
input.style.borderColor = 'red';
}
}
input.addEventListener('input', onInput);
function isEmailValid(value) {
return EMAIL_REGEXP.test(value);
Функция isEmailValid будет сравнивать введенное пользователем значение с регулярным выражением. В успешном случае функция вернет true, иначе — false.
Вот и все! Скрипт готов. Его работу вы можете проверить в моем Codepen.
ПОДПИСКА НА РАССЫЛКУ СРЕДСТВАМИ PHP – часть2.
Валидация имени и email адреса пользователя.
В предыдущей статье, размещенной по ссылке, мы создали html-файл c формой подписки на рассылку и организовали передачу данных из html-формы в php-скрипт, который размещает в таблице «subscribe» введенные пользователем данные (имя и email-адрес). Функцию подключения к базе данных мы вынесли в отдельный файл. В итоге у нас получилось 3 файла:
- «subscribe.html» содержит форму подписки на рассылку;
- «config.php» устанавливает соединение с базой данных;
- «subscribe.php» принимает данные из html-формы и после соединения с БД вносит полученные данные в таблицу «subscribe»
Потерянным звеном этой цепочки оказалась проверка введенных пользователем данных. Восполним этот пробел и напишем функцию валидации email и имени пользователя. При проверке будем руководствоваться следующими критериями соответствия:
Имя пользователя:
- Содержит от 2 до 50 символов.
- Может состоять из букв русского и латинского алфавита, чисел, символа подчеркивания и пробела.
Email пользователя:
- Содержит от 3 до 50 символов.
- Соответствует структуре логин@доменное-имя.доменная-зона. При этом логин, доменное имя и доменная зона содержат только цифры и буквы латинского алфавита.
Руководствуясь перечисленными критериями соответствия дополним файл «subscribe.php» двумя функциями:
1. Функция валидации имени пользователя:
function validate_name($data) {
$err=""; /* присваиваем переменной $err пустую строку */
if(strlen($data)<2 || strlen($data)>50) /* если длина переменной $data меньше 2 или больше 50 символов*/
$err = "Длина имени должна быть от 2 до 50 символов";
if (preg_match("/[^(w)|(x7F-xFF)|(s)]/",$data)) /* если в имени содержатся недопустимые символы */
$err = $err . "<p>В написании имени допустимы только буквы латинского и русского алфавита,цифры, символ подчеркивания и пробел</p>";
if(!empty($err))
return($err);
else
return 0;
}
Переменная $err, презентованная в начале функции, предназначена для хранения текста ошибок. Для проверки количества символов используется функция strlen($data). Корректно ли введенное пользователем имя мы проверяем с помощью регулярного выражения.
2. Функция валидации email-адреса пользователя:
function validate_email($data){
$err ="";
if(strlen($data)<3 || strlen($data)>50) /* если длина email меньше 3 и больше 50 */
$err = "Email должен быть от 3 до 50 символов"; /*записываем в переменную $err сообщение об ошибке */
if(!preg_match('#^([w]+.?)+(?<!.)@(?!.)[a-zа-я0-9ё.-]+.?[a-zа-яё]{2,}$#ui', $data)) /* если введенный адрес недопустимого формата */
$err = $err . "<p>Недопустимый формат email-адреса</p>"; /*записываем в переменную $err сообщение об ошибке */
if(!empty($err))
return($err);
else
return 0;
}
По аналогии с предыдущей функцией, в переменной $err мы будем хранить текст ошибок, количество символов проверим с помощью функции strlen($data), а в корректности email-адреса убедимся посредством регулярного выражения.
Если вы знакомы с функцией filter_var(), у вас может возникнуть вопрос: зачем городить регулярку, если можно решить вопрос простой функцией? Дело в том, что функция filter_var() «дискредитирует» email-адреса, содержащие кириллические символы. Приходится выбирать между дополнительным числом подписчиков в базе данных и компактной функцией с небольшим изъяном.
Функция валидации инпутов из формы подписки на рассылку
А теперь неплохо было бы объединить описанные выше функции в единую функцию валидации полученных из формы данных validate_inputs():
function validate_inputs($data_name,$data_email){
$err="";
$err_name = validate_name($data_name); /* вызываем функцию валидации имени пользователя */
$error_email = validate_email($data_email); /* вызываем функцию валидации email-адреса пользователя */
if(!empty($err_name))
$err = $err_name;
if(!empty($error_email))
$err = $err . $error_email;
return $err;
}
В данной функции мы поочередно выполняется валидация имени и email адреса, и возвращается текст ошибок или пустую строку.
Функция валидации готова! Осталось произвести вызов этой функции в php-скрипте сразу после получения переменных:
...
if(isset($_POST['submit_form']))
{
$name=$_POST["user_name"];
$email=$_POST["email"];
$error_form = validate_inputs($name, $email); /* вызываем функцию валидации формы*/
if(!empty($error_form)) { /* если найдена ошибка */
echo $error_form; /* выводим сообщение об ошибке */
}
else { /* иначе - вызываем подготовленный запрос */
$name=$_POST["user_name"]; /* извлекаем имя пользователя из массива $_POST в переменную $name */
$email=$_POST["email"]; /* извлекаем email пользователя из массива $_POST в переменную $email */
$prepared = $mysqli->prepare("insert into subscribe values('',?,?)"); /* формируем запрос, в котором вместо параметров записаны символы вопросительного знака */
$prepared->bind_param("ss",$name, $email); /* привязываем переменные имени и emaila параметрам запроса */
if($prepared->execute()) /* если запрос выполнен, сообщаем об успехе */
echo "Поздравляем! Подписка успешно оформлена! ";
else /*иначе - сообщаем об ошибке*/
echo "Ошибка запроса";
$prepared->close();
}
}
?>
Таким образом, размещение новой строки в таблице БД происходит только в том случае, если введенные пользователем данные удовлетворяют прописанным в функции validate_inputs() условиям.
Проверяем, содержится ли уже в таблице subscribe введенный пользователем email-адрес.
Чтобы не плодить в таблице записи с одинаковыми email-адресами, предлагаю после вызова функции validate_inputs() выполнить подготавливаемый mysqli-запрос на поиск в таблице «subscribe» строк с введенным пользователем email-адресом в ячейке email. Запрос будет выглядеть следующим образом:
$prepared = $mysqli->prepare("select id, name, email from subscribe where email = ?"); /* подготавливаем запрос - выбрать из таблицы строки с введенным пользователем email-адресом */
$prepared->bind_param("s", $email); /* привязываем переменную emaila к параметру запроса */
$prepared->execute(); /* выполняем запрос */
$prepared->store_result(); /* сохраняем результат запроса */
if($prepared->num_rows === 0) { /* если не найдена ни одна строка с таким email-адресом */
/* здесь будет находиться запрос для добавления пользовательских данных в
таблицу БД */
}
Таким образом, файл subscribe.php после внесенных изменений будет выглядеть следующим образом: скопировать файл с пояснениями
Скачать архив файлов с кодом подписки на рассылку можно по ссылке: subscribe_form2.zip. Не забудьте файле «config.php» поменять значения переменных на корректные для вашей базы данных!
Для тех, кто решил написать простую (или сложную) программу, получающую данные от пользователя в процессе работы обязательно придётся столкнуться с вопросом валидации данных, введённых пользователем у себя в браузере. Эти данные можно как угодно обрабатывать на стороне клиента, используя навороченные проверки с помощью JavaScript. Но все эти проверки легко обходятся и всегда есть шанс того, что на сервер прилетит не то, что задумано и должно быть заранее проверено на ошибки. В этой статье расскажу, к какому решению по валидации адреса электронной почты (email) я пришёл.
В общем случае задача о валидации адреса электронной почты (email) на сервере стоит таким образом, что нужно проверить соответствие полученной строки на соблюдение стандартов. И при ближайшем рассмотрении получается, что email — это не просто куски текста, цифр и определённых спец.символов, разделённых @ и .. После внедрения IDN (Internationalized Domain Names — интернационализованные доменные имена) нужно по-хорошему ещё пытаться переводить полученные данные в Punycode, если вдруг окажется, что пользователь решил завести себе мыло с использованием национального алфавита. При этом нужно учесть ещё тот факт, что есть не просто пользователи и злоумышленники (или просто экспериментаторы), которые могут отправить винегрет ланитицы и кирилицы…
В общем, зарывшись в этот вопрос с головой я решил не влазить в эти дебри, тем более, что они куда более извилисты и тернисты. В итоге решил использовать использовать стандартные средства, предлагаемые разработчиками php. Как только они внесут какие-то доработки в язык программирования, так пользователи моих сервисов смогут использовать то, что в текущей версии для них недоступно. Для тех, кто боится потерять своих пользователей, лучше ищите другое решение. В данном вопросе я решил быть консерватором и не поддаваться тем веяниям моды, которые пока не вошли в стандарт языка. Мне так проще. Как быть с пользователями, которые используют нестандартизованные решения — это на их усмотрение. Хотят получить доступ к моим разработкам — зарегистрируют бесплатный ящик на нормальном почтовом сервисе. Хотят выпендрёжа, — это их право.
Важно!
Повторюсь. То, что прилетело к вам на сервер на вход к скрипту-обработчику данных формы, нужно проверять вне зависимости от того, какими бы проверками вы не увешали форму в браузере пользователя. Все эти проверки легко обходятся и на вход скрипту можно прислать любые кракозяблики. =D
Валидация адреса электронной почты (email) на сервере стандартными средствами php
В php есть встроенная функция фильтрации данных для обработки данных форм. Это функция filter_var(), которая фильтрует переменную с помощью определенного фильтра. У неё есть ряд фильтров, которые можно применять для обработки переменной. Я выбрал две, которые должны обеспечить защиту от злоумышленников и не отсекать пользователей, которые совершают какие-то совсем дурацкие ошибки.
- Фильтр
FILTER_SANITIZE_EMAIL, который удаляет все символы, кроме букв, цифр и!#$%&'*+-=?^_`{|}~@.[]. Использую его именно из-за пробелов, так как был не раз свидетелем того, как пользователи упорно ставили пробелы там, где их не должно быть. Зачем они это делают, так и не получилось выяснить при опросе — работа подсознания не поддаётся логическому анализу. =) - Фильтр
FILTER_VALIDATE_EMAIL, который проверяет, что значение является корректным e-mail. В целом, происходит проверка синтаксиса адреса в соответствии с RFC 822, за исключением того, что не поддерживаются комментарии, схлопывание пробельных символов и доменные имена без точек.
Программа на php валидации адреса электронной почты (email) на сервере стандартными фильтрами
Собственно, как всё это работает, можно проверить, написав простую программу:
<?php
if (isset($_POST['email'])) {$email = $_POST['email'];} else {$email = '';}
$sanitized_email = filter_var($email, FILTER_SANITIZE_EMAIL);
if (filter_var($sanitized_email, FILTER_VALIDATE_EMAIL)) {
echo "E-mail адрес <font color=green><b>" . $sanitized_email . "</b></font> указан верно<br>n";
} else {
echo "E-mail адрес <font color=red><b>" . $sanitized_email . "</b></font> указан неверно<br>n";
}
?>
<form method="post" action="">
<input type="text" name="email" placeholder="введите email">
<input class="enter" type="submit" value="Enter!">
</form>
Последние четыре строчки — это HTML-код вывода формы для ввода email’а.
Первая строчка if (isset($_POST['email'])) {$email = $_POST['email'];} else {$email = '';} — проверка на то, что поле email было заполнено. Но, при первом обращении к этому скрипту, поле не заполнено. Поэтому, чтобы не сыпались предупреджения, для этого случая, если переменная $_POST['email'] не задана, принудительно объявляем переменную $email с пустым значением ''. После этого интерпретатор php не будет выдавать никаких сообщений, даже, если включен режим отладки.
Во второй строчке $sanitized_email = filter_var($email, FILTER_SANITIZE_EMAIL); применяем фильтр FILTER_SANITIZE_EMAIL. к прилетевшей переменной $email и записываем отфильтрованное в переменную $sanitized_email.
Ну и проверяем полученную переменную фильтром FILTER_VALIDATE_EMAIL. Если проверка проходит filter_var($sanitized_email, FILTER_VALIDATE_EMAIL), выдаём сообщение, что всё хорошо. Если проверка не проходит — всё плохо.
Резюме
Если нет нужны хранить неотфильтрованную переменную, то код можно упростить до:
<?php
if (isset($_POST['email'])) {$email = $_POST['email'];} else {$email = '';}
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "E-mail адрес <font color=green><b>" . $email . "</b></font> указан верно<br>n";
} else {
echo "E-mail адрес <font color=red><b>" . $email . "</b></font> указан неверно<br>n";
}
?>
<form method="post" action="">
<input type="text" name="email" placeholder="введите email">
<input class="enter" type="submit" value="Enter!">
</form>
Просто перепрописав значение переменной $email после применения фильтра: $email = filter_var($email, FILTER_SANITIZE_EMAIL);. Так будет работать наверное чуть быстрее. =)
Таким образом я решил для себя вопрос о том, как сделать валидацию электронной почты (email) из данных формы на стороне сервера с помощью php.
Решает ли это 100% задачи? — Нет!
Но в моём случае этого достаточно.
P.S.
Есть мнение, что валидация email вообще не нужна. Нужно просто послать письмо пользователю на то, что он ввёл с кодом подтверждения. В моём случае — это следующий этап. Но оставлять без проверки того, что прилетело от пользователя в качестве его почты я пока не намерен. Мало ли кто что решит послать на вход моим программам. Да и хранить весь этот хлам в ожидании, пока пользователь (может быть) решит подтвердить свою почту, тоже не хочется. Повторюсь: неадекватные пользователи лично мне не нужны.
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Выберите, то, чем пользуетесь чаще всего:



