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)
相关推荐
张高兴39 分钟前
张高兴的 Hailo-10 开发指南:(二)使用 LangChain 搭建本地大模型 RAG 问答应用
python·边缘计算·hailo
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月6日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能
Land03291 小时前
Python + RPA 双引擎实战:从手写脚本到可交付自动化应用的完整链路
python·自动化·rpa
菜到离谱但坚持1 小时前
【小白零基础】RAG+LangChain 搭建私有知识库问答系统(完整可运行代码+超详细教程+避坑指南)
python·langchain·rag
ss2732 小时前
【入门OJ题解】分苹果问题(Python/Java/C 实现)
java·c语言·python
IsJunJianXin2 小时前
谷歌搜索cookie NID逆向生成
开发语言·python·google搜索·sgss·nid-cookie·算法生成nid·google-cookie
暗夜猎手-大魔王2 小时前
转载--Hermes Agent 11 | 智能审批与平台化安全:当 AI 来守护 AI
人工智能·python·安全
AIFQuant2 小时前
量化私募回测系统:高质量股票/外汇历史数据 API 选型与接入
python·websocket·金融·ai量化
Mr.Daozhi2 小时前
Playwright实战:抓取Meta Ad Library动态页面的三级降级策略
爬虫·python·自动化·playwright·meta广告
财经资讯数据_灵砚智能2 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月5日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能