๊ฐ๋ฐ์์ ๋ง์ผํฐ๊ฐ ๊ฐ์ฅ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ ์ค ํ๋๋ "์ค์ ๋ก ์ด๋ฉ์ผ์ ๋ณด๋ด์ง ์๊ณ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ธ๊ฐ์?"์ ๋๋ค. ์ด๋ ํ๋นํ ์ง๋ฌธ์ ๋๋ค. ์ ์ฌ์ ์ผ๋ก ์ ํจํ์ง ์์ ์ฃผ์๋ก ๊ฒ์ฆ ์ด๋ฉ์ผ์ ๋ณด๋ด๋ ๊ฒ์ ๋ฐ์ ์ ํํ์ ์์์ํค๊ณ ๋ฆฌ์์ค๋ฅผ ๋ญ๋นํ๋ฉฐ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ํ์ํฌ ์ ์์ต๋๋ค. ๋คํํ๋ ์ค์ ์ด๋ฉ์ผ ์ ๋ฌ์ ํธ๋ฆฌ๊ฑฐํ์ง ์๊ณ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ ์ ์๋ ์ฌ๋ฌ ๊ฒ์ฆ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋์์๋ ๊ฐ๋จํ ๊ตฌ๋ฌธ ๊ฒ์ฆ๋ถํฐ ์ ๊ตํ SMTP ํธ๋์ ฐ์ดํฌ ๊ธฐ์ ๊น์ง, ์ด๋ฉ์ผ์ ์ ์กํ์ง ์๊ณ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ๋ 5๊ฐ์ง ์ ๊ทผ ๋ฐฉ์์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๊ฐ์ ์์์ ๊ตฌ์ถํ๋ ๊ฐ๋ฐ์๋ ์ด๋ฉ์ผ ๋ชฉ๋ก์ ์ ๋ฆฌํ๋ ๋ง์ผํฐ๋ , ๊ธฐ์ ์ ์๊ตฌ ์ฌํญ๊ณผ ์ ํ๋ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๋ ์ค์ฉ์ ์ธ ์๋ฃจ์ ์ ์ฐพ์ ์ ์์ต๋๋ค.
์ด๋ฌํ ์ด๋ฉ์ผ ๊ฒ์ฆ ๊ธฐ์ ์ ์ดํดํ๋ ๊ฒ์ ์ด๋ฉ์ผ ์ ๋ฌ ๊ฐ๋ฅ์ฑ์ ์ ์งํ๋ ๋ฐ ์ง์งํ๊ฒ ์ํ๋ ๋ชจ๋ ์ฌ๋์๊ฒ ํ์์ ์ ๋๋ค. ๊ฐ๋ ฅํ ์ด๋ฉ์ผ ๊ฒ์ฆ ์ ๋ต์ ์ฒซ ๋ฒ์งธ ๋ฉ์์ง๊ฐ ๋ฉ์ผ ์๋ฒ๋ฅผ ๋ ๋๊ธฐ ์ ์ ์ด๋ฉ์ผ ์ ํจ์ฑ์ ํ์ธํ๋ ๋ฐฉ๋ฒ์ ์๋ ๊ฒ์์ ์์๋ฉ๋๋ค. ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐฉ๋ฒ๋ค์ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฉ์ผ ์ ์ก ์์ด ๊ฒ์ฆํ๋ ์ด์ ๋?
๊ธฐ์ ์ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ด๋ฉ์ผ์ ๋ณด๋ด์ง ์๊ณ ๊ฒ์ฆํ๋ ๊ฒ์ด ๋น์ฆ๋์ค์ ์ค์ํ ์ด์ ๋ฅผ ์ดํดํด ๋ด ์๋ค.
๋ฐ์ ์ ํํ ๋ณดํธ
๋ณด๋ด๋ ๋ชจ๋ ์ด๋ฉ์ผ์ ๋ฐ์ ์ ํํ ์ ์์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ์ ํจํ์ง ์์ ์ฃผ์๋ก ์ด๋ฉ์ผ์ ๋ณด๋ด๋ฉด ๋ฐ์ก๋๊ณ , ISP๋ ์ด๋ฅผ ์ฃผ์ํฉ๋๋ค. ๋๋ฌด ๋ง์ ๋ฐ์ก์ ์ด๋ฉ์ผ ์ ๊ณต์ ์ฒด์ ์คํธ ๋ฐ์ก์์ผ ์ ์๋ค๋ ์ ํธ๋ฅผ ๋ณด๋ด๋ฉฐ, ์ด๋ ์ ์์ ์ธ ์ด๋ฉ์ผ์ด ์คํธ ํด๋์ ๋ค์ด๊ฐ๊ฑฐ๋ ๋๋ฉ์ธ์ด ์์ ํ ์ฐจ๋จ๋ ์ ์์ต๋๋ค.
์ ์ก ์ ์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ๋ฉด ์ด๋ฌํ ์์์ ์ฃผ๋ ๋ฐ์ก์ด ๋ฐ์ํ์ง ์๋๋ก ๋ฐฉ์งํ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ฌ์ ์๋ฐฉ์ ์ ๊ทผ ๋ฐฉ์์ ๋ฐ์ ์ ํํ์ ์ ์งํ๊ณ ์ค์ํ ๋ฉ์์ง๊ฐ ์๋ํ ์์ ์์๊ฒ ๋๋ฌํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
์๊ฐ๊ณผ ๋ฆฌ์์ค ์ ์ฝ
์ด๋ฉ์ผ ์ ์ก์๋ ๋น์ฉ์ด ๋ญ๋๋ค. ESP๋ฅผ ํตํด ์ด๋ฉ์ผ๋น ๋น์ฉ์ ์ง๋ถํ๋ ์์ฒด ์ด๋ฉ์ผ ์ธํ๋ผ๋ฅผ ์ ์ง ๊ด๋ฆฌํ๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ๋ฉ์์ง๋ฅผ ์ ๋ ๋ฐ์ง ๋ชปํ ์ฃผ์๋ก ๋ณด๋ด๋ ๋ฆฌ์์ค๋ฅผ ๋ญ๋นํ ์ด์ ๊ฐ ์์๊น์? ์ ์ก ์ ๊ฒ์ฆ์ ์ด๋ฉ์ผ ์ํฌํ๋ก์ ๋ค์ด๊ฐ๊ธฐ ์ ์ ์ ํจํ์ง ์์ ์ฃผ์๋ฅผ ํํฐ๋งํ์ฌ ์ด๋ฌํ ๋ญ๋น๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
๋ํ ๋ฐ์ก๋ ์ด๋ฉ์ผ์ ์ฒ๋ฆฌํ๋ ค๋ฉด ์ฒ๋ฆฌ ๋ฅ๋ ฅ๊ณผ ์๋ ๊ฒํ ์๊ฐ์ด ํ์ํฉ๋๋ค. ์ ํจํ์ง ์์ ์ด๋ฉ์ผ์ ๋ฏธ๋ฆฌ ์ก์๋ด๋ฉด ์ด์์ ๊ฐ์ํํ๊ณ ํ์ด ๋ ๊ฐ์น ์๋ ์์ ์ ์ง์คํ ์ ์์ต๋๋ค.
์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์
๊ฐ์ ์์์์ ์ค์๊ฐ ์ด๋ฉ์ผ ๊ฒ์ฆ์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์๋ชป ์ ๋ ฅํ์ ์ ์๋ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ์ฆ๊ฐ์ ์ธ ์์ ์ ํ์ธ ์ด๋ฉ์ผ์ ๋ฐ์ง ๋ชปํ๋ ๋ถํธํจ์ ๋ฐฉ์งํ๊ณ "๋๋ฝ๋" ๊ฒ์ฆ ๋งํฌ์ ๋ํ ์ง์ ํฐ์ผ์ ์ค์ ๋๋ค.
๋ฐ์ดํฐ ํ์ง ์ ์ง
์ด๋ฉ์ผ ๋ชฉ๋ก์ ๊ท์คํ ๋น์ฆ๋์ค ์์ฐ์ ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ์ ํจํ์ง ์์ ์ด๋ฉ์ผ ์ฃผ์๋ ๋ถ์์ ๋ ์ด๋ ต๊ฒ ๋ง๋ค๊ณ ์ธ๋ถํ๋ฅผ ๋ ํจ๊ณผ์ ์ผ๋ก ๋ง๋๋ ๋ ธ์ด์ฆ๋ฅผ ๋ํ๋ ๋๋ค. ์ด๋ฉ์ผ์ ๋ณด๋ด์ง ์๊ณ ๊ฒ์ฆํ๋ฉด ์ฒ์๋ถํฐ ๊นจ๋ํ๊ณ ์ ํํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
์ด์ ์ค์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด์ง ์๊ณ ์ด๋ฉ์ผ ๊ฒ์ฆ์ ๋ฌ์ฑํ๋ 5๊ฐ์ง ์ฃผ์ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ฐฉ๋ฒ 1: ๊ตฌ๋ฌธ ๊ฒ์ฆ
๊ตฌ๋ฌธ ๊ฒ์ฆ์ ์ด๋ฉ์ผ ๊ฒ์ฆ์ ์ฒซ ๋ฒ์งธ์ด์ ๊ฐ์ฅ ๊ฐ๋จํ ๊ณ์ธต์ ๋๋ค. ์ด๋ฉ์ผ ์ฃผ์๊ฐ RFC 5321 ๋ฐ RFC 5322 ์ฌ์์ ์ ์๋ ์ ์ ํ ํ์ ๊ท์น์ ๋ฐ๋ฅด๋์ง ํ์ธํฉ๋๋ค.
๊ตฌ๋ฌธ ๊ฒ์ฆ์ด ํ์ธํ๋ ๊ฒ
์ ํจํ ์ด๋ฉ์ผ ์ฃผ์๋ ํน์ ํ์ ๊ท์น์ ๋ฐ๋ผ์ผ ํฉ๋๋ค:
- ์ ํํ ํ๋์ @ ๊ธฐํธ ํฌํจ
- ๋ช ๋ช ๊ท์น์ ๋ฐ๋ฅด๋ ๋ก์ปฌ ๋ถ๋ถ(@ ์)
- ์ ํจํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ๋๋ฉ์ธ ๋ถ๋ถ(@ ๋ค)
- ํ์ฉ๋ ๋ฌธ์๋ง ์ฌ์ฉ
- ๊ธธ์ด ์ ํ ์ค์(๋ก์ปฌ ๋ถ๋ถ ์ต๋ 64์, ์ ์ฒด ์ต๋ 254์)
JavaScript ๊ตฌํ
์ด๋ฉ์ผ ๊ตฌ๋ฌธ ๊ฒ์ฆ์ ์ํ ์ค์ฉ์ ์ธ JavaScript ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
function validateEmailSyntax(email) {
// Trim whitespace
email = email.trim();
// Check basic length constraints
if (email.length > 254) {
return { valid: false, reason: 'Email address too long' };
}
// RFC 5322 compliant regex pattern
const emailRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
if (!emailRegex.test(email)) {
return { valid: false, reason: 'Invalid email format' };
}
// Extract local part and check length
const localPart = email.split('@')[0];
if (localPart.length > 64) {
return { valid: false, reason: 'Local part too long' };
}
return { valid: true, reason: 'Syntax is valid' };
}
// Usage examples
console.log(validateEmailSyntax('user@example.com'));
// { valid: true, reason: 'Syntax is valid' }
console.log(validateEmailSyntax('invalid.email@'));
// { valid: false, reason: 'Invalid email format' }
console.log(validateEmailSyntax('user@domain'));
// { valid: false, reason: 'Invalid email format' }
์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ํ ๊ฐ๋จํ ์ ๊ท์
RFC ์ค์ ์ ๊ท์์ ํฌ๊ด์ ์ด์ง๋ง, ๋ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ํ์ ์ค๋ฅ๋ฅผ ์ก๋ ๋ ๊ฐ๋จํ ํจํด์ ์ฌ์ฉํฉ๋๋ค:
function simpleEmailValidation(email) {
const simpleRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return simpleRegex.test(email.trim());
}
๊ตฌ๋ฌธ ๊ฒ์ฆ์ ํ๊ณ
๊ตฌ๋ฌธ ๊ฒ์ฆ๋ง์ผ๋ก๋ ์ด๋ฉ์ผ ์ฃผ์๊ฐ ์ค์ ๋ก ์กด์ฌํ๋์ง ํ์ธํ ์ ์์ต๋๋ค. definitely.fake.address@gmail.com ์ฃผ์๋ ๊ตฌ๋ฌธ ๊ฒ์ฆ์ ์๋ฒฝํ๊ฒ ํต๊ณผํ์ง๋ง, Gmail์๋ ๊ทธ๋ฌํ ๊ณ์ ์ด ์์ต๋๋ค. ์ด๋ฌํ ์ด์ ๋ก ๊ตฌ๋ฌธ ๊ฒ์ฆ์ ์ฒซ ๋ฒ์งธ ํ์ธ์ด์ด์ผ ํ๋ฉฐ ์ ์ผํ ํ์ธ์ด ๋์ด์๋ ์ ๋ฉ๋๋ค.
์ ํ๋ ์์ค: ์ฝ 30-40% (๋ช ๋ฐฑํ ์คํ ๋ฐ ํ์ ์ค๋ฅ๋ง ์ก์๋)
๋ฐฉ๋ฒ 2: ๋๋ฉ์ธ/DNS ๊ฒ์ฆ
๋ ๋ฒ์งธ ๊ฒ์ฆ ๊ณ์ธต์ ์ด๋ฉ์ผ ์ฃผ์์ ๋๋ฉ์ธ ๋ถ๋ถ์ด ์ค์ ๋ก ์กด์ฌํ๊ณ ์ธํฐ๋ท์์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋์ด ์๋์ง ํ์ธํฉ๋๋ค.
DNS ๊ฒ์ฆ์ด ํ์ธํ๋ ๊ฒ
๋๋ฉ์ธ ๊ฒ์ฆ์ ๋ค์์ ํ์ธํฉ๋๋ค:
- ๋๋ฉ์ธ์ด DNS์ ์กด์ฌํจ
- ๋๋ฉ์ธ์ด ์ ํจํ ๋ ์ฝ๋๋ก ํ์ธ๋จ
- ๋๋ฉ์ธ์ด ๋ง๋ฃ๋๊ฑฐ๋ ํ๊ธฐ๋์ง ์์์
Node.js ๊ตฌํ
Node.js์์ DNS ๊ฒ์ฆ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
const dns = require('dns').promises;
async function validateDomain(email) {
const domain = email.split('@')[1];
if (!domain) {
return { valid: false, reason: 'No domain found in email' };
}
try {
// Try to resolve the domain's A or AAAA records
const addresses = await dns.resolve(domain);
if (addresses && addresses.length > 0) {
return {
valid: true,
reason: 'Domain exists',
addresses: addresses
};
}
return { valid: false, reason: 'Domain has no DNS records' };
} catch (error) {
if (error.code === 'ENOTFOUND') {
return { valid: false, reason: 'Domain does not exist' };
}
if (error.code === 'ENODATA') {
return { valid: false, reason: 'No data for domain' };
}
return { valid: false, reason: `DNS error: ${error.message}` };
}
}
// Usage
async function checkEmail(email) {
const result = await validateDomain(email);
console.log(`${email}: ${result.reason}`);
return result;
}
checkEmail('user@google.com'); // Domain exists
checkEmail('user@thisisnotarealdomain12345.com'); // Domain does not exist
Python ๊ตฌํ
import dns.resolver
def validate_domain(email):
try:
domain = email.split('@')[1]
except IndexError:
return {'valid': False, 'reason': 'Invalid email format'}
try:
# Try to resolve A records
answers = dns.resolver.resolve(domain, 'A')
return {
'valid': True,
'reason': 'Domain exists',
'addresses': [str(rdata) for rdata in answers]
}
except dns.resolver.NXDOMAIN:
return {'valid': False, 'reason': 'Domain does not exist'}
except dns.resolver.NoAnswer:
return {'valid': False, 'reason': 'No DNS records found'}
except dns.exception.Timeout:
return {'valid': False, 'reason': 'DNS query timeout'}
except Exception as e:
return {'valid': False, 'reason': f'DNS error: {str(e)}'}
# Usage
result = validate_domain('user@gmail.com')
print(result)
ํ๊ณ
๋๋ฉ์ธ์ ์ด๋ฉ์ผ์ ์์ ํ์ง ์๊ณ ๋ ์กด์ฌํ ์ ์์ต๋๋ค. ๋ฐ๋๋ก ์ ํจํ ์ด๋ฉ์ผ ๋๋ฉ์ธ์ด ๋คํธ์ํฌ ๋ฌธ์ ๋ก ์ธํด ์ผ์์ ์ผ๋ก DNS ํ์ธ์ ์คํจํ ์ ์์ต๋๋ค. ๋๋ฉ์ธ ๊ฒ์ฆ์ ๊ตฌ๋ฌธ๋ง ํ์ธํ๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ํ์ ์ ์ ๊ณตํ์ง๋ง ์ด๋ฉ์ผ ์ ๋ฌ ๊ฐ๋ฅ์ฑ์ ํ์ธํ์ง๋ ์์ต๋๋ค.
์ ํ๋ ์์ค: ์ฝ 50-60% (์กด์ฌํ์ง ์๋ ๋๋ฉ์ธ์ ํํฐ๋งํจ)
๋ฐฉ๋ฒ 3: MX ๋ ์ฝ๋ ๊ฒ์ฆ
MX(๋ฉ์ผ ๊ตํ) ๋ ์ฝ๋ ๊ฒ์ฆ์ ๊ธฐ๋ณธ ๋๋ฉ์ธ ํ์ธ๋ณด๋ค ํจ์ฌ ๋ ๋์ ๋จ๊ณ์ ๋๋ค. MX ๋ ์ฝ๋๋ ํนํ ์ด๋ค ๋ฉ์ผ ์๋ฒ๊ฐ ๋๋ฉ์ธ์ ์ด๋ฉ์ผ์ ์์ ํ๋ ์ฑ ์์ด ์๋์ง ๋ํ๋ ๋๋ค.
MX ๋ ์ฝ๋๊ฐ ์๋ ค์ฃผ๋ ๊ฒ
DNS์ MX ๋ ์ฝ๋๋ ๋ค์์ ์ง์ ํฉ๋๋ค:
- ๋๋ฉ์ธ์ ์์ ์ด๋ฉ์ผ์ ์ฒ๋ฆฌํ๋ ์๋ฒ
- ์ฌ๋ฌ ๋ฉ์ผ ์๋ฒ์ ์ฐ์ ์์
- ๋๋ฉ์ธ์ด ์ด๋ฉ์ผ์ ์์ ํ๋๋ก ๊ตฌ์ฑ๋์ด ์๋์ง ์ฌ๋ถ
MX ๋ ์ฝ๋๊ฐ ์๋ ๋๋ฉ์ธ์ ์ฌ์ ํ ์กด์ฌํ ์ ์์ง๋ง ์ด๋ฉ์ผ์ ๋ฐ์ ์ ์์ต๋๋ค.
Node.js ๊ตฌํ
const dns = require('dns').promises;
async function validateMXRecords(email) {
const domain = email.split('@')[1];
if (!domain) {
return { valid: false, reason: 'No domain found' };
}
try {
const mxRecords = await dns.resolveMx(domain);
if (mxRecords && mxRecords.length > 0) {
// Sort by priority (lower number = higher priority)
mxRecords.sort((a, b) => a.priority - b.priority);
return {
valid: true,
reason: 'MX records found',
mxRecords: mxRecords.map(mx => ({
host: mx.exchange,
priority: mx.priority
}))
};
}
return { valid: false, reason: 'No MX records configured' };
} catch (error) {
if (error.code === 'ENOTFOUND') {
return { valid: false, reason: 'Domain does not exist' };
}
if (error.code === 'ENODATA') {
// Some domains use A records as fallback for email
try {
const aRecords = await dns.resolve(domain);
if (aRecords && aRecords.length > 0) {
return {
valid: true,
reason: 'No MX records, but A records exist (fallback)',
fallbackAddress: aRecords[0]
};
}
} catch {
// Ignore fallback check errors
}
return { valid: false, reason: 'No MX records and no fallback' };
}
return { valid: false, reason: `Error: ${error.message}` };
}
}
// Example usage
async function checkMX(email) {
const result = await validateMXRecords(email);
console.log(`\n${email}:`);
console.log(`Valid: ${result.valid}`);
console.log(`Reason: ${result.reason}`);
if (result.mxRecords) {
console.log('MX Records:');
result.mxRecords.forEach(mx => {
console.log(` Priority ${mx.priority}: ${mx.host}`);
});
}
return result;
}
// Test different domains
checkMX('user@gmail.com');
checkMX('user@outlook.com');
checkMX('user@fakeinvaliddomain123.com');
Python ๊ตฌํ
import dns.resolver
def validate_mx_records(email):
try:
domain = email.split('@')[1]
except IndexError:
return {'valid': False, 'reason': 'Invalid email format'}
try:
mx_records = dns.resolver.resolve(domain, 'MX')
records = sorted(
[(r.preference, str(r.exchange)) for r in mx_records],
key=lambda x: x[0]
)
return {
'valid': True,
'reason': 'MX records found',
'mx_records': [{'priority': p, 'host': h} for p, h in records]
}
except dns.resolver.NXDOMAIN:
return {'valid': False, 'reason': 'Domain does not exist'}
except dns.resolver.NoAnswer:
# Check for A record fallback
try:
a_records = dns.resolver.resolve(domain, 'A')
return {
'valid': True,
'reason': 'No MX records, using A record fallback',
'fallback': str(a_records[0])
}
except:
return {'valid': False, 'reason': 'No MX records and no fallback'}
except Exception as e:
return {'valid': False, 'reason': f'Error: {str(e)}'}
# Example usage
emails = ['user@gmail.com', 'user@microsoft.com', 'user@nodomainhere.xyz']
for email in emails:
result = validate_mx_records(email)
print(f"\n{email}:")
print(f" Valid: {result['valid']}")
print(f" Reason: {result['reason']}")
if 'mx_records' in result:
for mx in result['mx_records']:
print(f" MX: {mx['priority']} - {mx['host']}")
MX ๋ ์ฝ๋ ๊ฒฐ๊ณผ ์ดํด
์ฃผ์ ์ด๋ฉ์ผ ์ ๊ณต์ ์ฒด์ MX ๋ ์ฝ๋๋ฅผ ์กฐํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์์ต๋๋ค:
Gmail (google.com):
- Priority 5: gmail-smtp-in.l.google.com
- Priority 10: alt1.gmail-smtp-in.l.google.com
- Priority 20: alt2.gmail-smtp-in.l.google.com
Outlook (outlook.com):
- Priority 10: outlook-com.olc.protection.outlook.com
์ฌ๋ฌ MX ๋ ์ฝ๋๋ ์ค๋ณต์ฑ์ ์ ๊ณตํฉ๋๋ค. ํ๋์ ๋ฉ์ผ ์๋ฒ๊ฐ ๋ค์ด๋๋ฉด ๋ฉ์์ง๊ฐ ๋ฐฑ์ ์๋ฒ๋ก ๋ผ์ฐํ ๋ฉ๋๋ค.
์ ํ๋ ์์ค: ์ฝ 70-75% (๋๋ฉ์ธ์ด ์ด๋ฉ์ผ์ ๋ฐ์ ์ ์์์ ํ์ธ)
๋ฐฉ๋ฒ 4: SMTP ํธ๋์ ฐ์ดํฌ ๊ฒ์ฆ
SMTP ํธ๋์ ฐ์ดํฌ ๊ฒ์ฆ์ ์ ์กํ์ง ์๊ณ ์ด๋ฉ์ผ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ๊ฐ์ฅ ์ ๊ตํ ๋ฐฉ๋ฒ์ ๋๋ค. ์ด๋ฉ์ผ ์ ๋ฌ ํ๋ก์ธ์ค์ ์์์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ์ค์ ๋ก ๋ฉ์์ง๋ฅผ ์ ์กํ๊ธฐ ์ง์ ์ ์ค์งํฉ๋๋ค.
SMTP ๊ฒ์ฆ ์๋ ๋ฐฉ์
SMTP ํ๋กํ ์ฝ์ ์ด๋ฉ์ผ ์ ๋ฌ์ ์ํ ํน์ ์์๋ฅผ ๋ฐ๋ฆ ๋๋ค. SMTP ๊ฒ์ฆ์ ์ด๊ธฐ ๋จ๊ณ๋ฅผ ์คํํฉ๋๋ค:
- ์ฐ๊ฒฐ - ๋ฉ์ผ ์๋ฒ์ ์ฐ๊ฒฐ(์ผ๋ฐ์ ์ผ๋ก ํฌํธ 25)
- HELO/EHLO - ๋ฉ์ผ ์๋ฒ์ ์์ ์ ์๋ณ
- MAIL FROM - ๋ฐ์ ์ ์ฃผ์ ์ง์
- RCPT TO - ์์ ์ ์ง์ (๊ฒ์ฆํ๋ ค๋ ์ฃผ์)
- ์๋ต ๋ถ์ - ์๋ฒ์ ์๋ต์ ์์ ์๊ฐ ์กด์ฌํ๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋
๋ฉ์ผ ์๋ฒ๊ฐ RCPT TO ๋ช ๋ น์ ์๋ฝํ๋ฉด(์๋ต ์ฝ๋ 250), ์ด๋ฉ์ผ ์ฃผ์๊ฐ ์กด์ฌํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ๊ฑฐ๋ถ(5xx ์๋ต)๋ ์ผ๋ฐ์ ์ผ๋ก ์ฃผ์๊ฐ ์ ํจํ์ง ์์์ ์๋ฏธํฉ๋๋ค.
Node.js ๊ตฌํ
const net = require('net');
const dns = require('dns').promises;
class SMTPVerifier {
constructor(timeout = 10000) {
this.timeout = timeout;
}
async verify(email) {
const domain = email.split('@')[1];
// First, get MX records
let mxHost;
try {
const mxRecords = await dns.resolveMx(domain);
mxRecords.sort((a, b) => a.priority - b.priority);
mxHost = mxRecords[0].exchange;
} catch (error) {
return {
valid: false,
reason: 'Could not resolve MX records',
email
};
}
return new Promise((resolve) => {
const socket = new net.Socket();
let step = 0;
let response = '';
const commands = [
null, // Initial server greeting
'EHLO verify.local\r\n',
'MAIL FROM:<verify@verify.local>\r\n',
`RCPT TO:<${email}>\r\n`,
'QUIT\r\n'
];
socket.setTimeout(this.timeout);
socket.on('connect', () => {
console.log(`Connected to ${mxHost}`);
});
socket.on('data', (data) => {
response = data.toString();
const code = parseInt(response.substring(0, 3));
console.log(`Step ${step}: ${response.trim()}`);
// Handle each step
if (step === 0) {
// Server greeting - expect 220
if (code === 220) {
socket.write(commands[1]);
step++;
} else {
resolve({ valid: false, reason: 'Server rejected connection', email });
socket.destroy();
}
} else if (step === 1) {
// EHLO response - expect 250
if (code === 250) {
socket.write(commands[2]);
step++;
} else {
resolve({ valid: false, reason: 'EHLO rejected', email });
socket.destroy();
}
} else if (step === 2) {
// MAIL FROM response - expect 250
if (code === 250) {
socket.write(commands[3]);
step++;
} else {
resolve({ valid: false, reason: 'MAIL FROM rejected', email });
socket.destroy();
}
} else if (step === 3) {
// RCPT TO response - this is the verification result
socket.write(commands[4]);
if (code === 250) {
resolve({ valid: true, reason: 'Email address exists', email });
} else if (code === 550 || code === 551 || code === 553) {
resolve({ valid: false, reason: 'Email address does not exist', email });
} else if (code === 452 || code === 421) {
resolve({ valid: null, reason: 'Server temporarily unavailable', email });
} else {
resolve({ valid: null, reason: `Uncertain: ${response.trim()}`, email });
}
socket.destroy();
}
});
socket.on('timeout', () => {
resolve({ valid: null, reason: 'Connection timeout', email });
socket.destroy();
});
socket.on('error', (error) => {
resolve({ valid: null, reason: `Socket error: ${error.message}`, email });
socket.destroy();
});
// Connect to mail server
socket.connect(25, mxHost);
});
}
}
// Usage
async function verifyEmail(email) {
const verifier = new SMTPVerifier();
const result = await verifier.verify(email);
console.log(`\nResult for ${email}:`);
console.log(`Valid: ${result.valid}`);
console.log(`Reason: ${result.reason}`);
return result;
}
verifyEmail('test@example.com');
Python ๊ตฌํ
import socket
import dns.resolver
class SMTPVerifier:
def __init__(self, timeout=10):
self.timeout = timeout
def get_mx_host(self, domain):
"""Get the primary MX host for a domain."""
try:
records = dns.resolver.resolve(domain, 'MX')
mx_records = sorted(
[(r.preference, str(r.exchange).rstrip('.')) for r in records],
key=lambda x: x[0]
)
return mx_records[0][1]
except Exception as e:
return None
def verify(self, email):
"""Verify an email address via SMTP handshake."""
try:
domain = email.split('@')[1]
except IndexError:
return {'valid': False, 'reason': 'Invalid email format'}
mx_host = self.get_mx_host(domain)
if not mx_host:
return {'valid': False, 'reason': 'Could not resolve MX records'}
try:
# Connect to mail server
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
sock.connect((mx_host, 25))
# Receive greeting
response = sock.recv(1024).decode()
if not response.startswith('220'):
return {'valid': False, 'reason': 'Server rejected connection'}
# Send EHLO
sock.send(b'EHLO verify.local\r\n')
response = sock.recv(1024).decode()
if not response.startswith('250'):
return {'valid': False, 'reason': 'EHLO rejected'}
# Send MAIL FROM
sock.send(b'MAIL FROM:<verify@verify.local>\r\n')
response = sock.recv(1024).decode()
if not response.startswith('250'):
return {'valid': False, 'reason': 'MAIL FROM rejected'}
# Send RCPT TO - this is the verification
sock.send(f'RCPT TO:<{email}>\r\n'.encode())
response = sock.recv(1024).decode()
code = int(response[:3])
# Close connection
sock.send(b'QUIT\r\n')
sock.close()
# Analyze response
if code == 250:
return {'valid': True, 'reason': 'Email address exists'}
elif code in [550, 551, 553]:
return {'valid': False, 'reason': 'Email address does not exist'}
elif code in [452, 421]:
return {'valid': None, 'reason': 'Server temporarily unavailable'}
else:
return {'valid': None, 'reason': f'Uncertain response: {response}'}
except socket.timeout:
return {'valid': None, 'reason': 'Connection timeout'}
except socket.error as e:
return {'valid': None, 'reason': f'Socket error: {str(e)}'}
except Exception as e:
return {'valid': None, 'reason': f'Error: {str(e)}'}
# Usage
verifier = SMTPVerifier()
result = verifier.verify('test@example.com')
print(f"Valid: {result['valid']}")
print(f"Reason: {result['reason']}")
SMTP ์๋ต ์ฝ๋ ์ค๋ช
๊ฒ์ฆ ๊ฒฐ๊ณผ๋ฅผ ํด์ํ๋ ค๋ฉด SMTP ์๋ต ์ฝ๋๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
| ์ฝ๋ | ์๋ฏธ | ํด์ |
|---|---|---|
| 250 | OK | ์ด๋ฉ์ผ ์ฃผ์๊ฐ ์กด์ฌํ๊ณ ๋ฉ์ผ์ ์์ ํจ |
| 251 | User not local | ๋ค๋ฅธ ์ฃผ์๋ก ์ ๋ฌ๋จ |
| 450 | Mailbox unavailable | ์ผ์์ ๋ฌธ์ , ๋์ค์ ์ฌ์๋ |
| 451 | Local error | ์๋ฒ ์ธก ๋ฌธ์ |
| 452 | Insufficient storage | ๋ฉ์ผํจ์ด ๊ฐ๋ ์ฐธ |
| 550 | Mailbox not found | ์ด๋ฉ์ผ ์ฃผ์๊ฐ ์กด์ฌํ์ง ์์ |
| 551 | User not local | ์ ๋ฌ ๊ตฌ์ฑ์ด ์์ |
| 553 | Mailbox name invalid | ๋ฉ์ผํจ ์ด๋ฆ์ ๊ตฌ๋ฌธ ์ค๋ฅ |
์ค์ํ ํ๊ณ
SMTP ๊ฒ์ฆ์๋ ๋ช ๊ฐ์ง ์ค์ํ ํ๊ณ๊ฐ ์์ต๋๋ค:
์บ์น์ฌ ๋๋ฉ์ธ: ์ผ๋ถ ๋ฉ์ผ ์๋ฒ๋ ์ค์ ๋ก ์กด์ฌํ๋์ง ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ชจ๋ ์ฃผ์๋ฅผ ์๋ฝํ๋ฉฐ ๋ชจ๋ ๊ฒ์ ๋ํด 250์ ๋ฐํํฉ๋๋ค. ์ด๋ฌํ "์บ์น์ฌ" ๊ตฌ์ฑ์ SMTP ๊ฒ์ฆ์ ๋ฌด๋ ฅํํฉ๋๋ค.
๊ทธ๋ ์ด๋ฆฌ์คํ : ์๋ฒ๋ ์ ์ ์๋ ๋ฐ์ ์์ ๋ฉ์์ง๋ฅผ ์ผ์์ ์ผ๋ก ๊ฑฐ๋ถํ ์ ์์ต๋๋ค. ๊ฒ์ฆ์ด ์ฌ์๋ ์ ์ฑ๊ณตํ ์ ์๋ ๊ฑฐ๋ถ๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
์๋ ์ ํ: ๋ฉ์ผ ์๋ฒ๋ ์ข ์ข ์ฐ๊ฒฐ ์๋๋ฅผ ์ ํํฉ๋๋ค. ๋๋ ๊ฒ์ฆ์ ์ฐจ๋จ์ ํธ๋ฆฌ๊ฑฐํ ์ ์์ต๋๋ค.
IP ํํ: ๊ฒ์ฆ ์๋ฒ์ IP ํํ์ ๋ฉ์ผ ์๋ฒ๊ฐ ์ ์งํ๊ฒ ์๋ตํ๋์ง ์ฌ๋ถ์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
๋ฐฉํ๋ฒฝ ์ ํ: ๋ง์ ๋คํธ์ํฌ๊ฐ ๋ณด์์์ ์ด์ ๋ก ํฌํธ 25์ ์์๋ฐ์ด๋ SMTP ํธ๋ํฝ์ ์ฐจ๋จํฉ๋๋ค.
์ ํ๋ ์์ค: ์ฝ 85-90% (์๋ฒ๊ฐ ์ ์งํ๊ฒ ์๋ตํ ๋)
๋ฐฉ๋ฒ 5: ์ด๋ฉ์ผ ๊ฒ์ฆ API ์๋น์ค
ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ, ์ ๋ฌธ ์ด๋ฉ์ผ ๊ฒ์ฆ API๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํ๋, ์๋ ๋ฐ ์์ ์ฑ์ ์ต์์ ๊ท ํ์ ์ ๊ณตํฉ๋๋ค. BillionVerify์ ๊ฐ์ ์๋น์ค๋ ๊ฐ๋ณ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ฌ์ฑํ ์ ์๋ ์ถ๊ฐ ๊ฒ์ฌ๋ฅผ ์ ๊ณตํ๋ฉด์ ๋ค์ค ๋ฐฉ๋ฒ ๊ฒ์ฆ์ ๋ชจ๋ ๋ณต์ก์ฑ์ ์ฒ๋ฆฌํฉ๋๋ค.
API ๊ธฐ๋ฐ ๊ฒ์ฆ์ ์ฅ์
๋ ๋์ ์ ํ๋: ์ ๋ฌธ ์๋น์ค๋ ์ผํ์ฉ ์ด๋ฉ์ผ ๊ฐ์ง, ์ญํ ๊ธฐ๋ฐ ์ฃผ์ ์๋ณ ๋ฐ ์บ์น์ฌ ๋๋ฉ์ธ ์ฒ๋ฆฌ์ ๊ฐ์ ์ถ๊ฐ ์ธํ ๋ฆฌ์ ์ค์ ํจ๊ป ๋ชจ๋ ๊ฒ์ฆ ๋ฐฉ๋ฒ(๊ตฌ๋ฌธ, DNS, MX, SMTP)์ ๊ฒฐํฉํฉ๋๋ค.
๋ ๋์ ์ธํ๋ผ: API ์๋น์ค๋ ๊ฐ๋ ฅํ ํํ์ ๊ฐ์ง ์ ์ฉ IP ํ, ๋ ๋น ๋ฅธ ๊ธ๋ก๋ฒ ์๋ต์ ์ํ ๋ถ์ฐ ์๋ฒ, ์ฃผ์ ์ด๋ฉ์ผ ์ ๊ณต์ ์ฒด์์ ์ง์ ์ ์ธ ๊ด๊ณ๋ฅผ ์ ์งํฉ๋๋ค.
์ ์ง ๊ด๋ฆฌ ๋ถํ์: SMTP ๊ฒ์ฆ ์ฝ๋๋ฅผ ์ ์ง ๊ด๋ฆฌํ๊ฑฐ๋ ์ฃ์ง ์ผ์ด์ค๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ๊ฒ์ฆ ์๋ฒ๊ฐ ์ฐจ๋จ๋ ๊ฑฑ์ ์ ํ ํ์๊ฐ ์์ต๋๋ค.
ํ์ฅ์ฑ: API๋ ์ธํ๋ผ ๋ฌธ์ ์์ด ์๋ฐฑ๋ง ๊ฑด์ ๊ฒ์ฆ์ ์ฒ๋ฆฌํฉ๋๋ค.
BillionVerify API ํตํฉ
์ด๋ฉ์ผ ๊ฒ์ฆ์ ์ํด BillionVerify API๋ฅผ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
Node.js ์์ :
const axios = require('axios');
const BILLIONVERIFY_API_KEY = 'your_api_key_here';
const API_URL = 'https://api.billionverify.com/v1';
async function verifyEmailWithAPI(email) {
try {
const response = await axios.post(
`${API_URL}/verify`,
{ email },
{
headers: {
'Authorization': `Bearer ${BILLIONVERIFY_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
const result = response.data;
return {
email: result.email,
valid: result.deliverable,
status: result.status,
details: {
syntaxValid: result.syntax_valid,
domainExists: result.domain_exists,
mxRecords: result.mx_found,
smtpCheck: result.smtp_check,
disposable: result.is_disposable,
roleAddress: result.is_role_address,
catchAll: result.is_catch_all,
freeProvider: result.is_free_provider
},
score: result.quality_score
};
} catch (error) {
console.error('API Error:', error.response?.data || error.message);
throw error;
}
}
// Usage
async function main() {
const emails = [
'valid.user@gmail.com',
'fake.address@company.com',
'temp@10minutemail.com'
];
for (const email of emails) {
const result = await verifyEmailWithAPI(email);
console.log(`\n${email}:`);
console.log(` Deliverable: ${result.valid}`);
console.log(` Status: ${result.status}`);
console.log(` Quality Score: ${result.score}`);
console.log(` Disposable: ${result.details.disposable}`);
console.log(` Catch-All: ${result.details.catchAll}`);
}
}
main();
Python ์์ :
import requests
BILLIONVERIFY_API_KEY = 'your_api_key_here'
API_URL = 'https://api.billionverify.com/v1'
def verify_email_with_api(email):
"""Verify an email address using BillionVerify API."""
headers = {
'Authorization': f'Bearer {BILLIONVERIFY_API_KEY}',
'Content-Type': 'application/json'
}
response = requests.post(
f'{API_URL}/verify',
json={'email': email},
headers=headers
)
if response.status_code != 200:
raise Exception(f'API Error: {response.text}')
result = response.json()
return {
'email': result['email'],
'valid': result['deliverable'],
'status': result['status'],
'details': {
'syntax_valid': result['syntax_valid'],
'domain_exists': result['domain_exists'],
'mx_records': result['mx_found'],
'smtp_check': result['smtp_check'],
'disposable': result['is_disposable'],
'role_address': result['is_role_address'],
'catch_all': result['is_catch_all'],
'free_provider': result['is_free_provider']
},
'score': result['quality_score']
}
# Usage
emails = ['user@gmail.com', 'contact@company.com', 'test@tempmail.com']
for email in emails:
try:
result = verify_email_with_api(email)
print(f"\n{email}:")
print(f" Deliverable: {result['valid']}")
print(f" Status: {result['status']}")
print(f" Quality Score: {result['score']}")
except Exception as e:
print(f"Error verifying {email}: {e}")
์ค์๊ฐ ์์ ํตํฉ
๊ฐ์ ์์์ ๊ฒฝ์ฐ, BillionVerify๋ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ๋ ๋์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ ์ ์๋ ์ค์๊ฐ ๊ฒ์ฆ์ ์ ๊ณตํฉ๋๋ค:
// React component example
import { useState, useCallback } from 'react';
import debounce from 'lodash/debounce';
function EmailInput() {
const [email, setEmail] = useState('');
const [validation, setValidation] = useState(null);
const [loading, setLoading] = useState(false);
const verifyEmail = useCallback(
debounce(async (emailToVerify) => {
if (!emailToVerify || emailToVerify.length < 5) return;
setLoading(true);
try {
const response = await fetch('/api/verify-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: emailToVerify })
});
const result = await response.json();
setValidation(result);
} catch (error) {
console.error('Verification failed:', error);
} finally {
setLoading(false);
}
}, 500),
[]
);
const handleChange = (e) => {
const newEmail = e.target.value;
setEmail(newEmail);
verifyEmail(newEmail);
};
return (
<div className="email-input-wrapper">
<input
type="email"
value={email}
onChange={handleChange}
placeholder="Enter your email"
className={validation?.valid === false ? 'invalid' : ''}
/>
{loading && <span className="loading">Verifying...</span>}
{validation && !loading && (
<span className={validation.valid ? 'valid' : 'invalid'}>
{validation.valid ? 'โ Valid email' : 'โ ' + validation.reason}
</span>
)}
</div>
);
}
์ ํ๋ ์์ค: 97-99%+ (์ถ๊ฐ ์ธํ ๋ฆฌ์ ์ค์ ๋ชจ๋ ๋ฐฉ๋ฒ์ ๊ฒฐํฉ)
๋ฐฉ๋ฒ ๋น๊ต: ์ฌ๋ฐ๋ฅธ ์ ๊ทผ ๋ฐฉ์ ์ ํ
๋ค์์ ํ์์ ๋ง๋ ์ฌ๋ฐ๋ฅธ ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ ํํ๋ ๋ฐ ๋์์ด ๋๋ ํฌ๊ด์ ์ธ ๋น๊ต์ ๋๋ค:
| ๋ฐฉ๋ฒ | ์ ํ๋ | ์๋ | ๋ณต์ก์ฑ | ๋น์ฉ | ์ต์ ์ฉ๋ |
|---|---|---|---|---|---|
| ๊ตฌ๋ฌธ ๊ฒ์ฆ | 30-40% | ์ฆ์ | ๋ฎ์ | ๋ฌด๋ฃ | 1์ฐจ ํํฐ๋ง |
| ๋๋ฉ์ธ/DNS ํ์ธ | 50-60% | ๋น ๋ฆ | ๋ฎ์ | ๋ฌด๋ฃ | ๋น ๋ฅธ ์ฌ์ ํ์ธ |
| MX ๋ ์ฝ๋ ๊ฒ์ฆ | 70-75% | ๋น ๋ฆ | ์ค๊ฐ | ๋ฌด๋ฃ | ์์ ๊ฒ์ฆ |
| SMTP ํธ๋์ ฐ์ดํฌ | 85-90% | ๋๋ฆผ | ๋์ | ์ธํ๋ผ | ์ผ๊ด ์ ๋ฆฌ |
| API ์๋น์ค | 97-99% | ๋น ๋ฆ | ๋ฎ์ | ์ฟผ๋ฆฌ๋น | ํ๋ก๋์ ์์คํ |
์ฌ์ฉ ์ฌ๋ก๋ณ ๊ถ์ฅ ์ฌํญ
๊ฐ์ ์์: ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ํ ํด๋ผ์ด์ธํธ ์ธก ๊ตฌ๋ฌธ ๊ฒ์ฆ๊ณผ ์ ์ถ ์ API ๊ฒ์ฆ์ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ์ธ์. ์ด๋ ๋ฐ์ดํฐ ํ์ง์ ๋ณด์ฅํ๋ฉด์ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
์ด๋ฉ์ผ ๋ง์ผํ ์บ ํ์ธ: ์ ์ก ์ ๋๋ ๊ฒ์ฆ์ ์ํด API ์๋น์ค๋ฅผ ์ฌ์ฉํ์ธ์. ๊ฒ์ฆ๋น ๋น์ฉ์ ๋์ ๋ฐ์ก๋ฅ ๋ก ์ธํ ํผํด๋ณด๋ค ํจ์ฌ ์ ์ต๋๋ค.
๋ฐ์ดํฐ ์ ๋ฆฌ ํ๋ก์ ํธ: ๋๋ ์ ๋ก๋ ๊ธฐ๋ฅ์ด ์๋ API ์๋น์ค๋ ๊ธฐ์กด ๋ชฉ๋ก์ ์ ๋ฆฌํ๋ ๋ฐ ์์ด ์ ํ๋์ ํจ์จ์ฑ์ ์ต์์ ๊ท ํ์ ์ ๊ณตํฉ๋๋ค.
๊ฐ๋ฐ/ํ ์คํธ: ๊ตฌ๋ฌธ ๋ฐ MX ๊ฒ์ฆ์ ์๋ฒฝํ ์ ํ๋๊ฐ ์ค์ํ์ง ์์ ๊ฐ๋ฐ ํ๊ฒฝ์ ์ ํฉํ ์ ํ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ด๋ฉ์ผ ๊ฒ์ฆ ๋ชจ๋ฒ ์ฌ๋ก
์ฌ๋ฌ ๊ณ์ธต ๊ตฌํ
๋จ์ผ ๊ฒ์ฆ ๋ฐฉ๋ฒ์๋ง ์์กดํ์ง ๋ง์ธ์. ๊ณ์ธตํ๋ ์ ๊ทผ ๋ฐฉ์์ ๊ตฌํํ์ธ์:
- ์ฆ์: ํด๋ผ์ด์ธํธ ์ธก์ ๊ตฌ๋ฌธ ๊ฒ์ฆ
- ์ ์ถ ์: ๋น ๋ฅธ ์๋ฒ ์ธก ๊ฒ์ฆ์ ์ํ MX ๋ ์ฝ๋ ํ์ธ
- ์บ ํ์ธ ์ : ์ ๋ฌ ๊ฐ๋ฅ์ฑ ํ์ธ์ ์ํ ์ ์ฒด API ๊ฒ์ฆ
์ฃ์ง ์ผ์ด์ค๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌ
์ผ๋ถ ๊ฒ์ฆ ๊ฒฐ๊ณผ๋ ๊ฒฐ๋ก ์ด ๋์ง ์์ต๋๋ค(์บ์น์ฌ ๋๋ฉ์ธ, ์ผ์์ ์คํจ). ์์คํ ์ ๋ค์๊ณผ ๊ฐ์ด ์ค๊ณํ์ธ์:
- ๋ถํ์คํ ๊ฒ์ฆ ๊ฒฐ๊ณผ๊ฐ ์๋ ์ฃผ์๋ฅผ ์๋ฝํ๋ ๊ฒํ ๋ฅผ ์ํด ํ๋๊ทธ ์ง์
- ์ผ์์ ์คํจ์ ๋ํ ์ฌ์๋ ๋ก์ง ๊ตฌํ
- ํจํด์ ์๋ณํ๊ธฐ ์ํด ๊ฒ์ฆ ๊ฒฐ๊ณผ ์ถ์
์ ์ ํ ์์ ์ ๊ฒ์ฆ
- ๋ฑ๋ก: ๊ณ์ ์์ฑ ์ ์ ๊ฒ์ฆ
- ๊ฐ์ ธ์ค๊ธฐ: ์ธ๋ถ ์์ค์์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ฌ ๋ ๊ฒ์ฆ
- ์ ๊ธฐ์ : ์ฌ์ฐธ์ฌ ์บ ํ์ธ ์ ์ ํด๋ฉด ์ฃผ์ ์ฌ๊ฒ์ฆ
- ๋๊ท๋ชจ ์ ์ก ์ : ๋๊ท๋ชจ ์บ ํ์ธ ์ ์ ํญ์ ๊ฒ์ฆ
์๋ ์ ํ ์ค์
์์ฒด SMTP ๊ฒ์ฆ์ ์ฌ์ฉํ๋ API๋ฅผ ์ฌ์ฉํ๋ ๋ฉ์ผ ์๋ฒ ๋ฐ ์๋น์ค ์ ๊ณต์ ์ฒด์ ์ข์ ๊ด๊ณ๋ฅผ ์ ์งํ๊ธฐ ์ํด ์๋ ์ ํ์ ์ค์ํ์ธ์.
๊ฒฐ๋ก
์ค์ ์ด๋ฉ์ผ์ ๋ณด๋ด์ง ์๊ณ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๊ฒ์ฆํ๋ ๊ฒ์ ๊ฐ๋ฅํ ๋ฟ๋ง ์๋๋ผ ์ด๋ฉ์ผ ์ ๋ฌ ๊ฐ๋ฅ์ฑ๊ณผ ๋ฐ์ ์ ํํ์ ์ ์งํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ๊ฐ๋จํ ๊ตฌ๋ฌธ ํ์ธ๋ถํฐ ์ ๊ตํ API ๊ธฐ๋ฐ ๊ฒ์ฆ๊น์ง, ์ ํ๋ ์๊ตฌ ์ฌํญ๊ณผ ๊ธฐ์ ์ญ๋์ ๋ฐ๋ผ ์ฌ๋ฌ ์ต์ ์ด ์์ต๋๋ค.
๋๋ถ๋ถ์ ํ๋ก๋์ ์ ํ๋ฆฌ์ผ์ด์ ์๋ ๋ค์์ ๊ถ์ฅํฉ๋๋ค:
- ๊ฐ๋จํ๊ฒ ์์: ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ํ ๊ตฌ๋ฌธ ๊ฒ์ฆ ๊ตฌํ
- ๊น์ด ์ถ๊ฐ: ์๋ฒ ์ธก ๊ฒ์ฆ์ ์ํ DNS ๋ฐ MX ํ์ธ ํฌํจ
- ์ ๋ฌธ์ ์ผ๋ก ์ ํ: ํ๋ก๋์ ํ์ง ๊ฒ์ฆ์ ์ํด BillionVerify์ ๊ฐ์ API ์๋น์ค ์ฌ์ฉ
์ ๋ฌธ ์ด๋ฉ์ผ ๊ฒ์ฆ์ ๊ตฌํํ ์ค๋น๊ฐ ๋์ จ๋์? ๊ฒ์ฆ ์๋์ ํ์ธํ๋ ค๋ฉด ์ด๋ฉ์ผ ๊ฒ์ฌ๊ธฐ ๋๊ตฌ๋ฅผ ํ์ธํ๊ฑฐ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํํ๊ฒ ํตํฉํ๋ ค๋ฉด BillionVerify API๋ฅผ ์ดํด๋ณด์ธ์.
์ ์ ํ ์ด๋ฉ์ผ ๊ฒ์ฆ์ ๊ตฌํํ๋ฉด ๋ฐ์ ์ ํํ์ ๋ณดํธํ๊ณ ์ ๋ฌ ๊ฐ๋ฅ์ฑ์ ๊ฐ์ ํ๋ฉฐ ๋ฉ์์ง๋ฅผ ๋ฐ๊ณ ์ ํ๋ ์ฌ๋๋ค์๊ฒ ๋ฉ์์ง๊ฐ ๋๋ฌํ๋๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค. ์ค๋๋ถํฐ ๋ ์ค๋งํธํ๊ฒ ๊ฒ์ฆ์ ์์ํ์ธ์.