使用Python验证Email地址:批量检测规避SMTP服务器IP封禁方法
针对你要批量验证1000个邮箱的需求,结合你提供的代码,以下是几个能有效降低IP封禁风险的实操方法:
严格控制请求频率,加入随机延迟
SMTP服务器普遍有请求速率限制,连续高频的验证请求很容易触发封禁。建议在每次验证请求之间加入2-5秒的随机延迟(别用固定间隔,容易被识别为脚本),如果是同一个域名下的多个邮箱,间隔再拉长到5-10秒。可以用time.sleep(random.randint(2,5))实现,记得导入random和time模块。使用真实合法的发件人邮箱
你代码里的fromAddress = 'corn@bt.com'是第三方域名的无效邮箱,SMTP服务器会直接标记这类请求为恶意。换成你自己拥有的真实邮箱(比如自己域名的企业邮箱,或者正规服务商的邮箱),并且保证这个邮箱能正常接收邮件,避免被服务器拦截。复用SMTP连接,减少握手次数
原代码每次验证都新建一次SMTP连接,频繁的TCP握手会大幅增加被封禁的概率。优化思路是:先把所有邮箱按域名分组,同一个域名下的邮箱共用一个SMTP连接——先查该域名的MX记录,建立连接后批量验证所有该域名下的邮箱,验证完成后再断开连接。这样能大幅减少连接次数,降低服务器的警戒值。引入代理IP池(可选,适合超大量验证)
如果1000个邮箱覆盖的域名特别多,单IP还是有风险,可以用代理IP池轮换请求。找稳定的付费代理(免费代理大多不稳定,反而容易触发风控),每次验证前切换不同的代理IP,避免单个IP的请求量过高。动态处理错误响应,及时调整策略
SMTP返回的错误码能帮你判断服务器状态:比如遇到421(服务繁忙/暂时封禁)、550(IP被拉黑)这类错误,立刻暂停对该域名的验证,间隔10-15分钟再试,或者直接切换IP后继续。不要硬着头皮重复请求,只会加重封禁。前置过滤无效邮箱,减少不必要的SMTP请求
在发起SMTP验证前,先做几层过滤:- 用正则做语法校验(你代码里已经实现);
- 检查域名的MX记录是否存在,不存在的直接判定为无效;
- 可以查域名的WHOIS信息,判断域名是否处于活跃状态,废弃域名直接跳过。
优化后的代码示例(核心部分)
import re import smtplib import dns.resolver import time import random from collections import defaultdict # 替换成你自己的真实邮箱 fromAddress = 'your-real-email@your-domain.com' regex = '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$' # 假设这是你的1000个邮箱列表 email_list = ['test1@domain.com', 'test2@domain.com', ...] # 按域名分组 domain_emails = defaultdict(list) for email in email_list: if re.match(regex, email): domain = email.split('@')[1] domain_emails[domain].append(email) else: print(f"{email} 语法错误,跳过") for domain, emails in domain_emails.items(): try: # MX记录查询 records = dns.resolver.query(domain, 'MX') mxRecord = str(records[0].exchange) # 建立SMTP连接,复用该连接验证当前域名下所有邮箱 server = smtplib.SMTP() server.set_debuglevel(0) server.connect(mxRecord) server.helo(server.local_hostname) server.mail(fromAddress) for email in emails: try: code, message = server.rcpt(email) if code == 250: print(f"{email} 验证成功") else: print(f"{email} 验证失败") # 加入随机延迟 time.sleep(random.randint(2, 5)) except Exception as e: print(f"{email} 验证出错: {str(e)}") time.sleep(3) server.quit() # 不同域名之间增加更长延迟 time.sleep(random.randint(5, 10)) except Exception as e: print(f"域名 {domain} 处理失败: {str(e)}") time.sleep(10)
内容的提问来源于stack exchange,提问作者NS009

