diff --git a/.env.example b/.env.example index ba95ff1..9455b79 100644 --- a/.env.example +++ b/.env.example @@ -17,6 +17,9 @@ PROXY_PORT=7897 # 代理超时时间 PROXY_TIMEOUT=10 + +# 临时邮箱类型 可选值:tempemail, zmail +EMAIL_TYPE=tempemail # 多个域名使用逗号分隔 EMAIL_DOMAINS=xxx.xx @@ -25,6 +28,14 @@ EMAIL_USERNAME=xxx # 临时邮箱PIN码(如果需要) EMAIL_PIN= +# ===== ZMail配置 ===== +# ZMail API地址 +EMAIL_API=https://xxxxxxxxxxxxxxx +# 是否启用邮箱API代理 +EMAIL_PROXY_ENABLED=True +# 邮箱API代理地址 +EMAIL_PROXY_ADDRESS=http://ip:port + # ===== 账号管理配置 ===== # 系统最大已激活的账号数量,如果达到这个数量,则停止注册 # so 要么在页面维护好当前已激活的账号,要么在页面删除账号,或者直接增大该值 diff --git a/api.py b/api.py index 8701cc8..a5f148c 100644 --- a/api.py +++ b/api.py @@ -1216,6 +1216,10 @@ async def get_config(): "BROWSER_HEADLESS": os.getenv("BROWSER_HEADLESS", "True").lower() == "true", "BROWSER_USER_AGENT": os.getenv("BROWSER_USER_AGENT", ""), "MAX_ACCOUNTS": int(os.getenv("MAX_ACCOUNTS", "10")), + "EMAIL_TYPE": os.getenv("EMAIL_TYPE", "tempemail"), + "EMAIL_PROXY_ENABLED": os.getenv("EMAIL_PROXY_ENABLED", "False").lower() == "true", + "EMAIL_PROXY_ADDRESS": os.getenv("EMAIL_PROXY_ADDRESS", ""), + "EMAIL_API": os.getenv("EMAIL_API", ""), "EMAIL_DOMAINS": os.getenv("EMAIL_DOMAINS", ""), "EMAIL_USERNAME": os.getenv("EMAIL_USERNAME", ""), "EMAIL_DOMAIN": os.getenv("EMAIL_DOMAIN", ""), diff --git a/config.py b/config.py index 4322ae1..dee25d2 100644 --- a/config.py +++ b/config.py @@ -53,6 +53,8 @@ SIGN_UP_URL = "https://authenticator.cursor.sh/sign-up" SETTINGS_URL = "https://www.cursor.com/settings" # ===== 邮箱配置 ===== +# 邮箱类型 +EMAIL_TYPE = os.getenv("EMAIL_TYPE", "tempemail") # 临时邮箱用户名 EMAIL_USERNAME = os.getenv("EMAIL_USERNAME", "xxx") # 临时邮箱域名 @@ -63,6 +65,12 @@ EMAIL_PIN = os.getenv("EMAIL_PIN", "") EMAIL_DOMAINS = [ domain.strip() for domain in os.getenv("EMAIL_DOMAINS", "xxx.xx").split(",") ] +# ZMail API地址 +EMAIL_API = os.getenv("EMAIL_API", "") +# 是否启用邮箱API代理 +EMAIL_PROXY_ENABLED = os.getenv("EMAIL_PROXY_ENABLED", "false").lower() == "true" +# 邮箱API代理地址 +EMAIL_PROXY_ADDRESS = os.getenv("EMAIL_PROXY_ADDRESS", "") # 邮件验证码获取最大重试次数 EMAIL_VERIFICATION_RETRIES = int(os.getenv("EMAIL_VERIFICATION_RETRIES", 5)) # 邮件验证码获取重试间隔(秒) diff --git a/cursor_pro_keep_alive.py b/cursor_pro_keep_alive.py index d1afa8e..40e9532 100644 --- a/cursor_pro_keep_alive.py +++ b/cursor_pro_keep_alive.py @@ -10,6 +10,7 @@ from config import ( SETTINGS_URL, EMAIL_DOMAINS, REGISTRATION_MAX_RETRIES, + EMAIL_TYPE ) @@ -150,6 +151,8 @@ def sign_up_account(browser, tab, account_info): info( f"账号信息: 邮箱: {account_info['email']}, 密码: {account_info['password']}, 姓名: {account_info['first_name']} {account_info['last_name']}" ) + if EMAIL_TYPE == "zmail": + EmailVerificationHandler.create_zmail_email(account_info) tab.get(SIGN_UP_URL) try: if tab.ele("@name=first_name"): diff --git a/get_email_code.py b/get_email_code.py index f605d1d..b97cdd9 100644 --- a/get_email_code.py +++ b/get_email_code.py @@ -8,20 +8,30 @@ from config import ( EMAIL_PIN, EMAIL_VERIFICATION_RETRIES, EMAIL_VERIFICATION_WAIT, + EMAIL_TYPE, + EMAIL_PROXY_ADDRESS, + EMAIL_PROXY_ENABLED, + EMAIL_API ) class EmailVerificationHandler: def __init__(self, username=None, domain=None, pin=None): + self.email = EMAIL_TYPE self.username = username or EMAIL_USERNAME self.domain = domain or EMAIL_DOMAIN self.session = requests.Session() + self.emailApi = EMAIL_API self.emailExtension = f"@{self.domain}" self.pin = pin or EMAIL_PIN - info( - f"初始化邮箱验证器成功: {self.username}{self.emailExtension} pin: {self.pin}" - ) - + if self.email == "tempemail": + info( + f"初始化邮箱验证器成功: {self.username}{self.emailExtension} pin: {self.pin}" + ) + elif self.email == "zmail": + info( + f"初始化邮箱验证器成功: {self.emailApi}" + ) def get_verification_code( self, source_email=None, max_retries=None, wait_time=None ): @@ -40,7 +50,11 @@ class EmailVerificationHandler: info(f"开始获取邮箱验证码=>最大重试次数:{max_retries}, 等待时间:{wait_time}") for attempt in range(max_retries): try: - code, mail_id = self._get_latest_mail_code(source_email) + info(f"当前EMail类型为: {EMAIL_TYPE}") + if self.email == "tempemail": + code, mail_id = self.get_tempmail_email_code(source_email) + elif self.email == "zmail": + code, mail_id = self.get_zmail_email_code(source_email) if code: info(f"成功获取验证码: {code}") return code @@ -58,7 +72,7 @@ class EmailVerificationHandler: return None # 手动输入验证码 - def _get_latest_mail_code(self, source_email=None): + def get_tempmail_email_code(self, source_email=None): info("开始获取邮件列表") # 获取邮件列表 mail_list_url = f"https://tempmail.plus/api/mails?email={self.username}{self.emailExtension}&limit=20&epin={self.pin}" @@ -145,3 +159,116 @@ class EmailVerificationHandler: time.sleep(0.2) return False + + # 如果是zmail 需要先创建邮箱 + def create_zmail_email(account_info): + # 如果邮箱类型是zmail 需要先创建邮箱 + session = requests.Session() + if EMAIL_PROXY_ENABLED: + proxy = { + "http": f"{EMAIL_PROXY_ADDRESS}", + "https": f"{EMAIL_PROXY_ADDRESS}", + } + session.proxies.update(proxy) + # 创建临时邮箱URL + create_url = f"{EMAIL_API}/api/mailboxes" + username = account_info["email"].split("@")[0] + # 生成临时邮箱地址 + payload = { + "address": f"{username}", + "expiresInHours": 24, + } + # 发送POST请求创建临时邮箱 + try: + create_response = session.post( + create_url, json=payload, timeout=100 + ) # 添加超时参数 + info(f"创建临时邮箱成功: {create_response.status_code}") + create_data = create_response.json() + info(f"创建临时邮箱返回数据: {create_data}") + # 检查创建邮箱是否成功 + time.sleep(0.5) + if create_data.get("success") is True or create_data.get('error') == '邮箱地址已存在': + info(f"邮箱创建成功: {create_data}") + else: + error(f"邮箱创建失败: {create_data}") + return None, None + except requests.exceptions.Timeout: + error("创建临时邮箱超时", create_url) + return None, None + info(f"创建临时邮箱成功: {create_data}, 返回值: {create_data}") + + # 获取zmail邮箱验证码 + def get_zmail_email_code(self, source_email=None): + info("开始获取邮件列表") + # 获取邮件列表 + username = source_email.split("@")[0] + mail_list_url = f"{EMAIL_API}/api/mailboxes/{username}/emails" + proxy = { + "http": f"{EMAIL_PROXY_ADDRESS}", + "https": f"{EMAIL_PROXY_ADDRESS}", + } + self.session.proxies.update(proxy) + try: + mail_list_response = self.session.get( + mail_list_url, timeout=10000 + ) # 添加超时参数 + mail_list_data = mail_list_response.json() + time.sleep(2) + if not mail_list_data.get("emails"): + return None, None + except requests.exceptions.Timeout: + error("获取邮件列表超时") + return None, None + except requests.exceptions.ConnectionError: + error("获取邮件列表连接错误") + return None, None + except Exception as e: + error(f"获取邮件列表发生错误: {str(e)}") + return None, None + + # 获取最新邮件的ID、 + mail_detail_data_len = len(mail_list_data["emails"]) + if mail_detail_data_len == 0: + return None, None + mail_list_data = mail_list_data["emails"][0] + # 获取最新邮件的ID + mail_id = mail_list_data.get("id") + if not mail_id: + return None, None + # 获取具体邮件内容 + mail_detail_url = f"{EMAIL_API}/api/emails/{mail_id}" + returnData = '' + try: + mail_detail_response = self.session.get( + mail_detail_url, timeout=10 + ) # 添加超时参数 + returnData = mail_detail_response.json() + time.sleep(2) + except requests.exceptions.Timeout: + error("获取邮件详情超时") + return None, None + except requests.exceptions.ConnectionError: + error("获取邮件详情连接错误") + return None, None + except Exception as e: + error(f"获取邮件详情发生错误: {str(e)}") + return None, None + + # 从邮件文本中提取6位数字验证码\ + mail_text = returnData.get("email") + mail_text = mail_text.get("textContent") + # 如果提供了source_email,确保邮件内容中包含该邮箱地址 + if source_email and source_email.lower() not in mail_text.lower(): + error(f"邮件内容不包含指定的邮箱地址: {source_email}") + else: + info(f"邮件内容包含指定的邮箱地址: {source_email}") + + code_match = re.search(r"(?