You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask部署服务器后SMTP发送邮件报400请求错误求助

Flask部署后SMTP发送带Zip附件邮件报400错误的排查方案

先修复代码中的致命错误

你的线程创建方式存在逻辑错误:

# 错误写法:直接调用函数,会在主线程同步执行而非子线程
thread = threading.Thread(target=send_mail(recipient_mail,filename))
# 正确写法:传入函数对象+参数
thread = threading.Thread(target=send_mail, args=(recipient_mail, filename))

原写法会导致send_mail在请求线程中立即执行,服务器请求结束后可能销毁应用上下文,引发后续操作失败。

分步排查与修复

1. 添加错误日志,定位具体问题

服务器环境无法直观看到报错细节,必须捕获并记录异常:

import logging
logging.basicConfig(filename='email_errors.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

def send_mail(recipient_mail,filename):
    with app.app_context():
        try:
            # 原函数所有业务代码放在这里
        except Exception as e:
            logging.error(f"发送邮件失败: {str(e)}", exc_info=True)
            return False

查看email_errors.log,可明确是文件操作失败、SMTP登录失败还是邮件格式问题。

2. 检查服务器文件权限与路径

  • 确认Flask运行用户(如www-data)对/home/mechatt.tk/converted/目录有读权限,对临时文件生成目录有读写权限
  • 用绝对路径替代相对路径,避免因服务器工作目录差异导致文件找不到:
    import os
    import uuid
    # 获取当前脚本所在目录
    base_dir = os.path.dirname(os.path.abspath(__file__))
    # 生成唯一临时目录/文件名,避免多线程冲突
    temp_dir = os.path.join(base_dir, f"temp_files_{uuid.uuid4().hex}")
    zip_file_path = os.path.join(base_dir, f"files_{uuid.uuid4().hex}.zip")
    

3. 验证Gmail SMTP配置

Gmail的SMTP安全限制严格,服务器环境易踩坑:

  • 必须使用应用专用密码:开启Google账户两步验证后,在账户安全设置中生成应用专用密码,替换原密码
  • 检查服务器出站端口:部分服务商封禁587端口,改用465端口(SSL)尝试:
    # 替换原SMTP连接代码
    with smtplib.SMTP_SSL(Constants.SMTP_SERVER, 465) as server:
        server.login(Constants.SENDER_EMAIL, Constants.SENDER_PASSWORD)
        server.sendmail(Constants.SENDER_EMAIL, recipient_mail, message.as_string())
    
  • 确认Gmail账户未限制第三方应用访问:检查账户是否因异常登录保护拦截了SMTP请求

4. 规范邮件格式,避免编码问题

服务器环境字符编码可能与本地不同,优化邮件头编码:

from email.header import Header
# 替换主题设置,确保编码正确
message['Subject'] = Header('Zip文件包含请求内容', 'utf-8')
# 提前校验收件人邮箱格式
if not recipient_mail or '@' not in recipient_mail:
    logging.error(f"无效收件人邮箱: {recipient_mail}")
    return

5. 优化临时文件清理逻辑

原代码仅在发送成功后清理文件,失败时会残留文件,建议用try-finally确保清理:

def send_mail(recipient_mail,filename):
    with app.app_context():
        temp_dir = None
        zip_file_path = None
        try:
            # 创建临时目录、生成zip等业务逻辑
            temp_dir = os.path.join(base_dir, f"temp_files_{uuid.uuid4().hex}")
            zip_file_path = os.path.join(base_dir, f"files_{uuid.uuid4().hex}.zip")
            # ... 其余代码
        except Exception as e:
            logging.error(f"发送邮件失败: {str(e)}", exc_info=True)
        finally:
            # 无论成功失败都清理临时文件
            if zip_file_path and os.path.exists(zip_file_path):
                os.remove(zip_file_path)
            if temp_dir and os.path.exists(temp_dir):
                shutil.rmtree(temp_dir)

内容的提问来源于stack exchange,提问作者Ashmit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:15:40