рдлрд╝реЙрд░реНрдо рдкрд░рд┐рддреНрдпрд╛рдЧ рд╡реНрдпрд╡рд╕рд╛рдпреЛрдВ рдХреЛ рд╣рд░ рд╕рд╛рд▓ рдЕрд░рдмреЛрдВ рдбреЙрд▓рд░ рдХрд╛ рдиреБрдХрд╕рд╛рди рдкрд╣реБрдВрдЪрд╛рддрд╛ рд╣реИ, рдФрд░ рдЕрдорд╛рдиреНрдп рдИрдореЗрд▓ рдкрддреЗ рдЗрд╕рдХреЗ рдкреНрд░рдореБрдЦ рдХрд╛рд░рдгреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИрдВред рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЧрд▓рдд рдИрдореЗрд▓ рдкрддреЗ рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдлрд╝реЙрд░реНрдо рд╕рдмрдорд┐рдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рд╣реА рддреНрд░реБрдЯрд┐ рдХрд╛ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ, рддреЛ рдирд┐рд░рд╛рд╢рд╛ рдкрд░рд┐рддреНрдпрд╛рдЧ рдХреА рдУрд░ рд▓реЗ рдЬрд╛рддреА рд╣реИред рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╕рдордп рдИрдореЗрд▓ рдкрддреЛрдВ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИ, рддрддреНрдХрд╛рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдФрд░ рдбреЗрдЯрд╛ рдЧреБрдгрд╡рддреНрддрд╛ рджреЛрдиреЛрдВ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рддрд╛ рд╣реИред
рдпрд╣ рд╡реНрдпрд╛рдкрдХ рдЧрд╛рдЗрдб рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЦреЛрдЬ рдХрд░рддрд╛ рд╣реИ, рдмреБрдирд┐рдпрд╛рджреА рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рд╕реЗ рд▓реЗрдХрд░ рдкрд░рд┐рд╖реНрдХреГрдд API-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╕рддреНрдпрд╛рдкрди рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рддрдХ рдЬреЛ рдЖрдкрдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдорд╛рдиреНрдп, рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдФрд░ рдЬреЛрдЦрд┐рдо рднрд░реЗ рдИрдореЗрд▓ рдкрддреЛрдВ рдХреЛ рдкрдХрдбрд╝рддреА рд╣реИрдВред
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЛ рд╕рдордЭрдирд╛
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдИрдореЗрд▓ рдкрддреЛрдВ рдХреЛ рддреБрд░рдВрдд рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЖрдкрдХреЗ рдлрд╝реЙрд░реНрдо рдХреЗ рд╕рд╛рде рдЗрдВрдЯрд░реИрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдлрд╝реЙрд░реНрдо рд╕рдмрдорд┐рд╢рди рдпрд╛ рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рддрдХ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдпред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдИрдореЗрд▓ рд╡реИрдзрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рддрддреНрдХрд╛рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рд╕рддреНрдпрд╛рдкрди рддрдХрдиреАрдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рд╕рддреНрдпрд╛рдкрди рдмреИрдЪ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд╕реЗ рдХреИрд╕реЗ рдЕрд▓рдЧ рд╣реИ
рдкрд╛рд░рдВрдкрд░рд┐рдХ рдмреИрдЪ рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рд╕рдВрдЧреНрд░рд╣ рдХреЗ рдмрд╛рдж рдИрдореЗрд▓ рд╕реВрдЪрд┐рдпреЛрдВ рдХреЛ рдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдХрдИ рд╕рдорд╕реНрдпрд╛рдПрдВ рдкреИрджрд╛ рдХрд░рддрд╛ рд╣реИред рдЕрдорд╛рдиреНрдп рдИрдореЗрд▓ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЖрдкрдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░ рдЪреБрдХреЗ рд╣реИрдВ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдиреЗ рд╕реБрдзрд╛рд░ рдХреЗ рдЕрд╡рд╕рд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдЕрдкрдиреА рдпрд╛рддреНрд░рд╛ рдкреВрд░реА рдХрд░ рд▓реА рд╣реИ, рдФрд░ рд╕реВрдЪрд┐рдпреЛрдВ рдХреА рд╕рдлрд╛рдИ рдПрдХ рдЕрд▓рдЧ рдкрд░рд┐рдЪрд╛рд▓рди рдХрд╛рд░реНрдп рдмрди рдЬрд╛рддрд╛ рд╣реИред
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдЕрд▓рдЧ рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдИрдореЗрд▓ рд╡реИрд▓рд┐рдбреЗрдЯрд░ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЗ рдмрд┐рдВрджреБ рдкрд░ рдкрддреЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддрд╛ рд╣реИ, рдЕрдорд╛рдиреНрдп рдбреЗрдЯрд╛ рдХреЛ рдЖрдкрдХреА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рддрддреНрдХрд╛рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдорд┐рд▓рддреА рд╣реИ, рдЬрд┐рд╕рд╕реЗ рд╡реЗ рдЕрднреА рднреА рдЕрдкрдиреЗ рдлрд╝реЙрд░реНрдо рдХреЗ рд╕рд╛рде рд╡реНрдпрд╕реНрдд рд░рд╣рддреЗ рд╣реБрдП рдЯрд╛рдЗрдкреЛ рд╕реБрдзрд╛рд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рд╡реИрдХрд▓реНрдкрд┐рдХ рдкрддреЗ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╕рддреНрдпрд╛рдкрди рдкрд╛рдЗрдкрд▓рд╛рдЗрди
рдПрдХ рд╡реНрдпрд╛рдкрдХ рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдкреНрд░рдгрд╛рд▓реА рдХреНрд░рдо рдореЗрдВ рдХрдИ рдЬрд╛рдВрдЪ рдХрд░рддреА рд╣реИ:
рд╕рд┐рдВрдЯреИрдХреНрд╕ рд╡реИрд▓рд┐рдбреЗрд╢рди: рдкрд╣рд▓реА рдкрд░рдд рдЬрд╛рдВрдЪрддреА рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдИрдореЗрд▓ рдЙрдЪрд┐рдд рдлреЙрд░реНрдореЗрдЯрд┐рдВрдЧ рдирд┐рдпрдореЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдореЗрдВ @ рдкреНрд░рддреАрдХ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рдирд╛, рд▓реЛрдХрд▓ рднрд╛рдЧ (@ рд╕реЗ рдкрд╣рд▓реЗ) рдФрд░ рдбреЛрдореЗрди рднрд╛рдЧ (@ рдХреЗ рдмрд╛рдж) рдХреЛ рд╡реИрд▓рд┐рдбреЗрдЯ рдХрд░рдирд╛, рдФрд░ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ рдХрд┐ рдХреЛрдИ рдЕрдорд╛рдиреНрдп рд╡рд░реНрдг рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИрдВред
рдбреЛрдореЗрди рд╕рддреНрдпрд╛рдкрди: рд╕рд┐рд╕реНрдЯрдо рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдбреЛрдореЗрди рдореМрдЬреВрдж рд╣реИ рдФрд░ DNS рд░рд┐рдХреЙрд░реНрдб рдХреА рдХреНрд╡реЗрд░реА рдХрд░рдХреЗ рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдпрд╣ "gmial.com" рдЬреИрд╕реЗ рдЯрд╛рдЗрдкреЛ рдпрд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЧрдврд╝реЗ рдЧрдП рдбреЛрдореЗрди рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИред
MX рд░рд┐рдХреЙрд░реНрдб рдЪреЗрдХ: рдореЗрд▓ рдПрдХреНрд╕рдЪреЗрдВрдЬ рд░рд┐рдХреЙрд░реНрдб рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ рдХрд┐ рдХреМрди рд╕реЗ рд╕рд░реНрд╡рд░ рдХрд┐рд╕реА рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП рдИрдореЗрд▓ рдХреЛ рд╣реИрдВрдбрд▓ рдХрд░рддреЗ рд╣реИрдВред MX рд░рд┐рдХреЙрд░реНрдб рдХреЗ рдмрд┐рдирд╛ рдбреЛрдореЗрди рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рдЬрд┐рд╕рд╕реЗ рдЗрди рдбреЛрдореЗрди рдкрд░ рдкрддреЗ рдЕрдорд╛рдиреНрдп рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред
SMTP рд╕рддреНрдпрд╛рдкрди: рд╕рдмрд╕реЗ рдЧрд╣рди рдЬрд╛рдВрдЪ рдЧрдВрддрд╡реНрдп рдореЗрд▓ рд╕рд░реНрд╡рд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ рд╣реЛрддреА рд╣реИ рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдИрдореЗрд▓ рднреЗрдЬреЗ рдмрд┐рдирд╛ рдореЗрд▓рдмреЙрдХреНрд╕ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рддреА рд╣реИред рдпрд╣ рдЙрди рдкрддреЛрдВ рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдбреЛрдореЗрди рд╡реИрдз рд╣реИ рд▓реЗрдХрд┐рди рд╡рд┐рд╢рд┐рд╖реНрдЯ рдореЗрд▓рдмреЙрдХреНрд╕ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИред
рдЬреЛрдЦрд┐рдо рдореВрд▓реНрдпрд╛рдВрдХрди: рдЙрдиреНрдирдд рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рд╕реЗрд╡рд╛рдПрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдХрд╛рд░рдХреЛрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рддреА рд╣реИрдВ рдЬреИрд╕реЗ рдХрд┐ рдХреНрдпрд╛ рдкрддрд╛ рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рд╣реИ, рднреВрдорд┐рдХрд╛-рдЖрдзрд╛рд░рд┐рдд рд╣реИ, рдпрд╛ рдЬреНрдЮрд╛рдд рд╕реНрдкреИрдо рдкреИрдЯрд░реНрди рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реИред
рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛
рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рд░рдХреНрд╖рд╛ рдХреА рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рдФрд░ рддрддреНрдХрд╛рд▓ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЬрдмрдХрд┐ рдЕрдХреЗрд▓реЗ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ, рдпрд╣ рд╕рд░реНрд╡рд░ рд░рд╛рдЙрдВрдб-рдЯреНрд░рд┐рдк рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд┐рдирд╛ рд╕реНрдкрд╖реНрдЯ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИред
HTML5 рдИрдореЗрд▓ рд╡реИрд▓рд┐рдбреЗрд╢рди
рдЖрдзреБрдирд┐рдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░реЛрдВ рдореЗрдВ HTML5 рдИрдореЗрд▓ рдЗрдирдкреБрдЯ рдкреНрд░рдХрд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рд╢рд╛рдорд┐рд▓ рд╣реИ:
<form id="signup-form">
<label for="email">Email Address</label>
<input
type="email"
id="email"
name="email"
required
placeholder="you@example.com"
>
<span class="error-message"></span>
<button type="submit">Sign Up</button>
</form>
type="email" рд╡рд┐рд╢реЗрд╖рддрд╛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рддреА рд╣реИ рдЬреЛ рдмреБрдирд┐рдпрд╛рджреА рдИрдореЗрд▓ рдлреЙрд░реНрдореЗрдЯ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреА рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдмреНрд░рд╛рдЙрдЬрд╝рд░ рд╡реИрд▓рд┐рдбреЗрд╢рди рдЙрджрд╛рд░ рд╣реИ рдФрд░ рдХрдИ рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ рдЕрдорд╛рдиреНрдп рдкрддреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред
рдмреЗрд╣рддрд░ JavaScript рд╡реИрд▓рд┐рдбреЗрд╢рди
рдЕрдзрд┐рдХ рдЧрд╣рди рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдЬрд╛рдВрдЪ рдХреЗ рд▓рд┐рдП, рдХрд╕реНрдЯрдо JavaScript рд╡реИрд▓рд┐рдбреЗрд╢рди рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
class EmailValidator {
constructor(inputElement) {
this.input = inputElement;
this.errorElement = inputElement.nextElementSibling;
this.setupListeners();
}
setupListeners() {
this.input.addEventListener('blur', () => this.validate());
this.input.addEventListener('input', () => this.clearError());
}
validate() {
const email = this.input.value.trim();
if (!email) {
return this.showError('Email address is required');
}
if (!this.isValidFormat(email)) {
return this.showError('Please enter a valid email address');
}
if (this.hasCommonTypo(email)) {
return this.showError(this.getTypoSuggestion(email));
}
this.showSuccess();
return true;
}
isValidFormat(email) {
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return pattern.test(email);
}
hasCommonTypo(email) {
const domain = email.split('@')[1]?.toLowerCase();
const typos = {
'gmial.com': 'gmail.com',
'gmal.com': 'gmail.com',
'gamil.com': 'gmail.com',
'hotmal.com': 'hotmail.com',
'outlok.com': 'outlook.com',
'yahooo.com': 'yahoo.com'
};
return typos.hasOwnProperty(domain);
}
getTypoSuggestion(email) {
const [local, domain] = email.split('@');
const corrections = {
'gmial.com': 'gmail.com',
'gmal.com': 'gmail.com',
'gamil.com': 'gmail.com'
};
const corrected = corrections[domain.toLowerCase()];
return `Did you mean ${local}@${corrected}?`;
}
showError(message) {
this.input.classList.add('invalid');
this.input.classList.remove('valid');
this.errorElement.textContent = message;
this.errorElement.classList.add('visible');
return false;
}
showSuccess() {
this.input.classList.add('valid');
this.input.classList.remove('invalid');
this.errorElement.classList.remove('visible');
}
clearError() {
this.errorElement.classList.remove('visible');
this.input.classList.remove('invalid', 'valid');
}
}
// Initialize validator
const emailInput = document.getElementById('email');
const validator = new EmailValidator(emailInput);
рд╡рд┐рдЬрд╝реБрдЕрд▓ рдлреАрдбрдмреИрдХ рдХреЗ рд▓рд┐рдП CSS
рд╡реИрд▓рд┐рдбреЗрд╢рди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рджреГрд╢реНрдп рд╕рдВрдХреЗрддрдХ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ:
.form-group input {
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.form-group input:focus {
outline: none;
border-color: #2196f3;
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
}
.form-group input.valid {
border-color: #4caf50;
background-image: url("data:image/svg+xml,...");
background-repeat: no-repeat;
background-position: right 12px center;
}
.form-group input.invalid {
border-color: #f44336;
}
.error-message {
display: block;
color: #f44336;
font-size: 14px;
margin-top: 4px;
opacity: 0;
transform: translateY(-4px);
transition: opacity 0.2s, transform 0.2s;
}
.error-message.visible {
opacity: 1;
transform: translateY(0);
}
API-рд╕рдВрдЪрд╛рд▓рд┐рдд рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рд╕рддреНрдпрд╛рдкрди
рдЬрдмрдХрд┐ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдлреЙрд░реНрдореЗрдЯрд┐рдВрдЧ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИ, API-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╕рддреНрдпрд╛рдкрди рдбрд┐рд▓реАрд╡рд░реЗрдмрд┐рд▓рд┐рдЯреА рд╕рддреНрдпрд╛рдкрди, рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдИрдореЗрд▓ рдбрд┐рдЯреЗрдХреНрд╢рди рдФрд░ рдЬреЛрдЦрд┐рдо рд╕реНрдХреЛрд░рд┐рдВрдЧ рд╕рд╣рд┐рдд рд╡реНрдпрд╛рдкрдХ рдИрдореЗрд▓ рдЬрд╛рдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рдбрд┐рдмрд╛рдЙрдВрд╕реНрдб API рдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛
рд╣рд░ рдХреАрд╕реНрдЯреНрд░реЛрдХ рдкрд░ API рдХреЙрд▓ рдХрд░рдирд╛ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдмрд░реНрдмрд╛рдж рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЦрд░рд╛рдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдмрдирд╛рддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХреЛ рд░реЛрдХрдиреЗ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдмрд╛рдЙрдВрд╕рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
class RealTimeEmailVerifier {
constructor(options = {}) {
this.apiKey = options.apiKey;
this.apiUrl = options.apiUrl || 'https://api.billionverify.com/v1/verify';
this.debounceMs = options.debounceMs || 500;
this.minLength = options.minLength || 5;
this.debounceTimer = null;
this.cache = new Map();
}
async verify(email, callbacks = {}) {
const { onStart, onSuccess, onError, onComplete } = callbacks;
// Clear pending verification
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
// Skip if email is too short or invalid format
if (!this.shouldVerify(email)) {
return;
}
// Check cache first
if (this.cache.has(email)) {
const cachedResult = this.cache.get(email);
onSuccess?.(cachedResult);
onComplete?.();
return cachedResult;
}
// Debounce the API call
return new Promise((resolve) => {
this.debounceTimer = setTimeout(async () => {
onStart?.();
try {
const result = await this.callApi(email);
this.cache.set(email, result);
onSuccess?.(result);
resolve(result);
} catch (error) {
onError?.(error);
resolve(null);
} finally {
onComplete?.();
}
}, this.debounceMs);
});
}
shouldVerify(email) {
if (email.length < this.minLength) return false;
if (!email.includes('@')) return false;
const basicPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return basicPattern.test(email);
}
async callApi(email) {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (!response.ok) {
throw new Error(`Verification failed: ${response.status}`);
}
return response.json();
}
clearCache() {
this.cache.clear();
}
}
рдлрд╝реЙрд░реНрдо рдПрд▓рд┐рдореЗрдВрдЯреНрд╕ рдХреЗ рд╕рд╛рде рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рди
рд╡реНрдпрд╛рдкрдХ UI рдлреАрдбрдмреИрдХ рдХреЗ рд╕рд╛рде рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдЕрдкрдиреЗ рдлрд╝реЙрд░реНрдо рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ:
class EmailFormField {
constructor(inputSelector, options = {}) {
this.input = document.querySelector(inputSelector);
this.container = this.input.closest('.form-group');
this.feedback = this.container.querySelector('.feedback');
this.spinner = this.container.querySelector('.spinner');
this.verifier = new RealTimeEmailVerifier({
apiKey: options.apiKey,
debounceMs: 600
});
this.lastVerifiedEmail = null;
this.lastResult = null;
this.setupEventListeners();
}
setupEventListeners() {
this.input.addEventListener('input', (e) => {
this.handleInput(e.target.value);
});
this.input.addEventListener('blur', () => {
this.handleBlur();
});
}
handleInput(email) {
// Reset state while typing
this.setStatus('typing');
// Perform real-time verification
this.verifier.verify(email, {
onStart: () => this.setStatus('verifying'),
onSuccess: (result) => this.handleResult(email, result),
onError: (error) => this.handleError(error)
});
}
handleBlur() {
const email = this.input.value.trim();
if (!email) {
this.setStatus('empty');
return;
}
// If we haven't verified this email yet, do it now
if (email !== this.lastVerifiedEmail) {
this.verifier.verify(email, {
onStart: () => this.setStatus('verifying'),
onSuccess: (result) => this.handleResult(email, result),
onError: (error) => this.handleError(error)
});
}
}
handleResult(email, result) {
this.lastVerifiedEmail = email;
this.lastResult = result;
if (result.is_deliverable) {
this.setStatus('valid', 'Email address verified');
} else if (result.is_disposable) {
this.setStatus('warning', 'Please use a permanent email address');
} else if (!result.is_valid) {
this.setStatus('invalid', 'This email address appears to be invalid');
} else {
this.setStatus('warning', 'We could not verify this email address');
}
}
handleError(error) {
console.error('Verification error:', error);
// Don't block user on API errors
this.setStatus('neutral', '');
}
setStatus(status, message = '') {
const statusClasses = ['typing', 'verifying', 'valid', 'invalid', 'warning', 'empty', 'neutral'];
this.container.classList.remove(...statusClasses);
this.container.classList.add(status);
this.feedback.textContent = message;
this.spinner.style.display = status === 'verifying' ? 'block' : 'none';
}
isValid() {
return this.lastResult?.is_deliverable === true;
}
getResult() {
return this.lastResult;
}
}
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП HTML рд╕рдВрд░рдЪрдирд╛
<div class="form-group">
<label for="email">Email Address</label>
<div class="input-wrapper">
<input
type="email"
id="email"
name="email"
autocomplete="email"
placeholder="you@example.com"
>
<div class="spinner" style="display: none;">
<svg class="animate-spin" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none" opacity="0.25"/>
<path fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
</svg>
</div>
<div class="status-icon"></div>
</div>
<div class="feedback"></div>
</div>
рдПрдЬ рдХреЗрд╕ рдФрд░ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЛ рдЕрдЪреНрдЫреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдХреЛ рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рдПрдЬ рдХреЗрд╕ рдХреЛ рд╕реБрдВрджрд░рддрд╛ рд╕реЗ рд╕рдВрднрд╛рд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдиреЗрдЯрд╡рд░реНрдХ рд╡рд┐рдлрд▓рддрд╛рдПрдВ
рдЬрдм рдиреЗрдЯрд╡рд░реНрдХ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдХрд╛рд░рдг API рдХреЙрд▓ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддреА рд╣реИрдВ, рддреЛ рдлрд╝реЙрд░реНрдо рд╕рдмрдорд┐рд╢рди рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмреНрд▓реЙрдХ рди рдХрд░реЗрдВ:
class ResilientEmailVerifier extends RealTimeEmailVerifier {
constructor(options) {
super(options);
this.maxRetries = options.maxRetries || 2;
this.retryDelay = options.retryDelay || 1000;
}
async callApi(email, attempt = 1) {
try {
return await super.callApi(email);
} catch (error) {
if (attempt < this.maxRetries) {
await this.delay(this.retryDelay * attempt);
return this.callApi(email, attempt + 1);
}
// Return a neutral result on failure
return {
email,
is_valid: true,
is_deliverable: null,
verification_status: 'unknown',
error: 'Verification unavailable'
};
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
рд░реЗрдЯ рд▓рд┐рдорд┐рдЯрд┐рдВрдЧ
API рдХреЛрдЯрд╛ рдХреЗ рднреАрддрд░ рд░рд╣рдиреЗ рдХреЗ рд▓рд┐рдП рдмреБрджреНрдзрд┐рдорд╛рди рд░реЗрдЯ рд▓рд┐рдорд┐рдЯрд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
class RateLimitedVerifier {
constructor(options) {
this.verifier = new RealTimeEmailVerifier(options);
this.requestQueue = [];
this.requestsPerMinute = options.requestsPerMinute || 60;
this.requestTimestamps = [];
}
async verify(email, callbacks) {
// Clean old timestamps
const oneMinuteAgo = Date.now() - 60000;
this.requestTimestamps = this.requestTimestamps.filter(t => t > oneMinuteAgo);
// Check if we're at the limit
if (this.requestTimestamps.length >= this.requestsPerMinute) {
const oldestRequest = this.requestTimestamps[0];
const waitTime = oldestRequest + 60000 - Date.now();
if (waitTime > 0) {
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
this.requestTimestamps.push(Date.now());
return this.verifier.verify(email, callbacks);
}
}
рдзреАрдореЗ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛
рдзреАрдореЗ рдХрдиреЗрдХреНрд╢рди рдкрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ:
class TimeoutAwareVerifier {
constructor(options) {
this.verifier = new RealTimeEmailVerifier(options);
this.timeout = options.timeout || 10000;
}
async verify(email, callbacks) {
const { onStart, onSuccess, onError, onComplete, onTimeout } = callbacks;
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Verification timeout')), this.timeout);
});
onStart?.();
try {
const result = await Promise.race([
this.verifier.verify(email, {}),
timeoutPromise
]);
onSuccess?.(result);
return result;
} catch (error) {
if (error.message === 'Verification timeout') {
onTimeout?.();
} else {
onError?.(error);
}
} finally {
onComplete?.();
}
}
}
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП UX рд╕рд░реНрд╡реЛрддреНрддрдо рдкреНрд░рдерд╛рдПрдВ
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдкрд░ рд╕рд╛рд╡рдзрд╛рдиреАрдкреВрд░реНрд╡рдХ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЦрд░рд╛рдм рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдирд┐рд░рд╛рд╢ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдлрд╝реЙрд░реНрдо рдкрд░рд┐рддреНрдпрд╛рдЧ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рд╕рдордп рдФрд░ рдлреАрдбрдмреИрдХ
рд╣рд░ рдХреАрд╕реНрдЯреНрд░реЛрдХ рдкрд░ рд╕рддреНрдпрд╛рдкрди рди рдХрд░реЗрдВ: рдпрд╣ рдЕрддреНрдпрдзрд┐рдХ API рдХреЙрд▓ рдФрд░ рд╡рд┐рдЪрд▓рд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ UI рдкрд░рд┐рд╡рд░реНрддрди рдмрдирд╛рддрд╛ рд╣реИред 400-600ms рджреЗрд░реА рдХреЗ рд╕рд╛рде рдбрд┐рдмрд╛рдЙрдВрд╕рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
рд▓реЛрдбрд┐рдВрдЧ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджрд┐рдЦрд╛рдПрдВ: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╕рдордЭрдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рд╕рддреНрдпрд╛рдкрди рдХрдм рд╣реЛ рд░рд╣рд╛ рд╣реИред рдПрдХ рд╕реВрдХреНрд╖реНрдо рд╕реНрдкрд┐рдирд░ рдпрд╛ рдкрд▓реНрд╕рд┐рдВрдЧ рдПрдиреАрдореЗрд╢рди рд╡рд┐рдЪрд▓рд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИред
рддрддреНрдХрд╛рд▓ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдлреАрдбрдмреИрдХ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ: рдмреБрдирд┐рдпрд╛рджреА рдлреЙрд░реНрдореЗрдЯ рд╡реИрд▓рд┐рдбреЗрд╢рди API рдХреЙрд▓ рдХреЗ рдмрд┐рдирд╛ рддреБрд░рдВрдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИред API рд╕рддреНрдпрд╛рдкрди рдХреЛ рддрдм рддрдХ рд╕рд╣реЗрдЬреЗрдВ рдЬрдм рддрдХ рдИрдореЗрд▓ рдкреВрд░реНрдг рди рджрд┐рдЦреЗред
рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рджрд┐рд╢рд╛рдирд┐рд░реНрджреЗрд╢
рд╡рд┐рд╢рд┐рд╖реНрдЯ рдФрд░ рд╕рд╣рд╛рдпрдХ рдмрдиреЗрдВ: "рдЕрдорд╛рдиреНрдп рдИрдореЗрд▓" рдХреЗ рдмрдЬрд╛рдп, рдХрд╣реЗрдВ "рдпрд╣ рдИрдореЗрд▓ рдбреЛрдореЗрди рдореМрдЬреВрдж рдирд╣реАрдВ рджрд┐рдЦрддрд╛ рд╣реИред рдХреНрдпрд╛ рдЖрдкрдХрд╛ рдорддрд▓рдм gmail.com рдерд╛?"
рдЬрдм рд╕рдВрднрд╡ рд╣реЛ рд╕реБрдЭрд╛рд╡ рджреЗрдВ: рдпрджрд┐ рдбреЛрдореЗрди рдЯрд╛рдЗрдкреЛ рдЬреИрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ, рддреЛ рд╕реБрдзрд╛рд░ рдХрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрдВред "gmial.com" рдЬреИрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рдЯрд╛рдЗрдкреЛ рдХреЛ "рдХреНрдпрд╛ рдЖрдкрдХрд╛ рдорддрд▓рдм gmail.com рдерд╛?" рд╕рдВрдХреЗрдд рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЖрдХреНрд░рд╛рдордХ рди рдмрдиреЗрдВ: рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдИрдореЗрд▓ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЪреЗрддрд╛рд╡рдирд┐рдпреЛрдВ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдлрдЯрдХрд╛рд░рдирд╛ рдирд╣реАрдВред "рдЦрд╛рддрд╛ рд╕реБрд░рдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП, рдХреГрдкрдпрд╛ рдПрдХ рд╕реНрдерд╛рдпреА рдИрдореЗрд▓ рдкрддреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ" "рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдИрдореЗрд▓ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рд╣реИ" рд╕реЗ рдмреЗрд╣рддрд░ рд╣реИред
рдкреНрд░рдЧрддрд┐рд╢реАрд▓ рд╕рдВрд╡рд░реНрджреНрдзрди
рд╕рддреНрдпрд╛рдкрди рдХреЛ рдПрдХ рд╕рдВрд╡рд░реНрджреНрдзрди рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ:
class ProgressiveEmailVerification {
constructor(inputSelector, options) {
this.input = document.querySelector(inputSelector);
this.form = this.input.closest('form');
this.hasApiAccess = !!options.apiKey;
// Always enable basic validation
this.enableBasicValidation();
// Enable API verification if available
if (this.hasApiAccess) {
this.enableApiVerification(options);
}
}
enableBasicValidation() {
this.input.addEventListener('blur', () => {
const email = this.input.value.trim();
if (email && !this.isValidFormat(email)) {
this.showError('Please enter a valid email address');
}
});
}
enableApiVerification(options) {
this.verifier = new RealTimeEmailVerifier(options);
this.input.addEventListener('input', (e) => {
this.verifier.verify(e.target.value, {
onSuccess: (result) => this.handleVerificationResult(result)
});
});
}
isValidFormat(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
handleVerificationResult(result) {
// Enhanced verification results
}
showError(message) {
// Error display logic
}
}
рдлреНрд░реЗрдорд╡рд░реНрдХ-рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЖрдзреБрдирд┐рдХ JavaScript рдлреНрд░реЗрдорд╡рд░реНрдХ рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЛ рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреИрдЯрд░реНрди рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред
React рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
import { useState, useCallback, useEffect, useRef } from 'react';
function useEmailVerification(apiKey, options = {}) {
const [status, setStatus] = useState('idle');
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
const debounceRef = useRef(null);
const cacheRef = useRef(new Map());
const verify = useCallback(async (email) => {
// Clear pending verification
if (debounceRef.current) {
clearTimeout(debounceRef.current);
}
// Skip invalid emails
if (!email || !email.includes('@') || email.length < 5) {
setStatus('idle');
return;
}
// Check cache
if (cacheRef.current.has(email)) {
setResult(cacheRef.current.get(email));
setStatus('success');
return;
}
// Debounce API call
debounceRef.current = setTimeout(async () => {
setStatus('loading');
try {
const response = await fetch('https://api.billionverify.com/v1/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
if (!response.ok) throw new Error('Verification failed');
const data = await response.json();
cacheRef.current.set(email, data);
setResult(data);
setStatus('success');
} catch (err) {
setError(err);
setStatus('error');
}
}, options.debounceMs || 500);
}, [apiKey, options.debounceMs]);
return { verify, status, result, error };
}
function EmailInput({ apiKey }) {
const [email, setEmail] = useState('');
const { verify, status, result } = useEmailVerification(apiKey);
useEffect(() => {
verify(email);
}, [email, verify]);
const getStatusClass = () => {
if (status === 'loading') return 'verifying';
if (status === 'success' && result?.is_deliverable) return 'valid';
if (status === 'success' && !result?.is_deliverable) return 'invalid';
return '';
};
return (
<div className={`form-group ${getStatusClass()}`}>
<label htmlFor="email">Email Address</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
{status === 'loading' && <span className="spinner" />}
{status === 'success' && result && (
<span className="feedback">
{result.is_deliverable
? 'тЬУ Email verified'
: 'This email may not be deliverable'}
</span>
)}
</div>
);
}
Vue.js рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
<template>
<div :class="['form-group', statusClass]">
<label for="email">Email Address</label>
<div class="input-wrapper">
<input
type="email"
id="email"
v-model="email"
@input="handleInput"
placeholder="you@example.com"
/>
<span v-if="isVerifying" class="spinner"></span>
</div>
<span v-if="feedbackMessage" class="feedback">
{{ feedbackMessage }}
</span>
</div>
</template>
<script>
import { ref, computed, watch } from 'vue';
import { useDebounceFn } from '@vueuse/core';
export default {
props: {
apiKey: { type: String, required: true }
},
setup(props) {
const email = ref('');
const status = ref('idle');
const result = ref(null);
const cache = new Map();
const verifyEmail = useDebounceFn(async (emailValue) => {
if (!emailValue || !emailValue.includes('@')) {
status.value = 'idle';
return;
}
if (cache.has(emailValue)) {
result.value = cache.get(emailValue);
status.value = 'success';
return;
}
status.value = 'loading';
try {
const response = await fetch('https://api.billionverify.com/v1/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${props.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email: emailValue })
});
const data = await response.json();
cache.set(emailValue, data);
result.value = data;
status.value = 'success';
} catch (error) {
status.value = 'error';
}
}, 500);
const handleInput = () => {
verifyEmail(email.value);
};
const isVerifying = computed(() => status.value === 'loading');
const statusClass = computed(() => {
if (status.value === 'loading') return 'verifying';
if (status.value === 'success' && result.value?.is_deliverable) return 'valid';
if (status.value === 'success' && !result.value?.is_deliverable) return 'invalid';
return '';
});
const feedbackMessage = computed(() => {
if (status.value !== 'success' || !result.value) return '';
return result.value.is_deliverable
? 'тЬУ Email verified'
: 'This email may not be deliverable';
});
return {
email,
handleInput,
isVerifying,
statusClass,
feedbackMessage
};
}
};
</script>
рдкреНрд░рджрд░реНрд╢рди рдЕрдиреБрдХреВрд▓рди рд░рдгрдиреАрддрд┐рдпрд╛рдБ
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рд╕рд╛рд╡рдзрд╛рдиреА рд╕реЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд┐рдП рдЬрд╛рдиреЗ рдкрд░ рдкреЗрдЬ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд╕реБрдЪрд╛рд░реВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрди рдЕрдиреБрдХреВрд▓рди рд░рдгрдиреАрддрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВред
рд╕рддреНрдпрд╛рдкрди рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдХреИрд╢ рдХрд░рдирд╛
рдЕрдирд╛рд╡рд╢реНрдпрдХ API рдХреЙрд▓ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдХреИрд╢ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
class VerificationCache {
constructor(options = {}) {
this.maxSize = options.maxSize || 100;
this.ttl = options.ttl || 300000; // 5 minutes
this.cache = new Map();
}
get(email) {
const normalized = email.toLowerCase().trim();
const entry = this.cache.get(normalized);
if (!entry) return null;
if (Date.now() > entry.expiresAt) {
this.cache.delete(normalized);
return null;
}
return entry.result;
}
set(email, result) {
const normalized = email.toLowerCase().trim();
// Enforce max size with LRU eviction
if (this.cache.size >= this.maxSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
this.cache.set(normalized, {
result,
expiresAt: Date.now() + this.ttl
});
}
clear() {
this.cache.clear();
}
}
рд╕рддреНрдпрд╛рдкрди рдореЙрдбреНрдпреВрд▓ рдХреЛ рд▓реЗрдЬрд╝реА рд▓реЛрдб рдХрд░рдирд╛
рд╕рддреНрдпрд╛рдкрди рдореЙрдбреНрдпреВрд▓ рдХреЛ рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдиреЗ рдкрд░ рд▓реЛрдб рдХрд░реЗрдВ:
async function initEmailVerification(inputSelector, options) {
// Only load when user focuses on email field
const input = document.querySelector(inputSelector);
input.addEventListener('focus', async function onFocus() {
input.removeEventListener('focus', onFocus);
const { RealTimeEmailVerifier } = await import('./email-verifier.js');
const verifier = new RealTimeEmailVerifier(options);
input.addEventListener('input', (e) => {
verifier.verify(e.target.value, {
onSuccess: (result) => updateUI(result),
onError: (error) => handleError(error)
});
});
}, { once: true });
}
рдмрдВрдбрд▓ рдЖрдХрд╛рд░ рдХреЛ рдХрдо рдХрд░рдирд╛
рдкреЗрдЬ рд▓реЛрдб рдкрд░ рдкреНрд░рднрд╛рд╡ рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреНрд░реА-рд╢реЗрдХрд┐рдВрдЧ рдФрд░ рдХреЛрдб рд╕реНрдкреНрд▓рд┐рдЯрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
// email-verifier/index.js - Main entry point
export { RealTimeEmailVerifier } from './verifier';
export { EmailFormField } from './form-field';
// email-verifier/lite.js - Lightweight version for basic validation
export { BasicEmailValidator } from './basic-validator';
рд╕рддреНрдпрд╛рдкрди рдкреНрд░рднрд╛рд╡рд╢реАрд▓рддрд╛ рдХреЛ рдорд╛рдкрдирд╛
рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдЖрдкрдХреЗ рдлрд╝реЙрд░реНрдо рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдореБрдЦреНрдп рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдХреЛ рдЯреНрд░реИрдХ рдХрд░реЗрдВред
рдореБрдЦреНрдп рдкреНрд░рджрд░реНрд╢рди рд╕рдВрдХреЗрддрдХ
рд╕рддреНрдпрд╛рдкрди рд╕рдлрд▓рддрд╛ рджрд░: рд╕рддреНрдпрд╛рдкрди рдкрд╛рд╕ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдИрдореЗрд▓ рдХрд╛ рдкреНрд░рддрд┐рд╢рддред рдХрдо рджрд░реЗрдВ UX рд╕рдорд╕реНрдпрд╛рдУрдВ рдпрд╛ рд▓рдХреНрд╖реНрдпреАрдХрд░рдг рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╕рдВрдХреЗрдд рджреЗ рд╕рдХрддреА рд╣реИрдВред
рдлрд╝реЙрд░реНрдо рдкреВрд░реНрдгрддрд╛ рджрд░: рд╕рддреНрдпрд╛рдкрди рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдФрд░ рдмрд╛рдж рдореЗрдВ рдкреВрд░реНрдгрддрд╛ рджрд░реЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВред рдЕрдЪреНрдЫреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреВрд░реНрдгрддрд╛ рджрд░реЛрдВ рдХреЛ рдмрдирд╛рдП рд░рдЦрдирд╛ рдпрд╛ рд╕реБрдзрд╛рд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЕрдорд╛рдиреНрдп рдИрдореЗрд▓ рджрд░: рдЯреНрд░реИрдХ рдХрд░реЗрдВ рдХрд┐ рдлрд╝реЙрд░реНрдо рднрд░рддреЗ рд╕рдордп рдХрд┐рддрдиреЗ рдЕрдорд╛рдиреНрдп рдИрдореЗрд▓ рдкрдХрдбрд╝реЗ рдЧрдП рдФрд░ рд╕реБрдзрд╛рд░реЗ рдЧрдП рдмрдирд╛рдо рдмрд╛рдж рдореЗрдВ рдЦреЛрдЬреЗ рдЧрдПред
API рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╕рдордп: рд╕рддреНрдпрд╛рдкрди рдЧрддрд┐ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░реЗрдВред рдзреАрдореА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдПрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдирд┐рд░рд╛рд╢ рдХрд░рддреА рд╣реИрдВ рдФрд░ рдкрд░рд┐рддреНрдпрд╛рдЧ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдХрд░рддреА рд╣реИрдВред
рдПрдирд╛рд▓рд┐рдЯрд┐рдХреНрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
class VerificationAnalytics {
constructor(analyticsProvider) {
this.analytics = analyticsProvider;
}
trackVerificationStart(email) {
this.analytics.track('email_verification_started', {
domain: this.extractDomain(email),
timestamp: Date.now()
});
}
trackVerificationComplete(email, result, duration) {
this.analytics.track('email_verification_completed', {
domain: this.extractDomain(email),
is_valid: result.is_valid,
is_deliverable: result.is_deliverable,
is_disposable: result.is_disposable,
risk_score: result.risk_score,
duration_ms: duration
});
}
trackVerificationError(email, error) {
this.analytics.track('email_verification_error', {
domain: this.extractDomain(email),
error_type: error.name,
error_message: error.message
});
}
trackFormSubmission(email, verificationResult) {
this.analytics.track('form_submitted_with_verification', {
email_verified: !!verificationResult,
verification_passed: verificationResult?.is_deliverable,
verification_status: verificationResult?.verification_status
});
}
extractDomain(email) {
return email.split('@')[1]?.toLowerCase() || 'unknown';
}
}
рд╕реБрд░рдХреНрд╖рд╛ рд╡рд┐рдЪрд╛рд░
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдореЗрдВ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рднреЗрдЬрдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЧреЛрдкрдиреАрдпрддрд╛ рдХреА рд░рдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рдЙрдЪрд┐рдд рд╕реБрд░рдХреНрд╖рд╛ рдЙрдкрд╛рдп рд▓рд╛рдЧреВ рдХрд░реЗрдВред
API рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рд╕реБрд░рдХреНрд╖рд╛
рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдХреЛрдб рдореЗрдВ рдХрднреА рднреА API рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреЛ рдЙрдЬрд╛рдЧрд░ рди рдХрд░реЗрдВред рдмреИрдХрдПрдВрдб рдкреНрд░реЙрдХреНрд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
// Backend proxy endpoint (Node.js/Express)
app.post('/api/verify-email', async (req, res) => {
const { email } = req.body;
// Validate input
if (!email || typeof email !== 'string') {
return res.status(400).json({ error: 'Invalid email' });
}
// Rate limiting per IP
const clientIp = req.ip;
if (await isRateLimited(clientIp)) {
return res.status(429).json({ error: 'Too many requests' });
}
try {
const response = await fetch('https://api.billionverify.com/v1/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BILLIONVERIFY_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
const result = await response.json();
res.json(result);
} catch (error) {
res.status(500).json({ error: 'Verification service unavailable' });
}
});
рдЗрдирдкреБрдЯ рд╕реИрдирд┐рдЯрд╛рдЗрдЬреЗрд╢рди
рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд╕реЗ рдкрд╣рд▓реЗ рд╣рдореЗрд╢рд╛ рдИрдореЗрд▓ рдЗрдирдкреБрдЯ рдХреЛ рд╕реИрдирд┐рдЯрд╛рдЗрдЬ рдХрд░реЗрдВ:
function sanitizeEmail(email) {
if (typeof email !== 'string') return '';
return email
.toLowerCase()
.trim()
.replace(/[<>\"']/g, '') // Remove potential XSS characters
.substring(0, 254); // Max email length per RFC
}
рдирд┐рд╖реНрдХрд░реНрд╖
рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдлрд╝реЙрд░реНрдо рдЗрдВрдЯрд░реИрдХреНрд╢рди рдХреЛ рдирд┐рд░рд╛рд╢рд╛рдЬрдирдХ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдиреЗ рдХреЗ рдЦреЗрд▓ рд╕реЗ рдЖрддреНрдорд╡рд┐рд╢реНрд╡рд╛рд╕ рднрд░реЗ, рдирд┐рд░реНрджреЗрд╢рд┐рдд рдЕрдиреБрднрд╡реЛрдВ рдореЗрдВ рдмрджрд▓ рджреЗрддрд╛ рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╕рдордп рдИрдореЗрд▓ рдкрддреЛрдВ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдХреЗ, рдЖрдк рдЕрдорд╛рдиреНрдп рдбреЗрдЯрд╛ рдХреЛ рдЕрдкрдиреА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рд╕реЗ рд░реЛрдХрддреЗ рд╣реИрдВ рдЬрдмрдХрд┐ рддрддреНрдХрд╛рд▓ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рд╕рдлрд▓ рд╣реЛрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреА рд╣реИред
рд╕рдлрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:
рдЕрдкрдиреЗ рд╕рддреНрдпрд╛рдкрди рдХреЛ рдкрд░рдд рджреЗрдВ: рд╡реНрдпрд╛рдкрдХ API рд╕рддреНрдпрд╛рдкрди рдХреЗ рд╕рд╛рде рддрддреНрдХрд╛рд▓ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдлреЙрд░реНрдореЗрдЯ рдЬрд╛рдВрдЪ рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░реЗрдВред рдкреНрд░рддреНрдпреЗрдХ рдкрд░рдд рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреА рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рдкрдХрдбрд╝рддреА рд╣реИред
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░реЗрдВ: рдЕрддреНрдпрдзрд┐рдХ API рдХреЙрд▓ рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдмрд╛рдЙрдВрд╕рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рд╕реНрдкрд╖реНрдЯ рджреГрд╢реНрдп рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ, рдФрд░ рд╕рддреНрдпрд╛рдкрди рд╕реЗрд╡рд╛ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдХрд╛рд░рдг рдХрднреА рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдмреНрд▓реЙрдХ рди рдХрд░реЗрдВред
рд╡рд┐рдлрд▓рддрд╛рдУрдВ рдХреЛ рд╕реБрдВрджрд░рддрд╛ рд╕реЗ рд╕рдВрднрд╛рд▓реЗрдВ: рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдФрд░ API рдЯрд╛рдЗрдордЖрдЙрдЯ рдлрд╝реЙрд░реНрдо рд╕рдмрдорд┐рд╢рди рдХреЛ рдирд╣реАрдВ рд░реЛрдХрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЬрдм рдЙрдиреНрдирдд рд╕рддреНрдпрд╛рдкрди рдЕрдиреБрдкрд▓рдмреНрдз рд╣реЛ рддреЛ рдмреБрдирд┐рдпрд╛рджреА рд╕рддреНрдпрд╛рдкрди рдкрд░ рд╡рд╛рдкрд╕ рдЖрдПрдВред
рдореЙрдирд┐рдЯрд░ рдХрд░реЗрдВ рдФрд░ рджреЛрд╣рд░рд╛рдПрдВ: рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рддреНрдпрд╛рдкрди рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдХреЛ рдЯреНрд░реИрдХ рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдлрд╝реЙрд░реНрдо рдкреВрд░реНрдгрддрд╛ рдФрд░ рдбреЗрдЯрд╛ рдЧреБрдгрд╡рддреНрддрд╛ рдХреЛ рдХреИрд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЕрдкрдиреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЛ рдкрд░рд┐рд╖реНрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕ рдбреЗрдЯрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдХреА рд░рдХреНрд╖рд╛ рдХрд░реЗрдВ: API рдХреБрдВрдЬрд┐рдпреЛрдВ рдХреА рд░рдХреНрд╖рд╛ рдХреЗ рд▓рд┐рдП рдмреИрдХрдПрдВрдб рдкреНрд░реЙрдХреНрд╕реА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рддреНрдпрд╛рдкрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд░реВрдЯ рдХрд░реЗрдВ, рд░реЗрдЯ рд▓рд┐рдорд┐рдЯрд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ, рдФрд░ рд╕рднреА рдЗрдирдкреБрдЯ рдХреЛ рд╕реИрдирд┐рдЯрд╛рдЗрдЬ рдХрд░реЗрдВред
BillionVerify рдХрд╛ рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди API рдбрд┐рд▓реАрд╡рд░реЗрдмрд┐рд▓рд┐рдЯреА рдЬрд╛рдВрдЪ, рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдИрдореЗрд▓ рдбрд┐рдЯреЗрдХреНрд╢рди рдФрд░ рдЬреЛрдЦрд┐рдо рд╕реНрдХреЛрд░рд┐рдВрдЧ рд╕рд╣рд┐рдд рд╡реНрдпрд╛рдкрдХ рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдВрдЪрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдЧрд╛рдЗрдб рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреИрдЯрд░реНрди рдХреЗ рд╕рд╛рде рд╕рдВрдпреБрдХреНрдд, рдЖрдк рдЙрддреНрдХреГрд╖реНрдЯ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрднрд╡ рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реБрдП рдЙрдЪреНрдЪ-рдЧреБрдгрд╡рддреНрддрд╛ рд╡рд╛рд▓реЗ рдИрдореЗрд▓ рдкрддреЛрдВ рдХреЛ рдХреИрдкреНрдЪрд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдлрд╝реЙрд░реНрдо рдЕрдиреБрднрд╡ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред
рдмреБрдирд┐рдпрд╛рджреА рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рд╕реЗ рд╢реБрд░реВ рдХрд░реЗрдВ, рдлрд┐рд░ рдЕрдкрдиреА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ API-рд╕рдВрдЪрд╛рд▓рд┐рдд рд╕рддреНрдпрд╛рдкрди рдХреЗ рд╕рд╛рде рдкреНрд░рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдмрдврд╝рд╛рдПрдВред рд░рд┐рдпрд▓-рдЯрд╛рдЗрдо рдИрдореЗрд▓ рд╕рддреНрдпрд╛рдкрди рдореЗрдВ рдирд┐рд╡реЗрд╢ рдХрдо рдмрд╛рдЙрдВрд╕ рджрд░реЛрдВ, рдмреЗрд╣рддрд░ рдИрдореЗрд▓ рдбрд┐рд▓реАрд╡рд░реЗрдмрд┐рд▓рд┐рдЯреА рдФрд░ рдЙрдЪреНрдЪ-рдЧреБрдгрд╡рддреНрддрд╛ рд╡рд╛рд▓реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд▓рд╛рднрд╛рдВрд╢ рдХрд╛ рднреБрдЧрддрд╛рди рдХрд░рддрд╛ рд╣реИред