今天百度学习了如何在python中使用SMTP发送邮件,包括带HTML格式和附件。
基本套路就是定义一个MIMEText(不带附件)或者MIMEMultipart(可带多个附件),然后再连接、登录邮件服务器并发送即可。(发送HTML格式的邮件与纯文本消息的邮件不同之处就是将MIMEText中_subtype设置为html。
)
套路如下:不带附件
from email.mime.text import MIMEText
import smtplib
mail = MIMEText('邮件正文') # 简单纯文本消息的邮件
# mail = MIMEText('邮件正文', _subtype='html', _charset='utf-8') # HTML格式的邮件
mail['Subject'] = '邮件主题'
mail['From'] = '发件人地址' # 需与邮件服务器的认证用户一致
mail['To'] = '收件人地址'
smtp = smtplib.SMTP('smtp.qq.com', port=25) # 设置邮件服务器地址与端口
smtp.login('帐号', '密码') # 登录邮件服务器
smtp.sendmail('发件人地址', '收件人地址', mail.as_string()) # 发送邮件
self.smtp.quit() # 关闭邮件服务器
带附件
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
mail = MIMEMultipart()
mail.attach(MIMEText('邮件正文', _subtype='html', _charset='utf-8'))
# 构造附件att1,若是要带多个附件,可根据下边的格式构造
att1 = MIMEText(open('文件', 'rb').read(), 'base64', 'utf-8')
att1['Content-Type'] = 'application/octet-stream'
att1["Content-Disposition"] = 'attachment; filename="%s"' % 文件名
mail.attach(att1)
mail['Subject'] = '邮件主题'
mail['From'] = '发件人地址' # 需与邮件服务器的认证用户一致
mail['To'] = '收件人地址'
smtp = smtplib.SMTP('smtp.qq.com', port=25) # 设置邮件服务器地址与端口
smtp.login('帐号', '密码') # 登录邮件服务器
smtp.sendmail('发件人地址', '收件人地址', mail.as_string()) # 发送邮件
self.smtp.quit() # 关闭邮件服务器
我将其构造成一个类,以在构造类时是否传入file参数来判断是否要带附件。
说明:
- 需要在邮件服务器上设置打开smtp功能。
【阿里云上禁用25端口,需使用SMTP_SSL、端口465连接。这次一并修改了。】
- SMTP服务器地址和端口可以在邮件服务器的设置里找到(在设置上边 1 时,应该就可以看到)
- 发件人与登录邮件服务器的认证用户应该一致,所以我把它写死在代码里了。(或许使用一个常量定义会更好?)
- 若是多个收件人则需在to_email参数中用逗号隔开。另外:MIMEText()[“To”]的数据类型与sendmail(from_addrs,to_addrs,…)的to_addrs不同;前者为str类型,多个地址使用逗号分隔,后者为list类型。所以在sendmail()函数中使用split(’,’)来分离多个收件人。
代码如下:
# -*- coding:utf-8 -*-
""" 发送邮件 """
import smtplib, os, base64
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
email_server_user = 'QQ邮箱帐号'
email_server_pwd = 'QQ邮箱密码'
class Email(object):
"""
:param: to_email:字串,收件人地址,多个收件人时用逗号隔开
:param: from_email:发件人地址
:param: subject:邮件主题
:param: content:邮件正文
:param: files:列表,附件地址,支持多个附件
:return: 则返发送状态和信息
attachment是附件:
attachment = MIMEText(f.read(), 'base64', 'utf-8')
attachment['Content-Type'] = 'application/octet-stream'
attachment["Content-Disposition"] = 'attachment; filename="%s"' % file_name
self.mail.attach(attachment)
因为阿里云禁用了25端口,smtp = smtplib.SMTP('smtp.qq.com', port=25)将不可用。
需改用:smtp = smtplib.SMTP_SSL('smtp.qq.com', port=465)
范例:
email = Email(
to_email='****@qq.com',
from_email='****@qq.com',
subject='Test',
content='''
<b>测试测试</b><br>
这是我的Email模块!
<center>send by python_mail</center>
''' + str(datetime.now())[:19]
# file=['./1.png','./2.png']
)
email.sent()
"""
def __init__(self, to_email, from_email, subject='无主题', content=None, files=None):
self.to_email = to_email # 收件人
self.from_email = from_email # 发件人
self.subject = subject # 主题
self.content = content # 邮件正文
self.files = files # 附件
def sent(self):
if self.content or self.files:
try:
# 构造邮件
mail = MIMEMultipart()
mail['From'] = self.from_email
mail['To'] = self.to_email
mail['Subject'] = self.subject
if self.content:
mail.attach(MIMEText(self.content, _subtype='html', _charset='utf-8'))
# 添加附件
if self.files:
for file in self.files:
# 构造附件并添加至邮件
try:
with open(file, 'rb') as f:
attachment = MIMEText(f.read(), 'base64', 'utf-8')
except Exception as e:
return False, '发送失败:附件["{}"]读取错误【{}】'.format(file, str(e))
else:
attachment['Content-Type'] = 'application/octet-stream'
file_name = os.path.split(file)[1]
# 下面一句是处理附件名是中文的情况
file_name = '=?utf-8?b?' + base64.b64encode(file_name.encode()).decode() + '?='
attachment["Content-Disposition"] = 'attachment; filename="%s"' % file_name
mail.attach(attachment)
# 发送邮件
smtp = None
try:
smtp = smtplib.SMTP_SSL('smtp.qq.com', port=465) # 设置邮件服务器
smtp.login(email_server_user, email_server_pwd) # 登录邮件服务器
smtp.sendmail(mail['From'], mail['To'].split(','), mail.as_string()) # 发送邮件
except Exception as e:
return False, '发送失败:服务器连接/发送失败【{}】'.format(str(e))
finally:
if smtp:
smtp.quit() # 关闭邮件服务器
return True, '发送成功'
except Exception as e:
return False, '发送失败:{}'.format(str(e))
else:
return False, '发送失败:【邮件正文与附件都为空】'
如果本文对您有帮助,请给我留个言。谢谢!