mailcheck / app.py
seawolf2357's picture
Update app.py
2ab666f verified
import gradio as gr
import re
import dns.resolver
from typing import Tuple
from dns.exception import DNSException
def check_syntax(mail_address: str) -> Tuple[bool, str]:
"""이메일 μ£Όμ†Œ ꡬ문 검사"""
# RFC 5322 ν‘œμ€€μ„ 기반으둜 ν•œ 더 μ—„κ²©ν•œ 이메일 μ •κ·œμ‹ νŒ¨ν„΄
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
# κΈ°λ³Έ νŒ¨ν„΄ 검사
if not re.match(pattern, mail_address):
return False, "❌ 이메일 μ£Όμ†Œ ν˜•μ‹μ΄ μ˜¬λ°”λ₯΄μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
# μΆ”κ°€ μœ νš¨μ„± 검사
local_part, domain = mail_address.split('@')
# 둜컬 파트 검사
if len(local_part) > 64:
return False, "❌ 이메일 μ£Όμ†Œμ˜ @ μ•žλΆ€λΆ„μ΄ λ„ˆλ¬΄ κΉλ‹ˆλ‹€."
if local_part.startswith('.') or local_part.endswith('.'):
return False, "❌ 이메일 μ£Όμ†Œμ˜ @ μ•žλΆ€λΆ„μ΄ 점(.)으둜 μ‹œμž‘ν•˜κ±°λ‚˜ 끝날 수 μ—†μŠ΅λ‹ˆλ‹€."
if '..' in local_part:
return False, "❌ 이메일 μ£Όμ†Œμ˜ @ μ•žλΆ€λΆ„μ— μ—°μ†λœ 점(..)이 μžˆμ„ 수 μ—†μŠ΅λ‹ˆλ‹€."
# 도메인 파트 검사
if len(domain) > 255:
return False, "❌ 도메인이 λ„ˆλ¬΄ κΉλ‹ˆλ‹€."
if domain.startswith('-') or domain.endswith('-'):
return False, "❌ 도메인은 ν•˜μ΄ν”ˆ(-)으둜 μ‹œμž‘ν•˜κ±°λ‚˜ 끝날 수 μ—†μŠ΅λ‹ˆλ‹€."
if not all(part.isalnum() or '-' in part for part in domain.split('.')):
return False, "❌ 도메인에 ν—ˆμš©λ˜μ§€ μ•ŠλŠ” λ¬Έμžκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€."
return True, "βœ… 이메일 μ£Όμ†Œ ν˜•μ‹μ΄ μ˜¬λ°”λ¦…λ‹ˆλ‹€."
def is_disposable_domain(domain: str) -> bool:
"""μž„μ‹œ 이메일 도메인 체크"""
disposable_domains = {
'tempmail.com', 'throwawaymail.com', 'mailinator.com',
'temp-mail.org', 'fake-email.com', 'temporary-mail.net'
}
return domain.lower() in disposable_domains
def check_dns(domain: str) -> Tuple[bool, str]:
"""DNS MX λ ˆμ½”λ“œ 검사"""
try:
# μž„μ‹œ 이메일 도메인 체크
if is_disposable_domain(domain):
return False, "❌ μž„μ‹œ 이메일 도메인은 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€."
# DNS MX λ ˆμ½”λ“œ 확인
records = dns.resolver.resolve(domain, 'MX')
if not records:
return False, "❌ λ„λ©”μΈμ˜ 메일 μ„œλ²„λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."
# μ‹€μ œ MX λ ˆμ½”λ“œ λ‚΄μš© 확인
mx_records = [str(r.exchange).rstrip('.') for r in records]
if not mx_records:
return False, "❌ μœ νš¨ν•œ 메일 μ„œλ²„ 정보가 μ—†μŠ΅λ‹ˆλ‹€."
# A λ ˆμ½”λ“œλ„ 확인
try:
dns.resolver.resolve(domain, 'A')
except DNSException:
try:
dns.resolver.resolve(domain, 'AAAA')
except DNSException:
return False, "❌ 도메인이 μ‹€μ œλ‘œ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."
return True, "βœ… λ„λ©”μΈμ˜ 메일 μ„œλ²„κ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€."
except dns.resolver.NXDOMAIN:
return False, "❌ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” λ„λ©”μΈμž…λ‹ˆλ‹€."
except dns.resolver.NoAnswer:
return False, "❌ 도메인에 메일 μ„œλ²„ 정보가 μ—†μŠ΅λ‹ˆλ‹€."
except dns.resolver.NoNameservers:
return False, "❌ DNS μ„œλ²„μ— μ—°κ²°ν•  수 μ—†μŠ΅λ‹ˆλ‹€."
except Exception as e:
return False, f"❌ DNS 확인 쀑 였λ₯˜ λ°œμƒ: {str(e)}"
def validate_email(mail_address: str) -> str:
"""이메일 μ£Όμ†Œ μ’…ν•© 검증"""
results = []
# 1. κΈ°λ³Έ μž…λ ₯κ°’ 검사
if not mail_address or not isinstance(mail_address, str):
return "❌ μœ νš¨ν•˜μ§€ μ•Šμ€ μž…λ ₯μž…λ‹ˆλ‹€."
mail_address = mail_address.strip()
if not mail_address:
return "❌ 이메일 μ£Όμ†Œλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”."
# 2. ꡬ문 검사
syntax_valid, syntax_msg = check_syntax(mail_address)
results.append(syntax_msg)
if not syntax_valid:
return "\n".join(results)
# 3. 도메인 μΆ”μΆœ 및 DNS 검사
try:
domain = mail_address.split('@')[1]
dns_valid, dns_msg = check_dns(domain)
results.append(dns_msg)
if not dns_valid:
return "\n".join(results)
# λͺ¨λ“  검증 톡과
results.append("βœ… 이메일 μ£Όμ†Œκ°€ μœ νš¨ν•©λ‹ˆλ‹€.")
except Exception as e:
results.append(f"❌ 검증 쀑 였λ₯˜ λ°œμƒ: {str(e)}")
return "\n".join(results)
# Gradio μΈν„°νŽ˜μ΄μŠ€ ꡬ성
iface = gr.Interface(
fn=validate_email,
inputs=gr.Textbox(
label="이메일 μ£Όμ†Œλ₯Ό μž…λ ₯ν•˜μ„Έμš”",
placeholder="[email protected]"
),
outputs=gr.Textbox(label="검증 κ²°κ³Ό"),
title="이메일 μ£Όμ†Œ 검증 도ꡬ",
description="""
이 λ„κ΅¬λŠ” λ‹€μŒ 사항듀을 κ²€μ¦ν•©λ‹ˆλ‹€:
1. 이메일 μ£Όμ†Œ ν˜•μ‹ 검사 (RFC 5322 ν‘œμ€€ μ€€μˆ˜)
2. λ„λ©”μΈμ˜ 메일 μ„œλ²„(MX λ ˆμ½”λ“œ) 쑴재 μ—¬λΆ€ 확인
3. λ„λ©”μΈμ˜ μ‹€μ œ 쑴재 μ—¬λΆ€ 확인
4. μž„μ‹œ 이메일 도메인 필터링
""",
examples=[
["[email protected]"],
["[email protected]"],
["[email protected]"],
["malformed@@email.com"],
["[email protected]"],
["test@domain"],
["[email protected]"]
],
theme=gr.themes.Soft()
)
# μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹€ν–‰
if __name__ == "__main__":
iface.launch()