рдЖрдкрдХреЗ рджреНрд╡рд╛рд░рд╛ рднреЗрдЬрд╛ рдЧрдпрд╛ рд╣рд░ рдИрдореЗрд▓ рд╕рд░реНрд╡рд░реЛрдВ рдХреЗ рдПрдХ рд╕рд╛рд╡рдзрд╛рдиреАрдкреВрд░реНрд╡рдХ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдпрд╛рддреНрд░рд╛ рдХрд░рддрд╛ рд╣реИ, рдФрд░ Mail Exchange (MX) рд░рд┐рдХреЙрд░реНрдб рд╡реЗ рд╕рдВрдХреЗрдд рд╣реИрдВ рдЬреЛ рдЗрд╕ рдпрд╛рддреНрд░рд╛ рдХрд╛ рдорд╛рд░реНрдЧрджрд░реНрд╢рди рдХрд░рддреЗ рд╣реИрдВред MX рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдХреИрд╕реЗ рд╡реИрд▓рд┐рдбреЗрдЯ рдХрд░рдирд╛ рд╣реИ, рдпрд╣ рд╕рдордЭрдирд╛ рдХрд┐рд╕реА рднреА рдбреЗрд╡рд▓рдкрд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдореМрд▓рд┐рдХ рдХреМрд╢рд▓ рд╣реИ рдЬреЛ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рд╕рд┐рд╕реНрдЯрдо, рд╕рдВрдкрд░реНрдХ рдлреЙрд░реНрдо рдпрд╛ рдИрдореЗрд▓ рдкрддреЗ рдПрдХрддреНрд░ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рд╡реНрдпрд╛рдкрдХ рдЧрд╛рдЗрдб рдмреБрдирд┐рдпрд╛рджреА рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рд╕реЗ рд▓реЗрдХрд░ рдЙрдиреНрдирдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд░рдгрдиреАрддрд┐рдпреЛрдВ рддрдХ MX рд░рд┐рдХреЙрд░реНрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдХрд╛ рдЕрдиреНрд╡реЗрд╖рдг рдХрд░рддреА рд╣реИ, рдЬреЛ рдЖрдкрдХреЛ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рдиреЛрдВ рдореЗрдВ рдордЬрдмреВрдд рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдХрд╛ рдЬреНрдЮрд╛рди рджреЗрддреА рд╣реИред
MX рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХреЛ рд╕рдордЭрдирд╛
Mail Exchange рд░рд┐рдХреЙрд░реНрдб DNS рд░рд┐рдХреЙрд░реНрдб рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рд╕реА рдбреЛрдореЗрди рдХреА рдУрд░ рд╕реЗ рдИрдореЗрд▓ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреМрди рд╕реЗ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред рдЬрдм рдЖрдк user@example.com рдХреЛ рдИрдореЗрд▓ рднреЗрдЬрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЗ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХреЛ рдпрд╣ рдЬрд╛рдирдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХрд╣рд╛рдБ рдбрд┐рд▓реАрд╡рд░ рдХрд░рдирд╛ рд╣реИред MX рд░рд┐рдХреЙрд░реНрдб рдбреЛрдореЗрди рдХреЗ рдореЗрд▓ рд╕рд░реНрд╡рд░реЛрдВ рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рдХреЗ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред
MX рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ
рдЬрдм рдХреЛрдИ рдИрдореЗрд▓ рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рднреЗрдЬрдиреЗ рд╡рд╛рд▓рд╛ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рдХреЗ рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП MX рд░рд┐рдХреЙрд░реНрдб рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП DNS рд▓реБрдХрдЕрдк рдХрд░рддрд╛ рд╣реИред рдпрд╣ рд▓реБрдХрдЕрдк рдПрдХ рдпрд╛ рдЕрдзрд┐рдХ рдореЗрд▓ рд╕рд░реНрд╡рд░ рд╣реЛрд╕реНрдЯрдиреЗрдо рдХреЗ рд╕рд╛рде рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИ рдЬреЛ рд╡рд░реАрдпрддрд╛ рдХреНрд░рдо рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВред
gmail.com рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рдорд╛рдиреНрдп MX рд░рд┐рдХреЙрд░реНрдб рд▓реБрдХрдЕрдк рдпрд╣ рд▓реМрдЯрд╛ рд╕рдХрддрд╛ рд╣реИ:
gmail.com. MX 5 gmail-smtp-in.l.google.com. gmail.com. MX 10 alt1.gmail-smtp-in.l.google.com. gmail.com. MX 20 alt2.gmail-smtp-in.l.google.com. gmail.com. MX 30 alt3.gmail-smtp-in.l.google.com. gmail.com. MX 40 alt4.gmail-smtp-in.l.google.com.
рднреЗрдЬрдиреЗ рд╡рд╛рд▓рд╛ рд╕рд░реНрд╡рд░ рдкрд╣рд▓реЗ рд╕рдмрд╕реЗ рдХрдо рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкреНрд░рд╛рдердорд┐рдХрддрд╛ 5) рдкрд░ рдбрд┐рд▓реАрд╡рд░реА рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рд╡рд╣ рд╕рд░реНрд╡рд░ рдЕрдиреБрдкрд▓рдмреНрдз рд╣реИ, рддреЛ рдпрд╣ рдЕрдЧрд▓реЗ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╕реНрддрд░ рдХреЛ рдЖрдЬрдорд╛рддрд╛ рд╣реИ, рдФрд░ рдЗрд╕реА рддрд░рд╣ред рдпрд╣ рдЕрддрд┐рд░реЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд╕рд░реНрд╡рд░ рдбрд╛рдЙрди рд╣реЛрдиреЗ рдкрд░ рднреА рдИрдореЗрд▓ рдбрд┐рд▓реАрд╡рд░реА рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред
MX рд░рд┐рдХреЙрд░реНрдб рдШрдЯрдХ
рдкреНрд░рддреНрдпреЗрдХ MX рд░рд┐рдХреЙрд░реНрдб рдореЗрдВ рджреЛ рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░рд┐рдпрд╛рдВ рд╣реЛрддреА рд╣реИрдВ:
рдкреНрд░рд╛рдердорд┐рдХрддрд╛ (рд╡рд░реАрдпрддрд╛)
рдПрдХ рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рдорд╛рди рдЬреЛ рдХреНрд░рдо рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдореЗрд▓ рд╕рд░реНрд╡рд░реЛрдВ рдХреЛ рдЖрдЬрдорд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдХрдо рд╕рдВрдЦреНрдпрд╛ рдЙрдЪреНрдЪ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддреА рд╣реИред рд╕рдорд╛рди рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдХреНрд░рдо рдореЗрдВ рдЖрдЬрдорд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ, рдЬреЛ рд▓реЛрдб рдмреИрд▓реЗрдВрд╕рд┐рдВрдЧ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рдореЗрд▓ рд╕рд░реНрд╡рд░ рд╣реЛрд╕реНрдЯрдиреЗрдо
рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХрд╛ рдкреВрд░реНрдг рдпреЛрдЧреНрдп рдбреЛрдореЗрди рдирд╛рдо (FQDN) рдЬреЛ рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП рдИрдореЗрд▓ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред рдЗрд╕ рд╣реЛрд╕реНрдЯрдиреЗрдо рдХреЛ A рдпрд╛ AAAA рд░рд┐рдХреЙрд░реНрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ IP рдкрддреЗ рдореЗрдВ рд░рд┐рдЬрд╝реЙрд▓реНрд╡ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
MX рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдХреНрдпреЛрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИрдВ
MX рд░рд┐рдХреЙрд░реНрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЪреЗрдХрдкреЙрдЗрдВрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ:
рдбреЛрдореЗрди рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдкреБрд╖реНрдЯрд┐
рдпрджрд┐ рдХрд┐рд╕реА рдбреЛрдореЗрди рдореЗрдВ рдХреЛрдИ MX рд░рд┐рдХреЙрд░реНрдб рдирд╣реАрдВ рд╣реИ, рддреЛ рдпрд╣ рдЖрдорддреМрд░ рдкрд░ рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдХреБрдЫ рдбреЛрдореЗрди рдореЗрдВ A рд░рд┐рдХреЙрд░реНрдб рдлреЙрд▓рдмреИрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди MX рд░рд┐рдХреЙрд░реНрдб рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдЕрдХреНрд╕рд░ рдПрдХ рдордЬрдмреВрдд рд╕рдВрдХреЗрддрдХ рд╣реЛрддреА рд╣реИ рдХрд┐ рдбреЛрдореЗрди рдИрдореЗрд▓ рдХреЗ рд▓рд┐рдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдирд╣реАрдВ рд╣реИред
рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░ рд╕рддреНрдпрд╛рдкрди
рд╡реИрдз MX рд░рд┐рдХреЙрд░реНрдб рдЬреЛ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдореЗрд▓ рд╕рд░реНрд╡рд░реЛрдВ рдореЗрдВ рд░рд┐рдЬрд╝реЙрд▓реНрд╡ рд╣реЛрддреЗ рд╣реИрдВ, рдпрд╣ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ рдХрд┐ рдбреЛрдореЗрди рдореЗрдВ рдИрдореЗрд▓ рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░ рд╣реИред рдпрд╣ рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрддреЗ рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкреБрд╖реНрдЯрд┐ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдбреЛрдореЗрди рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред
рд╕реНрдкреИрдо рдФрд░ рдзреЛрдЦрд╛рдзрдбрд╝реА рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛
рд╡реИрдз рд╡реНрдпрд╡рд╕рд╛рдп рдЙрдЪрд┐рдд MX рд░рд┐рдХреЙрд░реНрдб рдмрдирд╛рдП рд░рдЦрддреЗ рд╣реИрдВред рд╕реНрдкреИрдо рдпрд╛ рдзреЛрдЦрд╛рдзрдбрд╝реА рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╕рдВрджрд┐рдЧреНрдз рдбреЛрдореЗрди рдореЗрдВ рдЕрдХреНрд╕рд░ рдЧрд▓рдд рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдП рдЧрдП рдпрд╛ рдЧрд╛рдпрдм MX рд░рд┐рдХреЙрд░реНрдб рд╣реЛрддреЗ рд╣реИрдВред
рдкреНрд░рджрд░реНрд╢рди рдЕрдиреБрдХреВрд▓рди
SMTP рд╕рддреНрдпрд╛рдкрди рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ MX рд░рд┐рдХреЙрд░реНрдб рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рд╕реЗ рдЙрди рдбреЛрдореЗрди рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдореЗрдВ рдмрд░реНрдмрд╛рдж рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рд╕рдордп рд╕реЗ рдмрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
MX рд░рд┐рдХреЙрд░реНрдб рд▓реБрдХрдЕрдк рд▓рд╛рдЧреВ рдХрд░рдирд╛
рдЖрдЗрдП рд╡рд┐рднрд┐рдиреНрди рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд╡рд╛рддрд╛рд╡рд░рдгреЛрдВ рдореЗрдВ MX рд░рд┐рдХреЙрд░реНрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХрд╛ рдЕрдиреНрд╡реЗрд╖рдг рдХрд░реЗрдВред
Node.js рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
Node.js dns рдореЙрдбреНрдпреВрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд DNS рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
const dns = require('dns').promises;
async function getMxRecords(domain) {
try {
const records = await dns.resolveMx(domain);
// Sort by priority (lowest first)
records.sort((a, b) => a.priority - b.priority);
return {
success: true,
domain,
records: records.map(r => ({
exchange: r.exchange,
priority: r.priority
}))
};
} catch (error) {
return {
success: false,
domain,
error: error.code,
message: getMxErrorMessage(error.code)
};
}
}
function getMxErrorMessage(code) {
const messages = {
'ENODATA': 'No MX records found for this domain',
'ENOTFOUND': 'Domain does not exist',
'ETIMEOUT': 'DNS lookup timed out',
'ESERVFAIL': 'DNS server failed to respond'
};
return messages[code] || 'Unknown DNS error';
}
// Usage
const result = await getMxRecords('gmail.com');
console.log(result);
Python рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
Python рдХрд╛ dnspython рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ dns.resolver рдореЙрдбреНрдпреВрд▓ рд╡реНрдпрд╛рдкрдХ DNS рд▓реБрдХрдЕрдк рдХреНрд╖рдорддрд╛рдПрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
import dns.resolver
import dns.exception
def get_mx_records(domain):
try:
answers = dns.resolver.resolve(domain, 'MX')
records = []
for rdata in answers:
records.append({
'exchange': str(rdata.exchange).rstrip('.'),
'priority': rdata.preference
})
# Sort by priority
records.sort(key=lambda x: x['priority'])
return {
'success': True,
'domain': domain,
'records': records
}
except dns.resolver.NXDOMAIN:
return {
'success': False,
'domain': domain,
'error': 'NXDOMAIN',
'message': 'Domain does not exist'
}
except dns.resolver.NoAnswer:
return {
'success': False,
'domain': domain,
'error': 'NoAnswer',
'message': 'No MX records found for this domain'
}
except dns.exception.Timeout:
return {
'success': False,
'domain': domain,
'error': 'Timeout',
'message': 'DNS lookup timed out'
}
# Usage
result = get_mx_records('gmail.com')
print(result)
Go рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
Go рдХрд╛ net рдкреИрдХреЗрдЬ рд╕реАрдзреЗ DNS рд▓реБрдХрдЕрдк рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
package main
import (
"fmt"
"net"
"sort"
)
type MxResult struct {
Success bool
Domain string
Records []MxRecord
Error string
}
type MxRecord struct {
Exchange string
Priority uint16
}
func getMxRecords(domain string) MxResult {
records, err := net.LookupMX(domain)
if err != nil {
return MxResult{
Success: false,
Domain: domain,
Error: err.Error(),
}
}
if len(records) == 0 {
return MxResult{
Success: false,
Domain: domain,
Error: "No MX records found",
}
}
// Sort by priority
sort.Slice(records, func(i, j int) bool {
return records[i].Pref < records[j].Pref
})
result := MxResult{
Success: true,
Domain: domain,
Records: make([]MxRecord, len(records)),
}
for i, r := range records {
result.Records[i] = MxRecord{
Exchange: r.Host,
Priority: r.Pref,
}
}
return result
}
func main() {
result := getMxRecords("gmail.com")
fmt.Printf("%+v\n", result)
}
рдЙрдиреНрдирдд MX рд╡реИрд▓рд┐рдбреЗрд╢рди рддрдХрдиреАрдХреЗрдВ
рдореВрд▓ MX рд▓реБрдХрдЕрдк рдкреБрд╖реНрдЯрд┐ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд░рд┐рдХреЙрд░реНрдб рдореМрдЬреВрдж рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡реНрдпрд╛рдкрдХ рдИрдореЗрд▓ рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЗ рд▓рд┐рдП рдЧрд╣рд░реЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХрдиреЗрдХреНрдЯрд┐рд╡рд┐рдЯреА рдХреЛ рд╡реИрд▓рд┐рдбреЗрдЯ рдХрд░рдирд╛
MX рд░рд┐рдХреЙрд░реНрдб рд╣реЛрд╕реНрдЯрдиреЗрдо рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ IP рдкрддреЛрдВ рдореЗрдВ рд░рд┐рдЬрд╝реЙрд▓реНрд╡ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдореЗрд▓ рд╕рд░реНрд╡рд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкрд╣реБрдВрдЪ рдпреЛрдЧреНрдп рд╣реИрдВ:
const dns = require('dns').promises;
const net = require('net');
async function validateMxConnectivity(domain) {
// Get MX records
const mxResult = await getMxRecords(domain);
if (!mxResult.success) {
return mxResult;
}
// Validate each mail server
const validatedRecords = [];
for (const record of mxResult.records) {
const validation = await validateMailServer(record.exchange);
validatedRecords.push({
...record,
...validation
});
}
return {
success: true,
domain,
records: validatedRecords,
hasReachableServer: validatedRecords.some(r => r.reachable)
};
}
async function validateMailServer(hostname) {
try {
// Resolve hostname to IP
const addresses = await dns.resolve4(hostname);
if (addresses.length === 0) {
return { reachable: false, error: 'No A record' };
}
// Test connection to port 25
const connected = await testConnection(addresses[0], 25);
return {
reachable: connected,
ip: addresses[0],
error: connected ? null : 'Connection refused'
};
} catch (error) {
return {
reachable: false,
error: error.message
};
}
}
function testConnection(host, port, timeout = 5000) {
return new Promise((resolve) => {
const socket = new net.Socket();
socket.setTimeout(timeout);
socket.on('connect', () => {
socket.destroy();
resolve(true);
});
socket.on('timeout', () => {
socket.destroy();
resolve(false);
});
socket.on('error', () => {
resolve(false);
});
socket.connect(port, host);
});
}
A рд░рд┐рдХреЙрд░реНрдб рдлреЙрд▓рдмреИрдХ рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛
рдЬрдм рдХреЛрдИ MX рд░рд┐рдХреЙрд░реНрдб рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдИрдореЗрд▓ рдорд╛рдирдХ (RFC 5321) рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдбреЛрдореЗрди рдХреЗ A рд░рд┐рдХреЙрд░реНрдб рдХреЛ рдлреЙрд▓рдмреИрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЕрдкрдиреА рд╡реИрд▓рд┐рдбреЗрд╢рди рдореЗрдВ рдЗрд╕ рдлреЙрд▓рдмреИрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
async function getMailServers(domain) {
// Try MX records first
try {
const mxRecords = await dns.resolveMx(domain);
if (mxRecords.length > 0) {
return {
type: 'MX',
servers: mxRecords.sort((a, b) => a.priority - b.priority)
};
}
} catch (error) {
if (error.code !== 'ENODATA') {
throw error;
}
}
// Fallback to A record
try {
const aRecords = await dns.resolve4(domain);
if (aRecords.length > 0) {
return {
type: 'A_FALLBACK',
servers: [{ exchange: domain, priority: 0 }],
warning: 'Using A record fallback - no MX records found'
};
}
} catch (error) {
if (error.code !== 'ENODATA') {
throw error;
}
}
return {
type: 'NONE',
servers: [],
error: 'No mail servers found for domain'
};
}
Null MX рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛
RFC 7505 "null MX" рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ рдХрд┐ рдПрдХ рдбреЛрдореЗрди рдИрдореЗрд▓ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЗрди рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдореЗрдВ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ 0 рдФрд░ рдПрдХ рдЦрд╛рд▓реА рд╣реЛрд╕реНрдЯрдиреЗрдо (".") рдХреЗ рд╕рд╛рде рдПрдХ рдПрдХрд▓ MX рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рд╣реЛрддреА рд╣реИ:
function hasNullMx(mxRecords) {
if (mxRecords.length === 1) {
const record = mxRecords[0];
if (record.priority === 0 &&
(record.exchange === '.' || record.exchange === '')) {
return true;
}
}
return false;
}
async function validateDomainMx(domain) {
const mxResult = await getMxRecords(domain);
if (!mxResult.success) {
return mxResult;
}
if (hasNullMx(mxResult.records)) {
return {
success: false,
domain,
error: 'NULL_MX',
message: 'Domain explicitly does not accept email'
};
}
return mxResult;
}
MX рд▓реБрдХрдЕрдк рдХреЛ рдХреИрд╢рд┐рдВрдЧ рдХрд░рдирд╛
DNS рд▓реБрдХрдЕрдк рд╣рд░ рд╕рддреНрдпрд╛рдкрди рдореЗрдВ рд╡рд┐рд▓рдВрдмрддрд╛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреИрд╢рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
class MxCache {
constructor(ttlMs = 3600000) { // 1 hour default TTL
this.cache = new Map();
this.ttl = ttlMs;
}
get(domain) {
const entry = this.cache.get(domain.toLowerCase());
if (!entry) return null;
if (Date.now() > entry.expiry) {
this.cache.delete(domain.toLowerCase());
return null;
}
return entry.data;
}
set(domain, data) {
this.cache.set(domain.toLowerCase(), {
data,
expiry: Date.now() + this.ttl
});
}
// Respect DNS TTL values when available
setWithTtl(domain, data, ttlSeconds) {
const ttlMs = Math.min(ttlSeconds * 1000, this.ttl);
this.cache.set(domain.toLowerCase(), {
data,
expiry: Date.now() + ttlMs
});
}
}
const mxCache = new MxCache();
async function getMxRecordsCached(domain) {
const cached = mxCache.get(domain);
if (cached) {
return { ...cached, fromCache: true };
}
const result = await getMxRecords(domain);
if (result.success) {
mxCache.set(domain, result);
}
return { ...result, fromCache: false };
}
рд╕рд╛рдорд╛рдиреНрдп MX рд░рд┐рдХреЙрд░реНрдб рдкреИрдЯрд░реНрди
рд╕рд╛рдорд╛рдиреНрдп MX рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рд╕рдордЭрдирд╛ рдЖрдкрдХреЛ рд╡реИрд▓рд┐рдбреЗрд╢рди рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рдиреЗ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред
рдкреНрд░рдореБрдЦ рдИрдореЗрд▓ рдкреНрд░рджрд╛рддрд╛
рдкреНрд░рдореБрдЦ рдкреНрд░рджрд╛рддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП MX рдкреИрдЯрд░реНрди рдХреЛ рдкрд╣рдЪрд╛рдирдиреЗ рд╕реЗ рдореБрдлреНрдд рдИрдореЗрд▓ рдкрддреЛрдВ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдорд┐рд▓ рд╕рдХрддреА рд╣реИ:
const knownProviders = {
'google': [
'gmail-smtp-in.l.google.com',
'googlemail-smtp-in.l.google.com',
'aspmx.l.google.com'
],
'microsoft': [
'outlook-com.olc.protection.outlook.com',
'mail.protection.outlook.com'
],
'yahoo': [
'mta5.am0.yahoodns.net',
'mta6.am0.yahoodns.net',
'mta7.am0.yahoodns.net'
],
'protonmail': [
'mail.protonmail.ch',
'mailsec.protonmail.ch'
]
};
function identifyEmailProvider(mxRecords) {
const exchanges = mxRecords.map(r => r.exchange.toLowerCase());
for (const [provider, patterns] of Object.entries(knownProviders)) {
for (const pattern of patterns) {
if (exchanges.some(ex => ex.includes(pattern.toLowerCase()))) {
return provider;
}
}
}
return 'unknown';
}
Google Workspace рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛
Google Workspace (рдкреВрд░реНрд╡ рдореЗрдВ G Suite) рдбреЛрдореЗрди Google рдХреЗ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рд▓реЗрдХрд┐рди рдореБрдлреНрдд рдИрдореЗрд▓ рдЦрд╛рддреЗ рдирд╣реАрдВ рд╣реИрдВ:
function isGoogleWorkspace(domain, mxRecords) {
const isGoogleMx = mxRecords.some(r =>
r.exchange.toLowerCase().includes('google') ||
r.exchange.toLowerCase().includes('googlemail')
);
// Check if domain is not a known Google consumer domain
const googleConsumerDomains = ['gmail.com', 'googlemail.com'];
const isConsumerDomain = googleConsumerDomains.includes(domain.toLowerCase());
return isGoogleMx && !isConsumerDomain;
}
рд╕реНрд╡-рд╣реЛрд╕реНрдЯреЗрдб рдИрдореЗрд▓ рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдирд╛
рдЬреЛ рдбреЛрдореЗрди рдЕрдкрдиреА рдИрдореЗрд▓ рд╣реЛрд╕реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдЙрдирдореЗрдВ рдЕрдХреНрд╕рд░ рд╕рдмрдбреЛрдореЗрди рдХреА рдУрд░ рдЗрд╢рд╛рд░рд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ MX рд░рд┐рдХреЙрд░реНрдб рд╣реЛрддреЗ рд╣реИрдВ:
function isSelfHosted(domain, mxRecords) {
const domainParts = domain.toLowerCase().split('.');
const baseDomain = domainParts.slice(-2).join('.');
return mxRecords.some(r => {
const exchange = r.exchange.toLowerCase();
return exchange.includes(baseDomain) &&
!isKnownProvider(exchange);
});
}
function isKnownProvider(exchange) {
const providers = ['google', 'microsoft', 'yahoo', 'outlook', 'protonmail'];
return providers.some(p => exchange.includes(p));
}
рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдкрд╛рдЗрдкрд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ MX рд╡реИрд▓рд┐рдбреЗрд╢рди
MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдПрдХ рд╡реНрдпрд╛рдкрдХ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ рдХрджрдо рд╣реИред рдЗрд╕рдХреА рднреВрдорд┐рдХрд╛ рдХреЛ рд╕рдордЭрдирд╛ рдкреНрд░рднрд╛рд╡реА рд╕рддреНрдпрд╛рдкрди рдкрд╛рдЗрдкрд▓рд╛рдЗрдиреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред
рд╕рддреНрдпрд╛рдкрди рдХреНрд░рдо
MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдЖрдорддреМрд░ рдкрд░ рд╕рддреНрдпрд╛рдкрди рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдЬрд▓реНрджреА рд╣реЛрддрд╛ рд╣реИ:
async function verifyEmail(email) {
// 1. Syntax validation (fastest, no network)
const syntaxResult = validateEmailSyntax(email);
if (!syntaxResult.valid) {
return { valid: false, reason: 'invalid_syntax', details: syntaxResult };
}
const domain = email.split('@')[1];
// 2. MX record validation (fast DNS lookup)
const mxResult = await validateMxRecords(domain);
if (!mxResult.valid) {
return { valid: false, reason: 'no_mx_records', details: mxResult };
}
// 3. Additional checks (disposable, role-based, etc.)
const domainCheck = await checkDomainReputation(domain);
if (domainCheck.isDisposable) {
return { valid: true, risky: true, reason: 'disposable_domain' };
}
// 4. SMTP verification (slowest, most thorough)
const smtpResult = await verifySmtp(email, mxResult.records);
return {
valid: smtpResult.exists,
deliverable: smtpResult.deliverable,
mxRecords: mxResult.records,
provider: mxResult.provider
};
}
рд╕рдорд╛рдирд╛рдВрддрд░ MX рд▓реБрдХрдЕрдк
рдХрдИ рдИрдореЗрд▓ рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рддреЗ рд╕рдордп, рд╡рд┐рднрд┐рдиреНрди рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП MX рд▓реБрдХрдЕрдк рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░реЗрдВ:
async function verifyEmailsBatch(emails) {
// Group emails by domain
const emailsByDomain = {};
for (const email of emails) {
const domain = email.split('@')[1];
if (!emailsByDomain[domain]) {
emailsByDomain[domain] = [];
}
emailsByDomain[domain].push(email);
}
// Lookup MX records for all domains in parallel
const domains = Object.keys(emailsByDomain);
const mxResults = await Promise.all(
domains.map(domain => getMxRecordsCached(domain))
);
// Map results back to domains
const mxByDomain = {};
domains.forEach((domain, index) => {
mxByDomain[domain] = mxResults[index];
});
// Process emails with MX data
const results = [];
for (const email of emails) {
const domain = email.split('@')[1];
const mx = mxByDomain[domain];
if (!mx.success) {
results.push({ email, valid: false, reason: 'invalid_domain' });
continue;
}
// Continue with SMTP verification using cached MX data
const smtpResult = await verifySmtp(email, mx.records);
results.push({ email, ...smtpResult });
}
return results;
}
рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдФрд░ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ
рдордЬрдмреВрдд MX рд╡реИрд▓рд┐рдбреЗрд╢рди рд╡рд┐рднрд┐рдиреНрди рддреНрд░реБрдЯрд┐ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЛ рд╕реБрдЪрд╛рд░реВ рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред
DNS рдЯрд╛рдЗрдордЖрдЙрдЯ рд╣реИрдВрдбрд▓рд┐рдВрдЧ
рдиреЗрдЯрд╡рд░реНрдХ рд╕рдорд╕реНрдпрд╛рдПрдВ DNS рд▓реБрдХрдЕрдк рдХреЛ рд▓рдЯрдХрд╛ рд╕рдХрддреА рд╣реИрдВред рдЯрд╛рдЗрдордЖрдЙрдЯ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
async function getMxRecordsWithTimeout(domain, timeoutMs = 10000) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('DNS_TIMEOUT')), timeoutMs);
});
try {
const result = await Promise.race([
getMxRecords(domain),
timeoutPromise
]);
return result;
} catch (error) {
if (error.message === 'DNS_TIMEOUT') {
return {
success: false,
domain,
error: 'TIMEOUT',
message: 'DNS lookup timed out',
retryable: true
};
}
throw error;
}
}
рдЕрдорд╛рдиреНрдп рдбреЛрдореЗрди рд╣реИрдВрдбрд▓рд┐рдВрдЧ
DNS рд▓реБрдХрдЕрдк рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЙрди рдбреЛрдореЗрди рдХреЛ рд╕рдВрднрд╛рд▓реЗрдВ рдЬреЛ рд╡рд╛рдХреНрдпрд╛рддреНрдордХ рд░реВрдк рд╕реЗ рдЕрдорд╛рдиреНрдп рд╣реИрдВ:
function isValidDomain(domain) {
if (!domain || typeof domain !== 'string') {
return false;
}
// Check length
if (domain.length > 253) {
return false;
}
// Check for valid characters and structure
const domainRegex = /^(?!-)[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
if (!domainRegex.test(domain)) {
return false;
}
// Check each label length
const labels = domain.split('.');
for (const label of labels) {
if (label.length > 63) {
return false;
}
}
return true;
}
async function validateDomainMxSafe(domain) {
if (!isValidDomain(domain)) {
return {
success: false,
domain,
error: 'INVALID_DOMAIN',
message: 'Domain format is invalid'
};
}
return await getMxRecordsWithTimeout(domain);
}
рдЕрд╕реНрдерд╛рдпреА DNS рд╡рд┐рдлрд▓рддрд╛рдУрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛
DNS рд╡рд┐рдлрд▓рддрд╛рдПрдВ рдЕрд╕реНрдерд╛рдпреА рд╣реЛ рд╕рдХрддреА рд╣реИрдВред рдШрд╛рддреАрдп рдмреИрдХрдСрдл рдХреЗ рд╕рд╛рде рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рддрд░реНрдХ рд▓рд╛рдЧреВ рдХрд░реЗрдВ:
async function getMxRecordsWithRetry(domain, maxRetries = 3) {
const delays = [1000, 2000, 4000];
for (let attempt = 0; attempt < maxRetries; attempt++) {
const result = await getMxRecordsWithTimeout(domain);
// Don't retry for definitive failures
if (result.success ||
result.error === 'NXDOMAIN' ||
result.error === 'ENOTFOUND') {
return result;
}
// Retry for temporary failures
if (result.retryable && attempt < maxRetries - 1) {
await sleep(delays[attempt]);
continue;
}
return result;
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
рд╕реБрд░рдХреНрд╖рд╛ рд╡рд┐рдЪрд╛рд░
MX рд╡реИрд▓рд┐рдбреЗрд╢рди рд╕реБрд░рдХреНрд╖рд╛ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЛ рдкреЗрд╢ рдХрд░рддреА рд╣реИ рдЬрд┐рдиреНрд╣реЗрдВ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рд╕рдВрдмреЛрдзрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
DNS рд╕реНрдкреВрдлрд┐рдВрдЧ рд░реЛрдХрдерд╛рдо
рдорд╛рдирдХ DNS рдХреНрд╡реЗрд░реА рдПрдиреНрдХреНрд░рд┐рдкреНрдЯ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИрдВ рдФрд░ рд╕реНрдкреВрдлрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЕрд╕реБрд░рдХреНрд╖рд┐рдд рд╣реИрдВред рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП DNS over HTTPS (DoH) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:
const https = require('https');
async function getMxRecordsDoH(domain) {
const url = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(domain)}&type=MX`;
return new Promise((resolve, reject) => {
https.get(url, {
headers: { 'Accept': 'application/dns-json' }
}, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const response = JSON.parse(data);
if (response.Status !== 0) {
resolve({
success: false,
domain,
error: 'DNS_ERROR',
status: response.Status
});
return;
}
const records = (response.Answer || [])
.filter(a => a.type === 15)
.map(a => {
const [priority, exchange] = a.data.split(' ');
return {
priority: parseInt(priority),
exchange: exchange.replace(/\.$/, '')
};
})
.sort((a, b) => a.priority - b.priority);
resolve({
success: records.length > 0,
domain,
records
});
} catch (error) {
reject(error);
}
});
}).on('error', reject);
});
}
DNS рдХреНрд╡реЗрд░реА рдХреЛ рджрд░ рд╕реАрдорд┐рдд рдХрд░рдирд╛
DNS рдХреНрд╡реЗрд░реА рдХреА рджрд░ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдХреЗ рджреБрд░реБрдкрдпреЛрдЧ рдХреЛ рд░реЛрдХреЗрдВ:
class DnsRateLimiter {
constructor(maxQueriesPerSecond = 100) {
this.tokens = maxQueriesPerSecond;
this.maxTokens = maxQueriesPerSecond;
this.lastRefill = Date.now();
}
async acquire() {
this.refillTokens();
if (this.tokens > 0) {
this.tokens--;
return true;
}
// Wait for token availability
await sleep(1000 / this.maxTokens);
return this.acquire();
}
refillTokens() {
const now = Date.now();
const elapsed = now - this.lastRefill;
const tokensToAdd = (elapsed / 1000) * this.maxTokens;
this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
this.lastRefill = now;
}
}
const dnsLimiter = new DnsRateLimiter(50);
async function getMxRecordsRateLimited(domain) {
await dnsLimiter.acquire();
return getMxRecords(domain);
}
MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЗ рд▓рд┐рдП BillionVerify рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
рдЬрдмрдХрд┐ MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рд╕реНрд╡рдпрдВ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╢реИрдХреНрд╖рд┐рдХ рдореВрд▓реНрдп рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, BillionVerify рдЬреИрд╕реА рдкреЗрд╢реЗрд╡рд░ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рд╕реЗрд╡рд╛рдПрдВ рд╡реНрдпрд╛рдкрдХ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рд╕рдВрднрд╛рд▓рддреА рд╣реИрдВред
рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди API рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдлрд╛рдпрджреЗ
рд╡реНрдпрд╛рдкрдХ рдЬрд╛рдВрдЪ
BillionVerify рдХрд╛ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди API рдПрдХ рд╣реА API рдХреЙрд▓ рдореЗрдВ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдЬрд╛рдВрдЪ, SMTP рд╕рддреНрдпрд╛рдкрди, рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдИрдореЗрд▓ рдкрд╣рдЪрд╛рди рдФрд░ рдмрд╣реБрдд рдХреБрдЫ рдХреЗ рд╕рд╛рде MX рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЛ рдЬреЛрдбрд╝рддрд╛ рд╣реИред рдпрд╣ рдХрдИ рд╕рддреНрдпрд╛рдкрди рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЛ рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред
рдЕрдиреБрдХреВрд▓рд┐рдд рдЗрдиреНрдлреНрд░рд╛рд╕реНрдЯреНрд░рдХреНрдЪрд░
рдкреЗрд╢реЗрд╡рд░ рд╕реЗрд╡рд╛рдПрдВ рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░ рд╡рд┐рддрд░рд┐рдд DNS рд░рд┐рдЬрд╝реЙрд▓реНрд╡рд░ рдмрдирд╛рдП рд░рдЦрддреА рд╣реИрдВ, рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдХреИрд╢рд┐рдВрдЧ рдХреЛ рд╕рдВрднрд╛рд▓рддреА рд╣реИрдВ, рдФрд░ рд▓рд╛рдЦреЛрдВ рд╕рддреНрдпрд╛рдкрдиреЛрдВ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рддреА рд╣реИрдВред
рдирд┐рд░рдВрддрд░ рдЕрдкрдбреЗрдЯ
рдореЗрд▓ рд╕рд░реНрд╡рд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд▓рдЧрд╛рддрд╛рд░ рдмрджрд▓рддреЗ рд░рд╣рддреЗ рд╣реИрдВред рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рд╕реЗрд╡рд╛рдПрдВ рдЬреНрдЮрд╛рдд рдкреНрд░рджрд╛рддрд╛рдУрдВ, рдбрд┐рд╕реНрдкреЛрдЬреЗрдмрд▓ рдбреЛрдореЗрди рдФрд░ рдореЗрд▓ рд╕рд░реНрд╡рд░ рдкреИрдЯрд░реНрди рдХреЗ рдЕрдкрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд▓рдЧрд╛рддрд╛рд░ рдЕрдкрдбреЗрдЯ рдХрд░рддреА рд╣реИрдВред
API рдПрдХреАрдХрд░рдг рдЙрджрд╛рд╣рд░рдг
async function verifyEmailWithBillionVerify(email) {
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();
// MX information is included in the response
console.log('MX Valid:', result.mx_found);
console.log('Domain Valid:', result.domain_valid);
console.log('Is Deliverable:', result.is_deliverable);
return result;
}
рдирд┐рд╖реНрдХрд░реНрд╖
MX рд░рд┐рдХреЙрд░реНрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдореВрд▓рднреВрдд рдШрдЯрдХ рд╣реИ рдЬреЛ рдЕрдзрд┐рдХ рд╕рдВрд╕рд╛рдзрди-рдЧрд╣рди рдЬрд╛рдВрдЪ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдкреБрд╖реНрдЯрд┐ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдПрдХ рдбреЛрдореЗрди рдИрдореЗрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЙрдЪрд┐рдд MX рд╡реИрд▓рд┐рдбреЗрд╢рди рд▓рд╛рдЧреВ рдХрд░рдХреЗ, рдЖрдк рдЬрд▓реНрджреА рд╕реЗ рдЕрдорд╛рдиреНрдп рдбреЛрдореЗрди рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рддреНрдпрд╛рдкрди рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рдИрдореЗрд▓-рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред
MX рд░рд┐рдХреЙрд░реНрдб рд╡реИрд▓рд┐рдбреЗрд╢рди рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдирд┐рд╖реНрдХрд░реНрд╖:
- рд╣рдореЗрд╢рд╛ MX рд░рд┐рдХреЙрд░реНрдбреНрд╕ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВ SMTP рд╕рддреНрдпрд╛рдкрди рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕рдордп рдФрд░ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП
- A рд░рд┐рдХреЙрд░реНрдб рдлреЙрд▓рдмреИрдХ рдХреЛ рд╕рдВрднрд╛рд▓реЗрдВ рдмрд┐рдирд╛ MX рд░рд┐рдХреЙрд░реНрдб рд╡рд╛рд▓реЗ рдбреЛрдореЗрди рдХреЗ рд▓рд┐рдП RFC рдорд╛рдирдХреЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░
- рдХреИрд╢рд┐рдВрдЧ рд▓рд╛рдЧреВ рдХрд░реЗрдВ рдмрд╛рд░-рдмрд╛рд░ рд╕рддреНрдпрд╛рдкрдиреЛрдВ рдХреЗ рд▓рд┐рдП DNS рд▓реБрдХрдЕрдк рдУрд╡рд░рд╣реЗрдб рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
- рд╕рд╛рдорд╛рдиреНрдп рдкреИрдЯрд░реНрди рдХреЛ рдкрд╣рдЪрд╛рдиреЗрдВ рдИрдореЗрд▓ рдкреНрд░рджрд╛рддрд╛рдУрдВ рдФрд░ рд╕рдВрднрд╛рд╡рд┐рдд рдЬреЛрдЦрд┐рдореЛрдВ рдХреА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП
- рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рд╕реБрдЪрд╛рд░реВ рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓реЗрдВ рдЯрд╛рдЗрдордЖрдЙрдЯ, рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдФрд░ рдЙрдЪрд┐рдд рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде
рдЪрд╛рд╣реЗ рдЖрдк рдПрдХ рдХрд╕реНрдЯрдо рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рд╕рд┐рд╕реНрдЯрдо рдмрдирд╛ рд░рд╣реЗ рд╣реЛрдВ рдпрд╛ BillionVerify рдЬреИрд╕реА рд╕реЗрд╡рд╛ рдХреЗ рд╕рд╛рде рдПрдХреАрдХреГрдд рдХрд░ рд░рд╣реЗ рд╣реЛрдВ, MX рд░рд┐рдХреЙрд░реНрдб рдХреЛ рд╕рдордЭрдирд╛ рдЖрдкрдХреЛ рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рдиреЛрдВ рдореЗрдВ рдмреЗрд╣рддрд░ рдИрдореЗрд▓ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдмрдирд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред рдЖрдЬ рд╣реА MX рд╡реИрд▓рд┐рдбреЗрд╢рди рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ рдФрд░ рд╡реНрдпрд╛рдкрдХ рдИрдореЗрд▓ рд╡реЗрд░рд┐рдлрд┐рдХреЗрд╢рди рдХреА рдУрд░ рдкрд╣рд▓рд╛ рдХрджрдо рдЙрдард╛рдПрдВред