赞
踩
SMTP(Simple Mail Transfer Protocol)是简单传输协议,它是一组用于用于由源地址到目的地址的邮件传输规则。
python中对SMTP进行了简单的封装,可以发送纯文本邮件、HTML邮件以及带附件的邮件。两个核心模块如下:
1、创建SMTP对象
- import smtplib
- smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
- # smtpObj = smtplib.SMTP_SSL( [host [, port [, local_hostname]]] )
-
- 参数说明:
- host: SMTP 服务器主机。 你可以指定主机的ip地址或者域名如: runoob.com,这个是可选参数。
- port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下 SMTP 端口号为25。
- local_hostname: 如果 SMTP 在你的本机上,你只需要指定服务器地址为 localhost 即可。
-
-
- #################### 示例一
- smtp = smtplib.SMTP()
- smtp.connect([host[,port]]) # 连接远程smtp主机方法,host为远程主机地址,port为远程主机smtp端口,默认为25,也可以直接使用host:port形式来表示,例如:SMTP.connect("smtp.163.com","25")
- smtp.starttls() # 开启安全传输模式
- smtp.login("test@arcvideo.com","pwd") # 邮箱账号登录校验
- smtp.sendmail(FROM, [TO], BODY) # 邮件发送
- smtp.quit() # 断开smtp连接
-
- #################### 示例二
- smtp = smtplib.SMTP([host[,port]])
- smtp.login("test@arcvideo.com","pwd") # 邮箱账号登录校验
- smtp.set_debuglevel(1) # 打印出和SMTP服务器交互的所有信息。
- smtp.sendmail(FROM, [TO], BODY) # 邮件发送
- smtp.quit() # 断开smtp连接
2、SMTP对象使用sendmail方法发送邮件:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options]) # from_addr: 邮件发送者地址。to_addrs: 字符串列表,邮件发送地址。msg: 发送消息
这里要注意一下第三个参数,msg 是字符串,表示邮件。我们知道邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意 msg 的格式。这个格式就是 smtp 协议中定义的格式。
SMTP类有几个常用的方法:
方法 | 描述 |
SMTP.set_debuglevel(level) | 设置输出debug调试信息,默认不输出 |
SMTP.docmd(cmd[, argstring]) | 发送一个命令到SMTP服务器 |
SMTP.connect([host[, port]]) | 连接到指定的SMTP服务器 |
SMTP.helo([hostname]) | 使用helo指令向SMTP服务器确认你的身份 |
SMTP.ehlo(hostname) | 使用ehlo指令像ESMTP(SMTP扩展)确认你的身份 |
SMTP.ehlo_or_helo_if_needed() | 如果在以前的会话连接中没有提供ehlo或者helo指令,这个方法会调用ehlo()或helo() |
SMTP.has_extn(name) | 判断指定名称是否在SMTP服务器上 |
SMTP.verify(address) | 判断邮件地址是否在SMTP服务器上 |
SMTP.starttls([keyfile[, certfile]]) | 使SMTP连接运行在TLS模式,所有的SMTP指令都会被加密 |
SMTP.login(user, password) | 登录SMTP服务器 |
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) | 发送邮件 from_addr:邮件发件人 to_addrs:邮件收件人 msg:发送消息 |
SMTP.quit() | 关闭SMTP会话 |
SMTP.close() | 关闭SMTP服务器连接 |
通过邮件传输简单的文本已经无法满足我们的需求,比如我们时常会定制业务质量报表,在邮件主体中会包含 HTML、图像、声音以及附件格式等,MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)作为一种新的扩展邮件格式很好地补充了这一点,更多MIME 知识见 email — An email and MIME handling package — Python 3.10.2 documentation。下面介绍几个 Python 中常用的 MIME 实现类:
MIMEBase
email.mime.base.MIMEBase
(_maintype,_subtype,*,policy = compat32,** _ params ):
这是所有MIME特定类的基类
- filename1 = '图片.pdf'
- attachfile_base = MIMEBase('application', 'octet-stream') # 创建基础对象指定类型
- attachfile_base.set_payload(open(filename,'rb').read()) # 设置我有效负载
-
- # 设置文件名可用中文
- attachfile_base.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', filename1))
- attachfile_base.add_header('Content-Disposition', 'attachment', filename=filename1 .encode('UTF-8'))
-
- encoders.encode_base64(attachfile_base)
- msg.attach(attachfile_base)
email.mime.multipart.MIMEMultipart(_subtype='mixed',boundary= None,_subparts = None,*,policy = compat32,** _ params ):
作用是生成包含多个部分的邮件体的 MIME 对象
- from email.mime.multipart import MIMEMultipart
-
-
- msg1 = MIMEMultipart('mixed') # 创建带附件的实例
- msg2 = MIMEMultipart('related') # 创建内嵌资源的实例
- msg3 = MIMEMultipart('alternative') # 创建纯文本与超文本实例
MIMEApplication
email.mime.application.MIMEApplication
(_data, _subtype='octet-stream', _encoder=email.encoders.encode_base64, *, policy=compat32, **_params):
被用来表示主要类型的MIME消息对象应用
- filename = 'abc.pdf'
- with open(filename,'rb') as f:
- attachfile = MIMEApplication(f.read())
- attachfile.add_header('Content-Disposition', 'attachment', filename=filename)
- msg.attach(attachfile)
email.mime.audio.MIMEAudio (_audiodata[, _subtype[, _encoder]]):
创建包含音频数据的邮件体
- from email.mime.audio import MIMEAudio
-
-
- msgaudio = MIMEAudio(open('yishengsuoai.mp3','rb').read(),'plain') # 文本音频对象
-
- msgaudio.add_header('Content-Disposition','attachment',filename='text.mp3') # 扩展标题类型,文件名
- msg.attach(msgaudio) # 附加对象加入到msg
email.mime.image.MIMEImage(_imagedata[, _subtype[, _encoder[, **_params]]]):
MIMENonMultipart中的一个子类,创建包含图片数据的邮件体,
- from email.mime.image import MIMEImage
-
-
- with open('test.png','rb') as fp:
- msgImage = MIMEImage(fp.read())
-
-
- msgImage.add_header('Content-ID','imgid') # 为图片对象拓展标题字段和值
- msg.attach(msgImage) # 将图像负载添加到msg负载
email.mime.text.MIMEText (_text[, _subtype[, _charset]]):
MIMENonMultipart中的一个子类,创建包含文本数据的邮件体
- from email.mime.text import MIMEText
-
-
- # 创建文本内容的邮件体
- msg = MIMEText("python test email",'plain','utf-8')
-
- # 创建HTML格式的邮件体
- msg = MIMEText("<p>python test email</p><p><a href="http://www.demo.com">链接</a></p>",'html','utf-8')
-
-
- # 构造TEXT格式的消息
- msg = MIMEText("hello.text","plain","utf-8")
- msg["Subject"] = "xxxxx" # 主题
- msg["From"] = "xxxx" # 发送者
- msg["To"] = "xxxx" # 接收者
- msg["Cc"] = "xxxx" # 抄送
-
- # 发送以上构造的邮件内容要使用as_string将构造的邮件内容转换为string形式。
- msg.sendmail("xxx","xxx",msg.as_string)
- msg.add_header('Content-ID','imgid') #设置图片ID
- msg.add_header('Content-Disposition','attachment',filename='test.xlsx') #为附件添加一个标题
- msg.add_header('Content-Disposition','attachment',filename=('utf-8','','中文标题')) #添加非ASCII字符时需指定编码
email.header.Header(s=None,charset=None):创建一个可以包含不同字符集中的字符串,并符合MIME的标头。
可选参数:s是初始标题值默认为None,可以使用append()方法追加到标题,charset指定字符集
- from email.header import Header
-
-
- msg['From'] = Header("测试邮件来自",'utf-8')
附加工具:email.utils
- from email.utils import formataddr
-
-
- msg['From'] = formataddr(['Meslef','92066@163.com'])
- msg['To'] = formataddr(['Anybody','92066@163.com'])
- # coding=utf-8
- import smtplib
- from email.mime.text import MIMEText
-
-
- sender = 'bmjoker@163.com' # 发送邮箱地址
- password = 'xxxxxxx' # 邮箱授权码,非登陆密码
- mailto_list = ['19xxxxxxx9@qq.com'] # 群发邮箱地址
- smtp_server = 'smtp.163.com' # smtp服务器
-
- # 发送纯文本格式的邮件
- msg = MIMEText('hello,send by python_test...','plain','utf-8')
- msg['From'] = sender # 发送邮箱地址
- msg['To'] =';'.join(mailto_list) # 发送多人邮件写法
- msg['Subject'] = 'hello,i just want to test' # 主题
-
- server = smtplib.SMTP(smtp_server,25) # SMTP协议默认端口是25
- server.login(sender,password) # login()方法用来登录SMTP服务器
- server.set_debuglevel(1) # 打印出和SMTP服务器交互的所有信息。
- server.sendmail(sender,mailto_list,msg.as_string()) # msg.as_string()把MIMEText对象变成str server.quit()
- # 第一个参数为发送者,第二个参数为接收者,可以添加多个例如:['hello@163.com','xxx@qq.com',]# 第三个参数为发送的内容
- server.quit()
查看和SMTP服务器交互的所有信息:
其中login()用来登陆SMTP服务器,sendmail()用来发送邮件,群发邮件的话,可以传入一个收件人邮箱列表,邮箱的正文是str,使用as_string()把MIMEText对象变成str,password指的不是smtp服务器的登陆密码,是smtp客户端的授权密码:
- import smtplib
- from email.mime.text import MIMEText
- from email.header import Header
-
-
- sender = 'bmjoker@163.com' # 发件邮箱
- passwd = 'xxxxxxxx' # 发送人邮箱授权码
- receivers = '19xxxxxxx9@qq.com' # 收件邮箱
- subject = 'python发邮Html邮件测试' # 主题
-
- content = "<html><h1>人生苦短,何必执着</h1></html>"
- msg = MIMEText(content,'html','utf-8')
- msg['Subject'] = Header(subject,'utf-8') # msg['Subject'] = subject
- msg['From'] = Header('hello','utf-8') # msg['From'] = sender
- msg['To'] = Header('emmmm','utf-8') # msg['To'] = receivers
-
- try:
- s = smtplib.SMTP_SSL('smtp.163.com',25)
- s.login(sender,passwd)
- s.sendmail(sender,receivers,msg.as_string())
- print('Send Success')
- except:
- print('Send Failure')
- import smtplib
- from email.mime.image import MIMEImage
- from email.mime.text import MIMEText
- from email.mime.multipart import MIMEMultipart
-
-
- sender = 'bmjoker@163.com'
- passwd = 'xxxxxxxx'
- receivers = '19xxxxxx9@qq.com'
- subject = 'python发邮带img的邮件测试'
-
- # 创建一个带附件的实例
- msg = MIMEMultipart()
- msg['Subject'] = subject
- msg['From'] = sender
- msg['To'] = receivers
-
- # 创建正文
- msg.attach(MIMEText('使用python smtplib模块和email模块自动发送邮件测试','plain','utf-8'))
-
- # 创建图片附件
- import os
- img_file = open(os.getcwd()+"/a4.jpg",'rb').read()
- msg_img = MIMEImage(img_file)
- msg_img.add_header('Content-Disposition','attachment', filename = "a4.jpg")
- msg_img.add_header('Content-ID', '<0>')
- msg.attach(msg_img)
-
- try:
- s = smtplib.SMTP('smtp.163.com',25)
- s.set_debuglevel(1) # 输出发送邮件详细过程
- s.login(sender,passwd)
- s.sendmail(sender,receivers,msg.as_string())
- print('Send Succese')
-
- except:
- print('Send Failure')
- <!--有效-->
- <img src="cid:ALogo" width="500" height="200">
-
- <!--无效-->
- <img src="cid:ALogo" style="width: 500px;height: 200px">
-
- <!--无效-->
- <img src="cid:ALogo" width="500px" height="200px">
- # 首先是xlsx类型的附件
- xlsxpart = MIMEApplication(open('test.xlsx', 'rb').read())
- xlsxpart.add_header('Content-Disposition', 'attachment', filename='test.xlsx')
- msg.attach(xlsxpart)
-
- # jpg类型的附件
- jpgpart = MIMEApplication(open('beauty.jpg', 'rb').read())
- jpgpart.add_header('Content-Disposition', 'attachment', filename='beauty.jpg')
- msg.attach(jpgpart)
-
- # mp3类型的附件
- mp3part = MIMEApplication(open('kenny.mp3', 'rb').read())
- mp3part.add_header('Content-Disposition', 'attachment', filename='benny.mp3')
- msg.attach(mp3part)
-
-
- ##################### 以下待验证
- # 读取xls文件作为附件,open()要带参数'rb',使文件变成二进制格式,从而使'base64'编码产生作用,否则附件打开乱码
- # att = MIMEText(open('C:\\ceshi.xls', 'rb').read(), 'base64', 'GB2312')
- # att['Content-Type'] = 'application/vnd.ms-excel'
- # att['Content-Disposition'] = 'attachment; filename ="1.xls"'
-
- # 读取xlsx文件作为附件,open()要带参数'rb',使文件变成二进制格式,从而使'base64'编码产生作用,否则附件打开乱码
- att = MIMEText(open(u'C:\\ceshi.xlsx', 'rb').read(), 'base64', 'utf-8')
- att['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
- #下面的filename 等号(=)后面好像不能有空格
- attname ='attachment; filename ="123.xlsx"'
- att['Content-Disposition'] = attname
-
- msgroot.attach(att)
-
- #encoding=utf8
- import smtplib
- from email.mime.multipart import MIMEMultipart
- from email.header import Header
- from email.mime.text import MIMEText
- from email.mime.application import MIMEApplication
- # 第三方 SMTP 服务
- mail_host = "*******" # 设置服务器
- mail_user = "*******" # 用户名
- mail_pass = "********" # 口令
-
- sender = '*****'
- receivers = ['*****'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱
- content = MIMEText('test')
- message = MIMEMultipart()
- message.attach(content)
- message['From'] = Header("Easy", 'utf-8')
- message['To'] = Header("测试", 'utf-8')
- subject = 'Python SMTP 邮件测试'
- message['Subject'] = Header(subject, 'utf-8')
- xlsx = MIMEApplication(open('test.xlsx', 'rb').read())
- xlsx["Content-Type"] = 'application/octet-stream'
- xlsx.add_header('Content-Disposition', 'attachment', filename='test.xlsx')
- message.attach(xlsx)
- try:
- smtpObj = smtplib.SMTP()
- smtpObj.connect(mail_host, 25) # 25 为 SMTP 端口号
- smtpObj.login(mail_user, mail_pass)
- smtpObj.sendmail(sender, receivers, message.as_string())
- print("邮件发送成功")
- except Exception as e:
- print(e)
- import smtplib
- from email.mime.multipart import MIMEMultipart
- from email.mime.text import MIMEText
- from email.mime.image import MIMEImage
-
- sender = 'xxx@163.com' # 这里就是你的163邮箱
- receiver = 'xxx@qq.com' # 发给单人时的邮件接收邮箱
- smtpserver = "smtp.163.com" # 邮件服务器,如果是163邮箱那就是这个了,其他的可以自行查找
- username = 'xxxx@163.com' # 这里还是你的邮箱
- password = 'xxxxx' # 上面获取的SMTP授权码,相当于是一个密码验证
- msgRoot = MIMEMultipart('related') # 邮件类型,如果要加图片等附件,就得是这个
- msgRoot['Subject'] = '监控日报' # 邮件标题,以下设置项都很明了
- msgRoot['From'] = sender
- msgRoot['To'] = receiver
-
- # 以下为邮件正文内容,含有一个居中的标题和一张图片
- content = MIMEText('<html><head><style>#string{text-align:center;font-size:25px;}</style><div id="string">我是居中显示的标题<div></head><body><img src="cid:image1" alt="image1"></body></html>','html','utf-8')
-
- # 如果有编码格式问题导致乱码,可以进行格式转换:
- # content = content.decode('utf-8').encode('gbk')
- msgRoot.attach(content)
-
- # 上面添加的图片src必须是cid:xxx的形式,xxx就是下面添加图片时设置的图片id
- fp = open('D:\\Desktop\\aaa.jpg', 'rb')
- msgImage = MIMEImage(fp.read())
- fp.close()
- msgImage.add_header('Content-ID', 'image') # 这个id用于上面html获取图片
- msgRoot.attach(msgImage)
- # 再加一个
- fp1 = open('D:\\Desktop\\bbb.jpg', 'rb')
- msgImage1 = MIMEImage(fp1.read())
- fp1.close()
- msgImage1.add_header('Content-ID', 'image1') # 这个id用于上面html获取图片
- msgRoot.attach(msgImage1)
-
- '''
- # 另外也可以用base64的方法直接加,但是这种方式outlook不支持
- import base64
- img_file = open('C:\\Users\\cloudoxou\\Desktop\\img.png','rb')
- base64_data = base64.b64encode(img_file.read())
- html = "<img src="https://img-blog.csdnimg.cn/2022010708251630187.png" alt="image1">"%(base64_data) # 这里简化了html代码
- '''
- # 连接邮件服务器,因为使用SMTP授权码的方式登录,必须是994端口
- smtp = smtplib.SMTP_SSL(smtpserver,994)
- smtp.login(username, password)
- smtp.sendmail(sender, receiver, msgRoot.as_string())
msg中输入的是邮件正文,因此需要根据具体内容格式选择合适的类型!
关于不同类型文件的对应类型,可参考此链接:HTTP Content-type 对照表。
- import smtplib
- from email.utils import make_msgid,formatdate
- from email.mime.text import MIMEText # html格式和文本格式邮件
- from email.mime.multipart import MIMEMultipart # 带多个部分的邮件
- from email.mime.image import MIMEImage # 带图片格式邮件
- from email.mime.audio import MIMEAudio # 音频文件对象
- from email.utils import formataddr # 分隔标题与地址
- from email.header import Header # 设置标题字符集
- from email import encoders # 编码器
- from email.mime.application import MIMEApplication # 主要类型的MIME消息对象应用
- from email.mime.base import MIMEBase
-
-
- username = 'service@gemail.com' # 发件人地址,通过控制台创建的发件人地址
- password = '*****' # 发件人密码,通过控制台创建的发件人密码
- replyto = 'aa@qq.com' # 自定义的回复地址
- rcptto = ['***', '***'] # 收件人地址或是地址列表,支持多个收件人,最多30个
-
- # 构建信件标头结构
- msg = MIMEMultipart('alternative') # 创建一个多部分的邮件对象
- msg['Subject'] = Header('自定义信件主题', 'utf-8')
- msg['From'] = formataddr([Header('自定义发信昵称','utf-8'),username])
- msg['To'] = formataddr([Header('自定义收信昵称','utf-8'),rcptto])
- msg['Reply-to'] = replyto
- msg['Message-id'] = make_msgid() #Message-ID标头
- msg['Date'] = formatdate() #日期
-
-
- #构建文本邮件内容
- msg_text = MIMEText('自定义TEXT纯文本部分','plain','utf-8')
- msg.attach(msg_text)
- #读取文件创建邮件内容
- with open('textfile','rb') as fp: #读取文件内容
- msg_text=MIMEText(fp.read(),'plain','utf-8')
-
-
- #构建HTML格式的邮件内容
- msg_html = MIMEText("<h1>HTML格式邮件</h1>","html","utf-8")
- msg.attach(msg_html)
-
-
- #构建HTML格式邮件带图片内容
- html1 = "<div><img src='cid:imgid'></div>"
- msg_html_img = MIMEText(html1,'html','utf-8')
- msg.attach(msg_html_img)
- with open("imgfile","rb") as f:
- msg_img = MIMEImage(f.read())
- msg_img.add_header('Content-ID','imgid') #扩展图片标题
- msg.attach(msg_img)
-
-
- #带附件的邮件MIMEApplication
- filename = '简历.pdf'
- with open(filename,'rb') as f:
- attachfile = MIMEApplication(f.read())
- attachfile.add_header('Content-Disposition', 'attachment', filename=filename)
- msg.attach(attachfile)
-
-
- #带多个附件的邮件MIMEApplication
- filenames = ['简历.pdf','副本.pdf']
- for tmp in filename:
- with open(tmp,'rb') as f:
- attachfiles = MIMEApplication(f.read())
- attachfiles.add_header('Content-Disposition', 'attachment', filename=tmp)
- msg.attach(attachfiles)
-
-
- #带附件的邮件MIMEBase
- filename1 = '图片.pdf'
- attachfile_base = MIMEBase('application', 'octet-stream') #创建基础对象指定类型
- attachfile_base.set_payload(open(filename,'rb').read()) #设置我有效负载
- attachfile_base.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', filename1) )
- encoders.encode_base64(attachfile_base)
- msg.attach(attachfile_base)
-
-
- #创建音频文件
- AUDIO_HTML = '''
- <p>this's audio file</p>
- <audio controls>
- <source src="cid:audioid" type="audio/mpeg">
- </audio>
- '''
- msg_test1 = MIMEText(AUDIO_HTML,'html','utf-8')
- msg_audio = MIMEAudio(open('iphone.mp3','rb').read(),'plain')
- msg_audio.add_header('Content-ID','audioid')
- msg.attach(msg_test1)
- msg.attach(msg_audio)
- #收到邮件不能播放,有待解决!
-
-
- # 发送邮件
- try:
- client = smtplib.SMTP()
- #需要使用SSL,可以这样创建client
- #client = smtplib.SMTP_SSL()
- client.connect('smtp.163.com', 25)
- #开启DEBUG模式
- client.set_debuglevel(1)
- client.login(username, password)
- client.sendmail(username, rcptto, msg.as_string())
- client.quit()
- print('email send success!')
- except smtplib.SMTPConnectError as e:
- print('邮件发送失败,连接失败:', e.smtp_code, e.smtp_error)
- except smtplib.SMTPAuthenticationError as e:
- print('邮件发送失败,认证错误:', e.smtp_code, e.smtp_error)
- except smtplib.SMTPSenderRefused as e:
- print('邮件发送失败,发件人被拒绝:', e.smtp_code, e.smtp_error)
- except smtplib.SMTPRecipientsRefused as e:
- print('邮件发送失败,收件人被拒绝:', e.smtp_code, e.smtp_error)
- except smtplib.SMTPDataError as e:
- print('邮件发送失败,数据接收拒绝:', e.smtp_code, e.smtp_error)
- except smtplib.SMTPException as e:
- print('邮件发送失败, ', e.message)
- except Exception as e:
- print('邮件发送异常, ', str(e))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。