本文主要是介绍【Python】发送邮件,超详细看图敲码(附完整代码)一一CSDN21天学习挑战赛,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 一、邮箱注册
- 二、邮箱设置
- 服务开启
- POP3 & SMTP & IMAP 介绍
- 三、Python发送邮件
- 发送默认邮件
- 邮件格式
- 发送文本格式邮件
- 发送HTML格式邮件
- 发送HTML带内嵌图片
- 发送带附件邮件
- 四、完整代码
- 总结
本系列文章为参与【Python】CSDN21天学习挑战赛,成为更好的自己,根据自身的学习进度并记录自己的学习过程。我也是Python纯小白,和大家一起学习,保持热爱学习的好习惯😁
活动地址:CSDN21天学习挑战赛
一、邮箱注册
注册网易邮箱,其他邮箱也支持的,我这里以网易为例,都差不多
二、邮箱设置
服务开启
1.注册后登录邮箱,选择我们设置
2.找到我们的POP3/SMTP/IMAP
3.需要开启我们的IMAP/SMTP服务和POP3/SMTP服务
提示:如果服务默认是开启的,但是不知道授权码,可以选择新增,或者删除,关闭服务重新开启,都是可以的
4.首先我们开启IMAP/SMTP服务,需要发送短信验证,使用手机微信,浏览器扫码都行,发送成功后,点击我已发送
5.然后就会生成一串授权码,一定一定要先记下来
,再点击确定,这里使用设备随便填
6.接着,我们开启POP3/SMTP服务,一样需要扫码发送短信
7.开启成功后,就会弹出提示,我们就可以用刚刚的授权码来发送邮件了
POP3 & SMTP & IMAP 介绍
POP3
是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
SMTP
的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。SMTP 认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。增加 SMTP 认证的目的是为了使用户避免受到垃圾邮件的侵扰。
IMAP
全称是Internet Mail Access Protocol,即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。
网易163免费邮箱相关服务器信息
服务器名称 服务器地址 SSL协议端口号 非SSL协议端口号 IMAP imap.163.com 993 143 SMTP smtp.163.com 456/994 25 POP3 pop.163.com 995 110
POP3
和IMAP
的区别协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 。
而
IMAP
提供webmail 与电子邮件客户端之间的双向通信,客户端的操作都会反馈到服务器上,对邮件进行的操作,服务器上的邮件也会做相应的动作。同时,
IMAP
像POP3
那样提供了方便的邮件下载服务,让用户能进行离线阅读。IMAP
提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。此外,IMAP
更好地支持了从多个不同设备中随时访问新邮件。
操作位置 操作内容 IMAP POP3 收件箱 阅读,标记,移动,删除邮件等 客户端与邮箱更新同步 仅客户端内 发件箱 保存到已发送 客户端与邮箱更新同步 仅客户端内 创建文件夹 新建自定义文件夹 客户端与邮箱更新同步 仅客户端内 草稿 保存草稿 客户端与邮箱更新同步 仅客户端内 垃圾文件夹 接受误移入垃圾文件夹的邮件 支持 不支持 广告邮件 接受被移入广告文件夹的邮件 支持 不支持 总之,
IMAP
整体上为用户带来更为便捷和可靠的体验。POP3
更易丢失邮件或多次下载相同的邮件,但IMAP
通过邮件客户端与webmail 之间的双向同步功能很好地避免了这些问题。
注:
若在web邮箱中设置了“保存到已发送”,使用客户端POP服务发信时,已发邮件也会自动同步到网页端“已发送”文件夹内。
三、Python发送邮件
发送默认邮件
1.启动PyCharm
2.新建文件email_163
3.导入发送邮件模块
# 导入发送邮件模块
import smtplib
4.创建class类
# 发送网易邮箱类
class Email163(object):
5.建议所有不怎么会变动的设置为类常量
# 服务器地址
HOST = 'smtp.163.com'
# 端口
PORT = '25'
# 授权码
PASSWORD = '填写自己的授权码(不是邮箱密码)'
# 登录用户(邮件发送者)
FROM_ADDR = '填写自己发送者的邮箱'
6.构造函数
def __init__(self, msg: str, to_addrs: str) -> None:"""构造函数:param msg: 邮件内容:param to_addrs: 邮件接收者"""self.msg = msgself.to_addrs = to_addrs
7.定义发送默认邮件函数
def send_default_email(self) -> None:"""发送默认邮件:return:None"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)# 发送邮件smtp.sendmail(self.FROM_ADDR, self.to_addrs, self.msg)# 发送完邮件,关闭服务smtp.close()print(f'邮件成功发送给:{self.to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'
8.入口函数调用
if __name__ == '__main__':# 邮件内容msg = 'hello world'# 邮件接收者(填写自己想要发送给别人的邮箱地址)# 可以发送多人(可以发给自己),格式:to_addrs = ['980338974@qq.com','*****','********']to_addrs = '980338974@qq.com'# 实例发送网易邮箱的类email163 = Email163(msg, to_addrs)# 调用发送邮件函数email163.send_default_email()
9.可以看到邮件以及发送成功了
10.接下来我们登录接收的邮箱看看,发现成功接收了邮件,但是没有主题,也没有任何内容
邮件格式
我们可以使用第三方库email
中的一些模块,更方便快速的构造邮件内容
发送文本格式邮件
提示:如果使用email模块群发邮件,群发报错
:AttributeError: 'list' object has no attribute 'decode'
,可以将接收者列表用,或;拼接为字符串
:','.join(to_addrs)
1.导入模块
# 导入邮件主题构造模块
from email.header import Header
# 导入邮件内容构造模块
from email.mime.text import MIMEText
2.定义发送文本格式邮件函数
def send_text_email(self) -> None:"""发送文本格式邮件:return:None"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)# 构造邮件内容# 第一个参数_text:内容# 第二个参数_subtype:格式# 第三个参数_charset:编码# 实例邮件正文message = MIMEText('这是使用Python发送的邮件测试!', 'plain', 'utf-8')# 构造邮件主题信息# 主题message['Subject'] = Header('Python发送邮件', 'utf-8')# 发送者message['From'] = Header(self.FROM_ADDR, 'utf-8')# 接收者# message['To'] = Header(','.join(self.to_addrs), 'utf-8') # 接收者为多人[]时,需要用,拼接为字符串message['To'] = Header(self.to_addrs, 'utf-8')# 发送邮件smtp.sendmail(self.FROM_ADDR, self.to_addrs, message.as_string())# 发送完邮件,关闭服务smtp.close()print(f'邮件成功发送给:{self.to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'
3.入口函数调用
if __name__ == '__main__':# 邮件内容msg = 'hello world'# 邮件接收者(填写自己想要发送给别人的邮箱地址)# 可以发送多人(可以发给自己),格式:to_addrs = ['980338974@qq.com','*****','********']to_addrs = '980338974@qq.com'# 实例发送网易邮箱的类email163 = Email163(msg, to_addrs)# 调用发送邮件函数email163.send_text_email()
4.再看邮箱,就有主题和内容了
发送HTML格式邮件
1.定义发送HTML格式邮件函数
def send_html_email(self) -> None:"""发送HTML格式邮件:return:None"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)# 构造邮件内容# 第一个参数_text:内容# 第二个参数_subtype:格式# 第三个参数_charset:编码text = """<h1>这是使用Python发送的HTML格式邮件测试,我是h1</h1><a href="http://t.csdn.cn/p58Yf">我是一个链接</a><table><th>我是表格列头</th><tr><td bgcolor="PowderBlue">我是有颜色的表单元格</td></tr></table>"""# 实例邮件正文message = MIMEText(text, 'html', 'utf-8')# 构造邮件主题信息# 主题message['Subject'] = Header('Python发送邮件', 'utf-8')# 发送者message['From'] = Header(self.FROM_ADDR, 'utf-8')# 接收者message['To'] = Header(','.join(self.to_addrs), 'utf-8') # 接收者为多人[]时,需要用,拼接为字符串# message['To'] = Header(self.to_addrs, 'utf-8')# 发送邮件smtp.sendmail(self.FROM_ADDR, self.to_addrs, message.as_string())# 发送完邮件,关闭服务smtp.close()print(f'邮件成功发送给:{self.to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'
2.入口函数调用
if __name__ == '__main__':# 邮件内容msg = 'hello world'# 邮件接收者(填写自己想要发送给别人的邮箱地址)# 可以发送多人(可以发给自己),格式:to_addrs = ['980338974@qq.com','*****','********']to_addrs = '980338974@qq.com'# 实例发送网易邮箱的类email163 = Email163(msg, to_addrs)# 调用发送邮件函数email163.send_html_email()
发送HTML带内嵌图片
邮件中HTML文本中,如果使用外网链接地址,一般是无效的,同样,我们可以用
:MIMEImage
模块完成
1.导入模块
# 导入邮件混合构造模块
from email.mime.multipart import MIMEMultipart
# 导入邮件图片处理模块
from email.mime.image import MIMEImage
2.定义函数
def send_html_with_image_email(self) -> None:"""发送HTML格式邮件带图片:return:None"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)# 实例内嵌的邮件(文本,HTML,图片)message = MIMEMultipart('related')# 构造邮件内容# 第一个参数_text:内容# 第二个参数_subtype:格式# 第三个参数_charset:编码# 构造邮件主题信息# 主题message['Subject'] = Header('Python发送邮件', 'utf-8')# 发送者message['From'] = Header(self.FROM_ADDR, 'utf-8')# 接收者message['To'] = Header(','.join(self.to_addrs), 'utf-8') # 接收者为多人[]时,需要用,拼接为字符串# message['To'] = Header(self.to_addrs, 'utf-8')text = """<h1>这是使用Python发送的HTML格式邮件测试,我是h1</h1><a href="http://t.csdn.cn/p58Yf">我是一个链接</a><table><th>我是表格列头</th><tr><td bgcolor="PowderBlue">我是有颜色的表单元格</td></tr></table><p>CSDN:</p><p><img src="cid:csdn"></p>"""# 附加邮件正文message.attach(MIMEText(text, 'html', 'utf-8'))# 打开图片img_name = 'csdn.gif'file = open(img_name, 'rb')img_data = file.read()file.close()# 创建图片img = MIMEImage(img_data)# 定义图片ID,在HTML文本中引用img.add_header('Content-ID', 'csdn')# 附加图片message.attach(img)# 发送邮件smtp.sendmail(self.FROM_ADDR, self.to_addrs, message.as_string())# 发送完邮件,关闭服务smtp.close()print(f'邮件成功发送给:{self.to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'
3.入口函数调用
if __name__ == '__main__':# 邮件内容msg = 'hello world'# 邮件接收者(填写自己想要发送给别人的邮箱地址)# 可以发送多人(可以发给自己),格式:to_addrs = ['980338974@qq.com','*****','********']to_addrs = '980338974@qq.com'# 实例发送网易邮箱的类email163 = Email163(msg, to_addrs)# 调用发送邮件函数email163.send_html_with_image_email()
4.查看邮箱,图片显示正常,因为我是网易邮箱发送给QQ邮箱,QQ邮箱设置了保护机制,点击显示图片就行了
5.可以看到,HTML和内嵌图片都显示成功了(这个CSDN
是个gif)
发送带附件邮件
1.在email_163.py
同级创建attachment.txt
文件,文件内容可写可不写
2.导入模块,混合模式包含所有类型,可以发送文本格式,HTML格式,带附件
# 导入邮件混合构造模块
from email.mime.multipart import MIMEMultipart
3.定义发送带附件邮件函数
def send_attachment_email(self) -> None:"""发送带附件邮件:return:None"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)# 实例带附件的邮件message = MIMEMultipart()# 构造邮件内容# 第一个参数_text:内容# 第二个参数_subtype:格式# 第三个参数_charset:编码text = """<h1>这是使用Python发送的HTML格式邮件测试,我是h1</h1><a href="http://t.csdn.cn/p58Yf">我是一个链接</a><table><th>我是表格列头</th><tr><td bgcolor="PowderBlue">我是有颜色的表单元格</td></tr></table>"""# 邮件正文message.attach(MIMEText(text, 'html', 'utf-8'))# 构造邮件主题信息# 发送者message['From'] = Header(self.FROM_ADDR, 'utf-8')# 接收者message['To'] = Header(','.join(self.to_addrs), 'utf-8') # 接收者为多人[]时,需要用,拼接为字符串# message['To'] = Header(self.to_addrs, 'utf-8')# 主题message['Subject'] = Header('Python发送邮件', 'utf-8')# 上传当前目录下的test.txt文件(附加文件1)attachment = MIMEText(open('attachment.txt', 'rb').read(), 'base64', 'utf-8')# 指定消息内容为字节流attachment["Content-Type"] = 'application/octet-stream'# 消息描述,这里的filename可以随便填写(最好不要中文,可能会乱码),这里填写的就会在邮件中附件名称显示attachment["Content-Disposition"] = 'attachment; filename="attachment.txt"'# 附加文件message.attach(attachment)# 上传当前目录下的test.txt文件(附件2)attachment = MIMEText(open('attachment.txt', 'rb').read(), 'base64', 'utf-8')# 指定消息内容为字节流attachment["Content-Type"] = 'application/octet-stream'# 消息描述,这里的filename可以随便填写(最好不要中文,可能会乱码),这里填写的就会在邮件中附件名称显示attachment["Content-Disposition"] = 'attachment; filename="attachment2.txt"'# 附加文件2message.attach(attachment)# 发送邮件smtp.sendmail(self.FROM_ADDR, self.to_addrs, message.as_string())print(f'邮件成功发送给:{self.to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'
4.入口函数调用
if __name__ == '__main__':# 邮件内容msg = 'hello world'# 邮件接收者(填写自己想要发送给别人的邮箱地址)# 可以发送多人(可以发给自己),格式:to_addrs = ['980338974@qq.com','*****','********']to_addrs = '980338974@qq.com'# 实例发送网易邮箱的类email163 = Email163(msg, to_addrs)# 调用发送邮件函数email163.send_attachment_email()
5.打开邮箱查看,发现邮件中有两个附件
四、完整代码
其实上面代码中,大量的脏代码,很多重复性内容,下面完整代码我做了简单的封装处理
PASSWORD填写自己的授权码,FROM_ADDR填写邮件发送者
# 导入发送邮件模块
import smtplib
# 导入邮件主题构造模块
from email.header import Header
# 导入邮件文字构造模块
from email.mime.text import MIMEText
# 导入邮件混合构造模块
from email.mime.multipart import MIMEMultipart
# 导入邮件图片处理模块
from email.mime.image import MIMEImage# 发送网易邮件类
class Email163(object):# 服务器地址HOST = 'smtp.163.com'# 端口PORT = '25'# 授权码(不是邮箱密码)'PASSWORD = ''# 登录用户(邮件发送者)FROM_ADDR = ''# 文本格式SUBTYPE_PLAIN = 'plain'# HTML格式SUBTYPE_HTML = 'html'# 附件ATTACHMENT = 'attachment'# 内嵌EMBEDDED = 'embedded'def __init__(self, subtype: str = SUBTYPE_PLAIN, charset: str = 'utf-8') -> None:"""构造函数:param subtype: 邮件格式:plain:文本,html:超文本标记语言,n(默认plain):param charset: 编码,默认utf-8"""self.subtype = subtypeself.charset = charsetdef get_smtp(self) -> smtplib.SMTP:"""实例SMTP并验证:return: smtplib.SMTP"""try:# 实例SMTPsmtp = smtplib.SMTP()# 连接邮箱服务器smtp.connect(self.HOST, self.PORT)# 验证授权码smtp.login(self.FROM_ADDR, self.PASSWORD)return smtpexcept smtplib.SMTPException:raise f'验证邮箱失败:用户:{self.FROM_ADDR},授权码:{self.PASSWORD}'def get_message(self, subject: str, text: str, subtype: str):"""获取邮件信息:param subject: 主题:param text: 内容:param charset: 编码:return: str"""# 构造邮件内容# 第一个参数_text:内容# 第二个参数_subtype:格式# 第三个参数_charset:编码if subtype == "attachment":# 实例混合邮件(附件)message = MIMEMultipart()elif subtype == "embedded":# 实例内嵌的邮件(文本,HTML,图片)message = MIMEMultipart('related')else:# 实例文字邮件message = MIMEText(text, self.subtype, self.charset)# 构造邮件主题信息# 主题message['Subject'] = Header(subject, self.charset)# 发送者message['From'] = Header(self.FROM_ADDR, self.charset)# 接收者,接收者为多人[]时,需要用,拼接为字符串message['To'] = Header(','.join(to_addrs), self.charset)# 返回消息实例return messagedef attach_attachment(self, message, text: str, subtype: str, attachment_list: list[dict[str, str]]) -> None:"""附加上传附件(可多文件):param message: 邮件消息:param subtype: 邮件类型:param attachment_list: 附件列表(内嵌也一样,名称对应src="cid:name"中的name):格式[{"path":"附件路径1","name":"显示名称"},{"path":"附件路径2","name":"显示名称"}]:return: None"""# 附加正文if subtype in (Email163.ATTACHMENT, Email163.EMBEDDED):message.attach(MIMEText(text, self.subtype, self.charset))if subtype == Email163.ATTACHMENT: # 附件for item in attachment_list:with open(item["path"], 'rb') as f:file_data = f.read()# 上传文件attachment = MIMEText(file_data, 'base64', 'utf-8')# 指定消息内容为字节流attachment["Content-Type"] = 'application/octet-stream'# 消息描述,这里的filename可以随便填写,这里填写的就会在邮件中附件名称显示attachment["Content-Disposition"] = f'attachment; filename="{item["name"]}"'# 附加文件message.attach(attachment)elif subtype == Email163.EMBEDDED: # 内嵌for item in attachment_list:with open(item["path"], 'rb') as f:img_data = f.read()# 创建图片img = MIMEImage(img_data)# 定义图片ID,在HTML文本中引用img.add_header('Content-ID', item["name"])# 附加图片message.attach(img)def send_email(self, smtp: smtplib.SMTP, message: str, to_addrs: list[str]) -> None:"""发送邮件:param smtp: SMTP实例:param message: 邮件消息:return: None"""try:# 发送邮件smtp.sendmail(self.FROM_ADDR, ','.join(to_addrs), message.as_string())# 发送完邮件,关闭服务smtp.close()print(f'邮件成功发送给:{to_addrs}')except smtplib.SMTPException:raise f'给{to_addrs}发送邮件失败'def main(self, subject: str, text: str, to_addrs: list[str], subtype: str = None,attachment_list: list[dict[str, str]] = None) -> None:"""发送网易邮件:param subject: 主题:param text: 内容:param to_addrs: 接收者:param attachment_list: 附件(默认空,格式[{"path":"文件路径","name":"显示文件名"}]):return:"""# 获取SMTP实例smtp = self.get_smtp()# 获取邮件消息message = self.get_message(subject, text, subtype)# 处理附件和内嵌self.attach_attachment(message, text, subtype, attachment_list)# 发送邮件self.send_email(smtp, message, to_addrs)if __name__ == '__main__':# region 发送文本格式邮件# 实例发送网易邮件# email163 = Email163()# # 主题# subject = 'Python发送邮件'# # 内容# text = '这是使用Python发送的文本格式邮件测试!'# # 接收者(用list[str])# to_addrs = ['980338974@qq.com']# # 调用统一函数main# email163.main(subject, text, to_addrs)# endregion# 发送HTML格式,附件格式,HTML内嵌图片格式公用内容html_text = """<h1>这是使用Python发送的HTML格式邮件测试,我是h1</h1><a href="http://t.csdn.cn/p58Yf">我是一个链接</a><table><th>我是表格列头</th><tr><td bgcolor="PowderBlue">我是有颜色的表单元格</td></tr></table><h3>CSDN:</h3><img src="cid:csdn">"""# region 发送HTML格式邮件# # 实例发送网易邮件# email163_html = Email163('html')# # 主题# subject = 'Python发送邮件'# # 接收者(用list[str])# to_addrs = ['980338974@qq.com']# # 调用统一函数main# email163_html.main(subject, html_text, to_addrs)# endregion# region 发送带附件邮件# # 实例发送网易邮件# email163_html = Email163('html')# # 主题# subject = 'Python发送邮件'# # 接收者(用list[str])# to_addrs = ['980338974@qq.com']# # 调用上传附件# attachment_list = [{"path": "./attachment.txt", "name": "1.txt"}]# # 调用统一函数main# email163_html.main(subject, html_text, to_addrs, Email163.ATTACHMENT, attachment_list)# endregion# region 发送HTML内嵌图片邮件# # 实例发送网易邮件# email163_html = Email163('html')# # 主题# subject = 'Python发送邮件'# # 接收者(用list[str])# to_addrs = ['980338974@qq.com']# # 调用上传附件# attachment_list = [{"path": "./csdn.gif", "name": "csdn"}]# # 调用统一函数main# email163_html.main(subject, html_text, to_addrs, Email163.EMBEDDED, attachment_list)# endregion
总结
以上就是关于用Python发送邮件的基本用法了,还有其他的邮箱也都可以,其实方法类似,一样注册邮箱,开通服务,然后登录验证授权码,构造邮件头,构造邮件正文,上传附件…等,有啥疑问的欢迎大家评论留言,感谢大家支持!
这篇关于【Python】发送邮件,超详细看图敲码(附完整代码)一一CSDN21天学习挑战赛的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!