1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
邮件发送服务
"""
 
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from typing import List, Optional
from loguru import logger
from config import settings
 
 
class EmailService:
    """邮件发送服务"""
 
    def __init__(self):
        self.smtp_server = settings.email_smtp_server
        self.smtp_port = settings.email_smtp_port
        self.username = settings.email_smtp_username
        self.password = settings.email_smtp_password
        self.from_email = settings.email_from_email
 
    def send_email(self, to_emails: List[str], subject: str, content: str) -> bool:
        """
        发送邮件
 
        Args:
            to_emails: 收件人邮箱列表
            subject: 邮件主题
            content: 邮件内容
 
        Returns:
            发送成功返回True,失败返回False
        """
        if not settings.email_enabled:
            logger.info("邮件发送功能已禁用")
            return True
 
        if not to_emails:
            logger.warning("收件人邮箱列表为空")
            return False
 
        try:
            # 创建邮件对象
            msg = MIMEMultipart()
            msg["From"] = self.from_email
            msg["To"] = ", ".join(to_emails)
            msg["Subject"] = subject
 
            # 添加邮件内容
            msg.attach(MIMEText(content, "plain", "utf-8"))
 
            # 连接SMTP服务器并发送邮件
            server = None
            email_sent = False
 
            try:
                server = smtplib.SMTP(self.smtp_server, self.smtp_port)
                server.starttls()  # 启用TLS加密
                server.login(self.username, self.password)
 
                # 发送邮件
                text = msg.as_string()
                server.sendmail(self.from_email, to_emails, text)
                email_sent = True
 
                logger.info(f"邮件发送成功: to={to_emails}, subject={subject}")
 
            finally:
                # 安全关闭连接,忽略关闭时的异常
                if server:
                    try:
                        server.quit()
                    except Exception:
                        # 忽略关闭连接时的异常,因为邮件可能已经发送成功
                        pass
 
            return email_sent
 
        except smtplib.SMTPAuthenticationError as e:
            logger.error(f"邮件发送认证失败: error={str(e)}")
            return False
        except smtplib.SMTPException as e:
            logger.error(f"邮件发送SMTP错误: error={str(e)}")
            return False
        except Exception as e:
            logger.error(f"邮件发送异常: error={str(e)}")
            return False
 
    def send_notification(self, subject: str, content: str) -> bool:
        """
        发送通知邮件到配置的收件人列表
 
        Args:
            subject: 邮件主题
            content: 邮件内容
 
        Returns:
            发送成功返回True,失败返回False
        """
        return self.send_email(settings.email_to_emails, subject, content)
 
    def test_connection(self) -> bool:
        """
        测试邮件服务器连接
 
        Returns:
            连接成功返回True,失败返回False
        """
        if not settings.email_enabled:
            logger.info("邮件发送功能已禁用")
            return True
 
        try:
            server = None
            connection_success = False
 
            try:
                server = smtplib.SMTP(self.smtp_server, self.smtp_port)
                server.starttls()
                server.login(self.username, self.password)
                connection_success = True
 
                logger.info("邮件服务器连接测试成功")
 
            finally:
                # 安全关闭连接,忽略关闭时的异常
                if server:
                    try:
                        server.quit()
                    except Exception:
                        # 忽略关闭连接时的异常
                        pass
 
            return connection_success
 
        except smtplib.SMTPAuthenticationError as e:
            logger.error(f"邮件服务器认证失败: error={str(e)}")
            return False
        except smtplib.SMTPException as e:
            logger.error(f"邮件服务器连接SMTP错误: error={str(e)}")
            return False
        except Exception as e:
            logger.error(f"邮件服务器连接异常: error={str(e)}")
            return False
 
 
# 全局邮件服务实例
email_service = EmailService()