From 1bd3d120c1ffca5197ca8e63de3be0711ee655d7 Mon Sep 17 00:00:00 2001 From: kyx236 Date: Tue, 3 Feb 2026 08:59:49 +0800 Subject: [PATCH] feat: implement mail service client for email generation, mailbox creation, and verification code retrieval. --- backend/internal/mail/service.go | 70 +++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/backend/internal/mail/service.go b/backend/internal/mail/service.go index 7346378..e32ab03 100644 --- a/backend/internal/mail/service.go +++ b/backend/internal/mail/service.go @@ -355,30 +355,61 @@ func (m *Client) GetEmails(email string, size int) ([]EmailItem, error) { // WaitForCode 等待验证码邮件 func (m *Client) WaitForCode(email string, timeout time.Duration) (string, error) { start := time.Now() + // 匹配6位数字验证码 codeRegex := regexp.MustCompile(`\b(\d{6})\b`) + // 专门匹配 OpenAI 验证码邮件标题格式: "Your ChatGPT code is 016547" 或 "OpenAI - Verify your email" + titleCodeRegex := regexp.MustCompile(`(?i)(?:code\s+is\s+|code:\s*|验证码[::]\s*)(\d{6})`) + + // 记录已经看到的验证码,避免重复返回旧验证码 + seenCodes := make(map[string]bool) + + // 第一次获取邮件,记录已有的验证码(这些是旧的) + initialEmails, _ := m.GetEmails(email, 10) + for _, mail := range initialEmails { + // 从标题提取 + if matches := codeRegex.FindStringSubmatch(mail.Subject); len(matches) >= 2 { + seenCodes[matches[1]] = true + } + // 从内容提取 + content := mail.Content + if content == "" { + content = mail.Text + } + if matches := codeRegex.FindStringSubmatch(content); len(matches) >= 2 { + seenCodes[matches[1]] = true + } + } for time.Since(start) < timeout { emails, err := m.GetEmails(email, 10) if err == nil { for _, mail := range emails { subject := strings.ToLower(mail.Subject) - // 匹配多种可能的验证码邮件主题 - // 包括 "Your ChatGPT code is 016547" 格式 - isCodeEmail := strings.Contains(subject, "code") || - strings.Contains(subject, "verify") || - strings.Contains(subject, "verification") || + // 匹配 OpenAI/ChatGPT 验证码邮件 + // 标题格式: "Your ChatGPT code is 016547" 或包含 "verify", "code" 等 + isCodeEmail := strings.Contains(subject, "chatgpt code") || strings.Contains(subject, "openai") || - strings.Contains(subject, "confirm") || - strings.Contains(subject, "chatgpt") + strings.Contains(subject, "verify your email") || + (strings.Contains(subject, "code") && strings.Contains(subject, "is")) if !isCodeEmail { continue } - // 优先从标题中提取验证码 (如 "Your ChatGPT code is 016547") - matches := codeRegex.FindStringSubmatch(mail.Subject) - if len(matches) >= 2 { - return matches[1], nil + // 优先使用专门的标题正则匹配 (如 "Your ChatGPT code is 016547") + if matches := titleCodeRegex.FindStringSubmatch(mail.Subject); len(matches) >= 2 { + code := matches[1] + if !seenCodes[code] { + return code, nil + } + } + + // 从标题中提取6位数字 + if matches := codeRegex.FindStringSubmatch(mail.Subject); len(matches) >= 2 { + code := matches[1] + if !seenCodes[code] { + return code, nil + } } // 如果标题中没有,从内容中提取 @@ -386,9 +417,20 @@ func (m *Client) WaitForCode(email string, timeout time.Duration) (string, error if content == "" { content = mail.Text } - matches = codeRegex.FindStringSubmatch(content) - if len(matches) >= 2 { - return matches[1], nil + // 在内容中查找验证码,优先匹配 "enter this code:" 后面的数字 + contentCodeRegex := regexp.MustCompile(`(?i)(?:enter\s+this\s+code[::]\s*|code[::]\s*)(\d{6})`) + if matches := contentCodeRegex.FindStringSubmatch(content); len(matches) >= 2 { + code := matches[1] + if !seenCodes[code] { + return code, nil + } + } + // 最后尝试普通6位数字匹配 + if matches := codeRegex.FindStringSubmatch(content); len(matches) >= 2 { + code := matches[1] + if !seenCodes[code] { + return code, nil + } } } }