上周要给200个客户发报价单,手动发了整整一个下午。后来用Python写了个脚本,5分钟搞定。
今天把邮件发送这件事彻底讲清楚。
先搞懂三个协议
发邮件不是直接"发"出去的,中间要经过好几个服务器。你需要认识三个协议:
SMTP(发件协议)
- • 端口一般是 465(SSL加密)或 587(TLS加密)
POP3(收件协议)
IMAP(收件协议)
记住一句话:发信用SMTP,收信用IMAP。
邮件发送原理
你以为点发送就直接到对方邮箱了?太天真了。
实际流程是这样的:
你的电脑 → 你的邮件服务器 → 对方的邮件服务器 → 对方的电脑
中间可能还会经过中继服务器,就像快递要经过好几个分拣中心。
这也是为什么你需要授权码而不是密码——你是在授权第三方应用代替你登录邮件服务器。
获取授权码
每个邮箱的获取方式不太一样,但思路相同:设置里找"POP3/SMTP服务",开启后生成授权码。
QQ邮箱
163邮箱
- 1. 登录163邮箱 → 设置 → POP3/SMTP/IMAP
Gmail
重要提醒:授权码不是你的登录密码!泄露了赶紧去重新生成。
发邮件:yagmail
Python发邮件的库有很多,但 yagmail 是最简单的,没有之一。
安装
pip install yagmail
基础用法:发一封纯文本邮件
import yagmail# 连接邮箱服务器yag = yagmail.SMTP( user='你的邮箱@qq.com', password='你的授权码', # 不是登录密码! host='smtp.qq.com', smtp_ssl=True)# 发送邮件yag.send( to='收件人@example.com', subject='测试邮件', contents='这是一封测试邮件')print('发送成功!')
注意: QQ邮箱的SMTP服务器地址是 smtp.qq.com,163是 smtp.163.com,Gmail是 smtp.gmail.com。
发送带附件的邮件
import yagmailyag = yagmail.SMTP( user='你的邮箱@qq.com', password='授权码', host='smtp.qq.com', smtp_ssl=True)# contents可以是列表,混合文本和文件路径yag.send( to='收件人@example.com', subject='报价单附上', contents=[ '你好,报价单在附件里,请查收。', '/path/to/报价单.pdf', '/path/to/产品说明.docx' ])
yagmail会自动识别文件路径作为附件,不用手动打开文件。
发送给多人
# to参数支持列表yag.send( to=['张三@qq.com', '李四@163.com', '王五@gmail.com'], subject='会议通知', contents='明天下午3点开会')
抄送和密送
yag.send( to='主收件人@example.com', subject='项目进度', contents='进度报告见附件', cc=['抄送人1@example.com', '抄送人2@example.com'], # 抄送 bcc=['密送人@example.com'] # 密送)
发送HTML格式邮件
html_content = """<h2>销售周报</h2><p>本周销售额:<strong>¥58,000</strong></p><table border="1"> <tr><th>产品</th><th>销量</th></tr> <tr><td>产品A</td><td>150</td></tr> <tr><td>产品B</td><td>230</td></tr></table>"""yag.send( to='老板@example.com', subject='本周销售周报', contents=html_content)
收邮件:imbox
发完邮件,有时候还需要读取收件箱里的邮件。imbox 这个库用起来很方便。
安装
pip install imbox
读取邮件
from imbox import Imbox# 连接邮箱(注意用IMAP)with Imbox( hostname='imap.qq.com', # QQ邮箱IMAP地址 username='你的邮箱@qq.com', password='授权码', ssl=True) as imbox: # 获取所有邮件 messages = imbox.messages() # 只看最新5封 for uid, message in messages[:5]: print(f"主题: {message.subject}") print(f"发件人: {message.sent_from}") print(f"日期: {message.date}") print("-" * 50)
按条件筛选邮件
from imbox import Imboxfrom datetime import datetimewith Imbox( hostname='imap.qq.com', username='你的邮箱@qq.com', password='授权码', ssl=True) as imbox: # 只看未读邮件 unread = imbox.messages(unread=True) # 看某个文件夹的邮件 inbox = imbox.messages(folder='INBOX') # 看某个发件人的邮件 from_boss = imbox.messages(sent_from='boss@company.com') # 看某个日期之后的邮件 recent = imbox.messages(date__gt=datetime(2024, 1, 1))
下载附件
with Imbox( hostname='imap.qq.com', username='你的邮箱@qq.com', password='授权码', ssl=True) as imbox: messages = imbox.messages(unread=True) for uid, message in messages: if message.attachments: for attachment in message.attachments: print(f"文件名: {attachment['filename']}") # 保存附件 with open(attachment['filename'], 'wb') as f: f.write(attachment['content'].getvalue())
常见坑和解决方案
1. 连接超时
smtplib.SMTPServerDisconnected: Connection unexpectedly closed
原因:网络问题或服务器拒绝连接。
解决:检查网络,确认端口和加密方式是否正确。
2. 认证失败
smtplib.SMTPAuthenticationError: (535, b'Error: authentication failed')
原因:授权码错误,或者用了登录密码。
解决:去邮箱重新生成授权码。
3. 被当成垃圾邮件
发出去的邮件对方收不到,在垃圾邮件里找到了。
解决:
4. QQ邮箱每天发送限制
QQ邮箱每天最多发送50封邮件。超过会报错。
如果需要大量发送,考虑用企业邮箱或专业邮件服务(如SendGrid、Mailgun)。
批量发送实战技巧
发送大量邮件时,建议加上这些保护措施:
import yagmailimport timeyag = yagmail.SMTP( user='你的邮箱@qq.com', password='授权码', host='smtp.qq.com', smtp_ssl=True)email_list = [ 'user1@example.com', 'user2@example.com', 'user3@example.com', # ... 更多邮箱]for email in email_list: try: yag.send( to=email, subject='活动邀请', contents='诚邀您参加...' ) print(f'发送成功: {email}') except Exception as e: print(f'发送失败: {email}, 错误: {e}') # 每封邮件间隔3秒,避免被封 time.sleep(3)
小技巧:加个 try-except 捕获异常,单封失败不影响后续发送。
最后
掌握这些,Python邮件发送就没什么难度了。
核心就两点:
授权码获取虽然麻烦,但一劳永逸。搞一次,以后脚本直接用。
引用链接
[1] Google应用专用密码: https://myaccount.google.com/apppasswords