Python命令行邮件发送工具如何实现附件上传百分比进度条
可行性结论
- 附件上传百分比进度的展示需求完全可以实现,但
smtplib没有提供内置的进度回调方法,需要通过改造现有全量发送的逻辑自主统计进度。 - 你当前代码的实现方式存在进度感知的根本限制:
server.sendmail()会一次性把全部组装好的邮件内容(含所有附件)交给底层网络连接传输,程序完全拿不到分块发送的实时字节数。
实现思路
- 提前将组装完成的MIME消息序列化为字节流,统计总长度作为进度计算的分母。
- 绕开
sendmail()的全量传输封装,按照SMTP协议的会话流程,把完整的邮件字节流拆成固定大小的分块,逐块写入底层网络连接;每写完一个分块就累计已发送的字节数,实时计算上传百分比并输出。 - 传输过程中的SMTP协议特殊字符转义、会话状态校验直接复用
smtplib的内置能力,不需要手动实现协议细节。
参考实现代码
替换原有sendmail逻辑的可运行示例:
# 提前序列化全量邮件内容并统计大小 total_email_content = message.as_bytes() total_email_size = len(total_email_content) sent_size = 0 # 常规选择4KB-16KB的分块大小,兼顾传输效率和进度刷新频率 CHUNK_SIZE = 4096 context = ssl.create_default_context() with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server: server.login(sender_email, password) # 按SMTP协议流程推进会话状态 server.mail(sender_email) server.rcpt(receiver_email) # 进入数据传输阶段 server.data(b"", first=True) # 分块发送内容 for offset in range(0, total_email_size, CHUNK_SIZE): chunk = total_email_content[offset:offset+CHUNK_SIZE] server.send(chunk) sent_size += len(chunk) # 单行刷新进度,避免控制台重复刷屏 progress = sent_size / total_email_size * 100 print(f"\r上传进度: {progress:.2f}%", end="", flush=True) # 发送数据结束标记,完成邮件提交 server.data(b".\r\n") print("\n邮件发送成功")
关键提示
- 上述统计的是整个邮件内容的传输进度,由于附件经过base64编码后通常占邮件总大小的90%以上,最终的进度数值和附件实际的上传完成度高度匹配,完全符合需求。
- 不要跳过SMTP的会话状态校验直接写socket内容,否则会触发服务器的协议报错,导致发送失败。
- 如果需要单独区分正文和附件的上传进度,可以在组装MIME消息时提前记录附件编码内容在全量字节流中的起始、结束偏移量,在进度计算时单独映射对应区间的进度。
内容的提问来源于stack exchange,提问作者Nimrod
相关产品推荐
相关产品推荐

