资讯动态

Python发送邮件和短信:基于smtplib与短信网关的自动化通知实战

发布时间:2026/10/14 2:01:35 来源:尧图企业网站定制
教程文档【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址https://gitcode.com/capable-ai/Python-100-Days点击查看免费下载发送邮件和短信是自动化办公与Web项目中最常见的需求之一程序生成好 Excel、Word、PDF 文档后需要通过邮件投递给指定收件人再用短信告知对方邮件已发出。本篇教程基于 Python-100-Days 项目 Day29 文档 展开完整讲解如何用标准库smtplib通过 SMTP 协议发送纯文本邮件与带附件邮件以及如何调用第三方短信网关螺丝帽发送验证码短信并结合仓库中 Django 项目的真实接入代码给出从能跑到能上线的完整方案。一、发送电子邮件从 SMTP 协议到 smtplib在即时通信软件如此发达的今天电子邮件仍然是互联网上使用最为广泛的应用之一公司向应聘者发出录用通知、网站向用户发送激活账号的链接、银行向客户推广理财产品几乎都通过电子邮件完成而这些任务大多由程序自动执行。1.1 SMTP 协议与 smtplib 模块用 HTTP超文本传输协议访问网站资源时HTTP 是建立在 TCP传输控制协议之上的应用级协议而发送电子邮件需要的是SMTP简单邮件传输协议它同样是建立在 TCP 之上的应用级协议规定了邮件的发送者如何与邮件服务器通信的细节。Python 通过名为smtplib的标准库模块将底层通信细节简化成了SMTP_SSL对象。开发者的核心工作只有两步通过SMTP_SSL(host, port)创建对象并连接邮件服务器调用对象的login方法登录、sendmail方法发送邮件。SMTP_SSL表示通过 SSL/TLS 加密通道连接服务器这是目前主流邮件服务商如 126、QQ、163 邮箱普遍采用的 465 端口默认方式。1.2 准备工作开启邮箱 SMTP 服务并获取授权码发送邮件首先需要接入邮件服务器。自建邮件服务器对新手并不友好因此更常见的做法是使用第三方提供的邮件服务。以 126 邮箱www.126.com为例注册账号并登录成功后在设置中开启SMTP 服务就等于获得了一个可用的邮件服务器。开启过程中邮箱会要求通过手机短信获取一个授权码见下图。授权码需要妥善保管一旦泄露就可能被他人冒用你的身份发送邮件。代码中用于login的密码不是邮箱登录密码而是这个授权码。1.3 发送一封简单的纯文本邮件下面这段代码演示了发送一封不含附件、图片及其他超文本内容的邮件。要点说明如下MIMEMultipart()创建邮件主体对象用于承载正文与附件等多个部分通过给email[From]、email[To]、email[Subject]赋值设置发件人、收件人和主题其中主题用email.header.Header包裹并指定 UTF-8 编码以正确支持中文MIMEText(content, plain, utf-8)构造纯文本正文并attach到邮件主体收件人支持多个sendmail的第二个参数传入收件人列表即可。import smtplib from email.header import Header from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText # 创建邮件主体对象 email MIMEMultipart() # 设置发件人、收件人和主题 email[From] xxxxxxxxx126.com email[To] yyyyyyqq.com;zzzzzz1000phone.com email[Subject] Header(上半年工作情况汇报, utf-8) # 添加邮件正文内容 content 据德国媒体报道当地时间9日德国火车司机工会成员进行了投票 定于当地时间10日起进行全国性罢工货运交通方面的罢工已于当地时间10日19时开始。 此后从11日凌晨2时到13日凌晨2时德国全国范围内的客运和铁路基础设施将进行48小时的罢工。 email.attach(MIMEText(content, plain, utf-8)) # 创建SMTP_SSL对象连接邮件服务器 smtp_obj smtplib.SMTP_SSL(smtp.126.com, 465) # 通过用户名和授权码进行登录 smtp_obj.login(xxxxxxxxx126.com, 邮件服务器的授权码) # 发送邮件发件人、收件人、邮件内容字符串 smtp_obj.sendmail( xxxxxxxxx126.com, [yyyyyyqq.com, zzzzzz1000phone.com], email.as_string() )注意email[To]中多个收件人用英文分号;分隔sendmail的第二个参数需要收件人列表。代码中的邮箱地址与授权码均为示例实际运行时需替换为自己的真实信息。1.4 发送带附件的邮件BASE64 编码与中文文件名处理如果要发送带附件的邮件只需将附件内容处理成BASE64 编码它就和普通文本内容几乎没有什么区别。BASE64 是一种基于 64 个可打印字符来表示二进制数据的表示方法常用于需要表示、传输、存储二进制数据的场合电子邮件就是其中之一。Python 标准库的base64模块提供了对 BASE64 编解码的支持。处理附件时还有两个容易被忽视的细节内容类型声明给附件设置content-type: application/octet-stream表示这是一个二进制文件流中文文件名转码邮件头中的文件名必须符合编码规范直接写入中文会导致乱码需要借助urllib.parse.quote将中文文件名处理成百分号编码后再放入content-disposition。import smtplib from email.header import Header from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from urllib.parse import quote # 创建邮件主体对象 email MIMEMultipart() # 设置发件人、收件人和主题 email[From] xxxxxxxxx126.com email[To] zzzzzzzz1000phone.com email[Subject] Header(请查收离职证明文件, utf-8) # 添加邮件正文内容带HTML标签排版的内容 content p亲爱的前同事/p p你需要的离职证明在附件中请查收/p br p祝好/p hr p孙美丽 即日/p email.attach(MIMEText(content, html, utf-8)) # 读取作为附件的文件 with open(fresources/王大锤离职证明.docx, rb) as file: attachment MIMEText(file.read(), base64, utf-8) # 指定内容类型 attachment[content-type] application/octet-stream # 将中文文件名处理成百分号编码 filename quote(王大锤离职证明.docx) # 指定如何处置内容 attachment[content-disposition] fattachment; filename{filename} # 创建SMTP_SSL对象连接邮件服务器 smtp_obj smtplib.SMTP_SSL(smtp.126.com, 465) # 通过用户名和授权码进行登录 smtp_obj.login(xxxxxxxxx126.com, 邮件服务器的授权码) # 发送邮件发件人、收件人、邮件内容字符串 smtp_obj.sendmail( xxxxxxxxx126.com, zzzzzzzz1000phone.com, email.as_string() )上面的示例中正文使用了html类型MIMEText允许你传入带有 HTML 标签排版的内容邮件客户端会按网页格式渲染正文——这比纯文本邮件更适合正式的商务通知场景。1.5 封装为通用函数一套代码适配多场景为了方便复用Day29 文档把上述逻辑封装成了send_email函数。使用时只需要调整邮件服务器域名、端口、用户名和授权码四个常量即可发送任意主题、正文和附件的邮件import smtplib from email.header import Header from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from urllib.parse import quote # 邮件服务器域名自行修改 EMAIL_HOST smtp.126.com # 邮件服务端口通常是465 EMAIL_PORT 465 # 登录邮件服务器的账号自行修改 EMAIL_USER xxxxxxxxx126.com # 开通SMTP服务的授权码自行修改 EMAIL_AUTH 邮件服务器的授权码 def send_email(*, from_user, to_users, subject, content, filenames[]): 发送邮件 :param from_user: 发件人 :param to_users: 收件人多个收件人用英文分号进行分隔 :param subject: 邮件的主题 :param content: 邮件正文内容 :param filenames: 附件要发送的文件路径 email MIMEMultipart() email[From] from_user email[To] to_users email[Subject] subject message MIMEText(content, plain, utf-8) email.attach(message) for filename in filenames: with open(filename, rb) as file: pos filename.rfind(/) display_filename filename[pos 1:] if pos 0 else filename display_filename quote(display_filename) attachment MIMEText(file.read(), base64, utf-8) attachment[content-type] application/octet-stream attachment[content-disposition] fattachment; filename{display_filename} email.attach(attachment) smtp smtplib.SMTP_SSL(EMAIL_HOST, EMAIL_PORT) smtp.login(EMAIL_USER, EMAIL_AUTH) smtp.sendmail(from_user, to_users.split(;), email.as_string())这个封装的几个细节值得学习filenames是附件文件路径列表函数用for循环逐个读取、转码、挂载天然支持批量发送多个附件通过filename.rfind(/)从完整路径中取出纯文件名再用quote处理中文避免把目录路径暴露给收件人收件人to_users以英文分号分隔函数内部用split(;)还原成列表与上面sendmail需要的列表参数对齐。二、发送短信接入第三方短信网关发送短信同样是项目中常见的功能网站的注册码、验证码、营销信息基本都通过短信下发给用户。发送短信需要第三方平台的支持Day29 文档以螺丝帽平台为例介绍接入方式仓库中的 Django 项目文档 则给出了完整的后台配置与生产级调用细节。2.1 平台准备API Key、短信签名与 IP 白名单在螺丝帽平台发送短信需要先在管理后台完成以下几项配置详见 57.接入三方平台.md注册账号新用户一般可免费试用登录管理后台进入短信版块点击触发发送获取专属的API Key身份标识代码中作为 HTTP Basic Auth 的凭证在签名管理中添加短信签名——几乎所有平台都强制要求短信携带签名免费试用的短信必须使用平台指定的签名如【铁壳测试】否则短信无法发送在IP 白名单中填写服务器公网 IP 地址本地运行时需查询本机公网 IP否则请求会被平台拒绝短信条数用完需到充值页面购买短信服务。在 Day29 文档的示例中签名配置为【Python小课】涉及敏感内容的短信还需要提前配置短信模板未在签名管理中加入该签名、或短信内容违反平台规则都会导致发送失败。2.2 用 requests 调用短信网关接下来通过requests库向平台提供的短信网关发起一个 HTTP POST 请求将接收短信的手机号和短信内容作为参数即可发送短信。以螺丝帽为例网关地址为http://sms-api.luosimao.com/v1/send.json请求使用 HTTP Basic Auth 认证用户名固定为api密码是平台分配的 Keyimport random import requests def send_message_by_luosimao(tel, message): 发送短信调用螺丝帽短信网关 resp requests.post( urlhttp://sms-api.luosimao.com/v1/send.json, auth(api, key-注册成功后平台分配的KEY), data{ mobile: tel, message: message }, timeout10, verifyFalse ) return resp.json() def gen_mobile_code(length6): 生成指定长度的手机验证码 return .join(random.choices(0123456789, klength)) def main(): code gen_mobile_code() message f您的短信验证码是{code}打死也不能告诉别人哟【Python小课】 print(send_message_by_luosimao(13500112233, message)) if __name__ __main__: main()代码中的两个函数各自职责清晰send_message_by_luosimao负责与网关通信timeout10防止请求长时间挂起verifyFalse关闭 HTTPS 证书校验短信网关接口通常为 HTTP生产环境建议结合网络环境评估是否需要校验gen_mobile_code用random.choices从0123456789中随机抽取指定位数默认 6 位的数字生成短信验证码。2.3 响应解析与常见错误码请求螺丝帽短信网关会返回 JSON 格式的数据如果返回{error: 0, msg: OK}说明短信发送成功如果error的值不是0则发送失败需要根据错误码排查问题。螺丝帽平台常见的错误类型如下表所示error字段取值含义说明error为0发送成功余额不足需在平台充值短信服务缺少短信签名短信内容未携带已配置的签名如【铁壳测试】IP 不在白名单请求来源 IP 未加入IP 白名单提示不同平台返回字段略有差异。例如仓库中 57.接入三方平台.md 提到螺丝帽的另一种返回格式为{err: 0, msg: ok}err而非error其中-20表示余额不足、-32表示缺少短信签名。实际接入时以所用平台当前版本的开发文档为准。2.4 结合仓库源码短信验证码在 Web 项目中的完整落地Day29 文档介绍了发送短信的基础能力而仓库中 57.接入三方平台.md 进一步给出了它在 Django 项目中的生产级用法可作为验证码短信功能的完整参考。首先发送前应先校验手机号合法性并用正则匹配中国大陆手机号import random import re TEL_PATTERN re.compile(r1[3-9]\d{9}) def check_tel(tel): 检查手机号 return TEL_PATTERN.fullmatch(tel) is not None def random_code(length6): 生成随机短信验证码 return .join(random.choices(0123456789, klength))然后在视图函数中调用发送函数并利用Redis实现两个生产环境必备的约束防刷屏通过键vote:block-mobile:{tel}设置 60 秒过期时间阻止用户在 60 秒内重复发送验证码验证码时效通过键vote2:valid-mobile:{tel}将验证码在 Redis 中保留 10 分钟即验证码有效期只有 10 分钟。api_view((GET, )) def get_mobilecode(request, tel): 获取短信验证码 if check_tel(tel): redis_cli get_redis_connection() if redis_cli.exists(fvote:block-mobile:{tel}): data {code: 30001, message: 请不要在60秒内重复发送短信验证码} else: code random_code() send_mobile_code(tel, code) # 通过Redis阻止60秒内容重复发送短信验证码 redis_cli.set(fvote:block-mobile:{tel}, x, ex60) # 将验证码在Redis中保留10分钟有效期10分钟 redis_cli.set(fvote2:valid-mobile:{tel}, code, ex600) data {code: 30000, message: 短信验证码已发送请注意查收} else: data {code: 30002, message: 请输入有效的手机号} return Response(data)这段代码的价值在于短信验证码是高频、高并发、强时效的业务场景单纯调用网关发短信是不够的必须配合 Redis 等缓存做限流和有效期控制才能防止接口被刷、验证码被滥用。该思路在仓库 97.电商网站技术要点剖析.md 中同样被提及——用 Redis 限流的道理与限制频繁发送手机验证码完全一致是后端流量控制的基础手段。此外仓库公开课 好玩的Python.md 还演示了短信的另一种典型用法爬虫抓取新闻标题后调用短信网关把发现一条您可能感兴趣的新闻 - 标题详情点击链接查看。【Python小课】推送到手机上并强调发送短信必须遵守平台规则违规短信无法发送。三、选型建议与总结国内的短信平台很多选择时通常要考虑费用预算、短信到达率、使用的难易程度等指标如果在商业项目中使用短信服务建议购买短信平台提供的套餐并务必配置好签名、模板与 IP 白名单。发送邮件也一样可以调用三方服务来完成但在实际的商业项目中更靠谱的选择是自己架设邮件服务器或购买专业的三方邮件服务原因在于自建邮件服务器可以完全掌控发送频率、内容与退信处理不受第三方免费额度限制邮件发送的稳定性和到达率直接关系到通知类业务的可靠性需要纳入整体运维体系。从 Day29 文档到仓库中的 Django 项目可以看到一条清晰的进阶路径先用smtplib 短信网关跑通发送这件事再结合 Redis 限流、手机号校验、签名与白名单配置把它打磨成可上线的业务功能。理解SMTP_SSL、MIMEMultipart、MIMEText、BASE64 编码和 HTTP Basic Auth 这些底层机制无论日后切换到哪家邮件服务商或短信平台都能快速迁移落地。相关资源本篇教程基于 Day29 - Python发送邮件和短信进阶接入案例见 57.接入三方平台.md公开课中的短信推送案例见 好玩的Python.md。赞分享教程文档【免费下载链接】Python-100-DaysPython - 100天从新手到大师项目地址https://gitcode.com/capable-ai/Python-100-Days点击查看免费下载相关推荐Python-100-Days 实战用 Python 自动发送邮件与短信smtplib 螺丝帽短信网关Python 100 Days 实战用 Python 自动发送邮件与短信smtplib 螺丝帽短信网关 本指南以 Python 100 Days 项目文档教程Quivr通知系统邮件、短信、推送通知集成Quivr通知系统邮件、短信、推送通知集成 引言智能助手的沟通桥梁 在当今信息爆炸的时代一个优秀的AI助手不仅需要强大的知识处理能力更需要及时有效的通知人工智能AI 应用大模型RAG后端前端Gel AI 在 EdgeQL 中的实战指南向量检索与内置 RAG 完全上手Gel AI 在 EdgeQL 中的实战指南向量检索与内置 RAG 完全上手 Gel 将向量搜索能力与检索增强生成RAG直接内建进数据库通过 ext::数据库图数据库关系型数据库上一篇DeviceUtil安全考虑设备信息检测中的隐私保护策略终极指南下一篇linux-command 项目实战hostname 命令显示与设置系统主机名详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑