feat:新增开源无限邮箱类型zmail、动态配置选择邮箱类型

This commit is contained in:
初衷
2025-03-28 15:27:52 +08:00
parent 594417b1d5
commit 9477320e76
8 changed files with 228 additions and 16 deletions

View File

@@ -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 要么在页面维护好当前已激活的账号,要么在页面删除账号,或者直接增大该值

4
api.py
View File

@@ -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", ""),

View File

@@ -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))
# 邮件验证码获取重试间隔(秒)

View File

@@ -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"):

View File

@@ -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"(?<![a-zA-Z@.])\b\d{6}\b", mail_text)
info(f"验证码匹配结果: {code_match}")
# 如果找到验证码, 返回验证码和邮件ID
if code_match:
return code_match.group(), mail_id
else:
error("未找到验证码")
return None, None

View File

@@ -344,21 +344,56 @@
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="email-type" class="form-label">邮箱类型</label>
<select id="email-type" class="form-control" disabled>
<option value="tempemail">TempEmail</option>
<option value="zmail">ZMail</option>
</select>
<small class="text-muted">选择用于注册的临时邮箱服务类型</small>
</div>
<div class="mb-3">
<label for="email-domains" class="form-label">邮箱域名</label>
<input type="text" id="email-domains" class="form-control" disabled>
<small class="text-muted">用于注册的邮箱域名,多个域名用逗号分隔</small>
</div>
<div class="mb-3">
<label for="email-username" class="form-label">临时邮箱用户名</label>
<input type="text" id="email-username" class="form-control" placeholder="加载中...">
<small class="text-muted">用于接收验证码的临时邮箱用户名(不需要输入@及后面的部分)</small>
<!-- TempEmail相关字段 -->
<div id="tempemail-fields">
<div class="mb-3">
<label for="email-username" class="form-label">临时邮箱用户名</label>
<input type="text" id="email-username" class="form-control" placeholder="加载中...">
<small class="text-muted">用于接收验证码的临时邮箱用户名(不需要输入@及后面的部分)</small>
</div>
<div class="mb-3">
<label for="email-pin" class="form-label">临时邮箱PIN</label>
<input type="text" id="email-pin" class="form-control" disabled>
<small class="text-muted">临时邮箱PIN码如果需要</small>
</div>
</div>
<div class="mb-3">
<label for="email-pin" class="form-label">临时邮箱PIN</label>
<input type="text" id="email-pin" class="form-control" disabled>
<small class="text-muted">临时邮箱PIN码如果需要</small>
<!-- ZMail相关字段 -->
<div id="zmail-fields" style="display: none;">
<div class="mb-3">
<label for="email-api" class="form-label">邮箱API</label>
<input type="text" id="email-api" class="form-control" disabled>
<small class="text-muted">ZMail API地址</small>
</div>
<div class="mb-3">
<label for="email-proxy-enabled" class="form-label">邮箱代理</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="email-proxy-enabled" disabled>
<label class="form-check-label" for="email-proxy-enabled">启用邮箱代理</label>
</div>
<small class="text-muted">是否启用邮箱API代理</small>
</div>
<div class="mb-3" id="email-proxy-address-container">
<label for="email-proxy-address" class="form-label">邮箱代理地址</label>
<input type="text" id="email-proxy-address" class="form-control" disabled>
<small class="text-muted">邮箱API代理服务器地址</small>
</div>
</div>
<div class="mb-3">
<label for="browser-path" class="form-label">浏览器路径 (可选)</label>
<input type="text" id="browser-path" class="form-control" disabled>
@@ -369,7 +404,6 @@
<input type="text" id="cursor-path" class="form-control" disabled>
<small class="text-muted">Cursor安装目录的完整路径</small>
</div>
</div>
</div>
<!-- 在系统配置表单中添加代理设置部分 -->
<div class="config-section card mb-3">

View File

@@ -1196,7 +1196,22 @@ function loadConfig() {
}
}
$("#email-type").val(config.EMAIL_TYPE);
$("#email-proxy-enabled").prop('checked', config.EMAIL_PROXY_ENABLED || false);
if (config.EMAIL_PROXY_ENABLED) {
$("#email-proxy-address").val(config.EMAIL_PROXY_ADDRESS);
$("#email-api").val(config.EMAIL_API);
}
if (config.EMAIL_TYPE == "tempemail") {
$("#tempemail-fields").show();
$("#zmail-fields").hide();
} else if (config.EMAIL_TYPE == "zmail") {
$("#tempemail-fields").hide();
$("#zmail-fields").show();
}
hideLoading();
} else {
showAlert('danger', '加载配置失败: ' + response.message);
hideLoading();

View File

@@ -66,4 +66,14 @@ $(window).resize(function() {
if ($(window).width() > 576) {
$('body').removeClass('sidebar-open');
}
});
});
$("#email-type").change(function() {
if ($(this).val() === "tempemail") {
$("#tempemail-fields").show();
$("#zmail-fields").hide();
} else if ($(this).val() === "zmail") {
$("#tempemail-fields").hide();
$("#zmail-fields").show();
}
});