Python邮箱工具类封装:高效邮件发送与管理

python 复制代码
"""
邮箱工具模块

提供:
1. EmailClient - 邮箱客户端类(封装SMTP连接池)
2. 各种邮件模板生成函数
"""
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from flask import current_app


class EmailClient:
    """邮箱客户端(SMTP连接管理)"""

    @staticmethod
    def _get_config():
        """获取邮件配置"""
        return {
            'server': current_app.config.get('MAIL_SERVER', 'smtp.qq.com'),
            'port': current_app.config.get('MAIL_PORT', 587),
            'use_tls': current_app.config.get('MAIL_USE_TLS', True),
            'use_ssl': current_app.config.get('MAIL_USE_SSL', False),
            'username': current_app.config.get('MAIL_USERNAME'),
            'password': current_app.config.get('MAIL_PASSWORD'),
            'default_sender': current_app.config.get('MAIL_DEFAULT_SENDER'),
        }

    @classmethod
    def send(cls, to_email, subject, body_html, body_text=None):
        """
        发送邮件

        Args:
            to_email: 收件人邮箱
            subject: 邮件主题
            body_html: HTML格式邮件正文
            body_text: 纯文本格式邮件正文(可选)

        Returns:
            bool: 发送是否成功
        """
        try:
            config = cls._get_config()

            if not config['username'] or not config['password']:
                current_app.logger.error("邮件配置不完整:缺少MAIL_USERNAME或MAIL_PASSWORD")
                return False

            msg = MIMEMultipart('alternative')
            msg['Subject'] = subject
            msg['From'] = config['default_sender'] or config['username']
            msg['To'] = to_email

            if body_text:
                msg.attach(MIMEText(body_text, 'plain', 'utf-8'))
            msg.attach(MIMEText(body_html, 'html', 'utf-8'))

            if config['use_ssl']:
                server = smtplib.SMTP_SSL(config['server'], config['port'])
            else:
                server = smtplib.SMTP(config['server'], config['port'])
                if config['use_tls']:
                    server.starttls()

            server.login(config['username'], config['password'])
            server.sendmail(msg['From'], [to_email], msg.as_string())
            server.quit()

            current_app.logger.info(f"邮件发送成功: {to_email}")
            return True

        except Exception as e:
            current_app.logger.error(f"邮件发送失败: {to_email}, 错误: {str(e)}")
            return False

    @classmethod
    def send_verification_email(cls, user, verification_url, token):
        """
        发送注册验证邮件

        Args:
            user: 用户对象(需包含username和email属性)
            verification_url: 验证链接
            token: 验证令牌

        Returns:
            bool: 发送是否成功
        """
        subject = '房屋租赁系统 - 邮箱验证'

        html_content = f"""
        <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; }}
                    .header {{ background-color: #5b6bf8; color: white; padding: 20px; text-align: center; border-radius: 8px; }}
                    .content {{ padding: 20px; background-color: #f9f9f9; border-radius: 8px; margin-top: 20px; }}
                    .button {{ display: inline-block; background-color: #5b6bf8; color: white; padding: 12px 30px; text-decoration: none; border-radius: 6px; margin: 20px 0; }}
                    .token-box {{ background-color: #fff; border: 2px dashed #5b6bf8; border-radius: 8px; padding: 20px; margin: 20px 0; text-align: center; }}
                    .token-label {{ color: #666; font-size: 14px; margin-bottom: 10px; }}
                    .token-code {{ font-size: 28px; font-weight: bold; color: #5b6bf8; letter-spacing: 3px; word-break: break-all; background-color: #f0f4ff; padding: 12px; border-radius: 6px; margin: 10px 0; }}
                    .copy-hint {{ color: #999; font-size: 12px; margin-top: 10px; }}
                    .footer {{ text-align: center; margin-top: 20px; color: #666; font-size: 12px; }}
                </style>
            </head>
            <body>
                <div class="header">
                    <h1>欢迎加入房屋租赁系统</h1>
                </div>
                <div class="content">
                    <h2>尊敬的 {user.username},您好!</h2>
                    <p>感谢您注册房屋租赁系统。为了完成注册,请点击下方按钮验证您的邮箱:</p>
                    <div style="text-align: center;">
                        <a href="{verification_url}" class="button">验证邮箱</a>
                    </div>

                    <div class="token-box">
                        <p class="token-label">您的验证令牌(可直接复制):</p>
                        <div class="token-code">{token}</div>
                        <p class="copy-hint">请复制上方令牌,在验证页面输入完成验证</p>
                    </div>

                    <p>如果按钮无法点击,请复制以下链接到浏览器地址栏:</p>
                    <p style="word-break: break-all; color: #666; font-size: 12px;">{verification_url}</p>
                    <p>本验证链接有效期为 24 小时,过期后请重新申请。</p>
                </div>
                <div class="footer">
                    <p>此邮件由系统自动发送,请勿直接回复。</p>
                </div>
            </body>
        </html>
        """

        return cls.send(user.email, subject, html_content)

    @classmethod
    def send_verification_code(cls, to_email, code, purpose='忘记密码'):
        """
        发送验证码邮件

        Args:
            to_email: 收件人邮箱
            code: 验证码
            purpose: 验证码用途(默认:忘记密码)

        Returns:
            bool: 发送是否成功
        """
        subject = f'房屋租赁系统 - {purpose}验证码'

        html_content = f"""
        <html>
            <head>
                <style>
                    body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px; }}
                    .header {{ background-color: #5b6bf8; color: white; padding: 20px; text-align: center; border-radius: 8px; }}
                    .content {{ padding: 20px; background-color: #f9f9f9; border-radius: 8px; margin-top: 20px; }}
                    .token-box {{ background-color: #fff; border: 2px dashed #5b6bf8; border-radius: 8px; padding: 20px; margin: 20px 0; text-align: center; }}
                    .token-label {{ color: #666; font-size: 14px; margin-bottom: 10px; }}
                    .token-code {{ font-size: 36px; font-weight: bold; color: #5b6bf8; letter-spacing: 5px; background-color: #f0f4ff; padding: 15px; border-radius: 6px; margin: 10px 0; }}
                    .copy-hint {{ color: #999; font-size: 12px; margin-top: 10px; }}
                    .footer {{ text-align: center; margin-top: 20px; color: #666; font-size: 12px; }}
                </style>
            </head>
            <body>
                <div class="header">
                    <h1>{purpose} - 验证码</h1>
                </div>
                <div class="content">
                    <h2>您好!</h2>
                    <p>您正在进行{purpose}操作,请使用以下验证码完成操作:</p>

                    <div class="token-box">
                        <p class="token-label">您的验证码:</p>
                        <div class="token-code">{code}</div>
                        <p class="copy-hint">请在5分钟内使用此验证码</p>
                    </div>

                    <p>如果您没有进行此操作,请忽略此邮件。</p>
                </div>
                <div class="footer">
                    <p>此邮件由系统自动发送,请勿直接回复。</p>
                </div>
            </body>
        </html>
        """

        return cls.send(to_email, subject, html_content)
相关推荐
子午1 小时前
基于YOLO的水稻害虫检测系统~Python+yolov8算法+深度学习+人工智能+模型训练
人工智能·python·yolo
我命由我123451 小时前
Android Framework P2 - 开机启动 Zygote 进程、Zygote 的预加载机制
android·java·开发语言·python·java-ee·intellij-idea·zygote
2401_850491651 小时前
PHP 中处理会话数组时的类型错误解析与修复指南
jvm·数据库·python
ㄟ留恋さ寂寞1 小时前
如何修改数据库实例名_ORACLE_SID环境变量重命名实战
jvm·数据库·python
2401_850491651 小时前
使用 curl 调用 Go 标准库 RPC 服务(JSON-RPC 协议详解)
jvm·数据库·python
平常心cyk2 小时前
OpenAI库的基本使用
python
深度学习lover2 小时前
<数据集>yolo 笔识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·笔识别
熊猫钓鱼>_>2 小时前
Q-Learning详解:从理论到实战的完整指南
人工智能·python·架构·大模型·llm·machine learning·q-learning
墨月白2 小时前
【Python】程序设计基本方法
开发语言·python