Python3利用SMTP协议发送E-mail电子邮件的方法


Posted in Python onSeptember 30, 2017

前言

本文主要给大家介绍了关于Python3用SMTP协议发送电子邮件的相关内容,在介绍如何使用python程序向指定邮箱发送邮件之前,我们需要先介绍一下有关电子邮件的相关知识。

Email的历史比Web还要久远,直到现在,Email也是互联网上应用非常广泛的服务。

几乎所有的编程语言都支持发送和接收电子邮件,但是,先等等,在我们开始编写代码之前,有必要搞清楚电子邮件是如何在互联网上运作的。

假设我们自己的电子邮件地址是me@163.com,对方的电子邮件地址是friend@sina.com,现在我们用Outlook或者Foxmail之类的软件写好邮件,填上对方的Email地址,点“发送”,电子邮件就发出去了。这些电子邮件软件被称为MUA:Mail User Agent——邮件用户代理。

Email从MUA发出去,不是直接到达对方电脑,而是发到MTA:Mail Transfer Agent——邮件传输代理,就是那些Email服务提供商,比如网易、新浪等等。由于我们自己的电子邮件是163.com,所以,Email首先被投递到网易提供的MTA,再由网易的MTA发到对方服务商,也就是新浪的MTA。这个过程中间可能还会经过别的MTA,但是我们不关心具体路线,我们只关心速度。

Email到达新浪的MTA后,由于对方使用的是@sina.com的邮箱,因此,新浪的MTA会把Email投递到邮件的最终目的地MDA:Mail Delivery Agent——邮件投递代理。Email到达MDA后,就静静地躺在新浪的某个服务器上,存放在某个文件或特殊的数据库里,我们将这个长期保存邮件的地方称之为电子邮箱。对方要取到邮件,必须通过MUA从MDA上把邮件取到自己的电脑上。

所以,一封电子邮件的旅程就是:

发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人

有了上述基本概念,要编写程序来发送和接收邮件,本质上就是:

      1.编写MUA把邮件发到MTA。

      2.编写MUA从MDA上收邮件。

发邮件时,MUA和MTA使用的协议就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一个MTA也是用SMTP协议。

收邮件时,MUA和MDA使用的协议有两种:POP:Post Office Protocol,目前版本是3,俗称POP3;IMAP:Internet Message Access Protocol,目前版本是4,优点是不但能取邮件,还可以直接操作MDA上存储的邮件,比如从收件箱移到垃圾箱,等等。

邮件客户端软件在发邮件时,会让你先配置SMTP服务器,也就是你要发到哪个MTA上。假设你正在使用163的邮箱,你就不能直接发到新浪的MTA上,因为它只服务新浪的用户,所以,你得填163提供的SMTP服务器地址:smtp.163.com,为了证明你是163的用户,SMTP服务器还要求你填写邮箱地址和邮箱口令,这样,MUA才能正常地把Email通过SMTP协议发送到MTA。

类似的,从MDA收邮件时,MDA服务器也要求验证你的邮箱口令,确保不会有人冒充你收取你的邮件,所以,Outlook之类的邮件客户端会要求你填写POP3或IMAP服务器地址、邮箱地址和口令,这样,MUA才能顺利地通过POP或IMAP协议从MDA取到邮件。

最后特别注意:目前大多数邮件服务商都需要手动打开SMTP发信和POP收信的功能,否则只允许在网页登录:

比如QQ邮箱

Python3利用SMTP协议发送E-mail电子邮件的方法

接下来,我们开始我们的正题,如何通过python发送电子邮件。

--------------------------------------------------------------------------------

发送简单文本邮件

SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。

Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。

首先,我们来构造一个最简单的纯文本邮件:

from email.mime.text import MIMEText
msg = MIMEText('hello, this is axin...', 'plain', 'utf-8')

注意:到构造MIMEText对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入'plain'表示纯文本,最终的MIME就是'text/plain',最后一定要用utf-8编码保证多语言兼容性。

我们光有了正文内容还不可以,我们还需要给我们要发送的邮件添加头部信息。头部信息中包含发送者和接收者以及邮件主题等信息。

msg = MIMEText('hello, this is axin...', 'plain', 'utf-8') #邮件正文
msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #邮件头部,发送者信息
msg['To'] = _format_addr('aa <%s>' % to_addr) #接收者信息
msg['Subject'] = Header('test', 'utf-8').encode() #邮件主题

构造完我们要发送的信息后,我们只需要调用python对应的函数,通过SMTP发出去:

server = smtplib.SMTP(smtp_server, 25) #SMTP协议默认端口是25
server.set_debuglevel(1) #打印出和SMTP服务器交互的所有信息
server.login(from_addr, password) #登录SMTP服务器
server.sendmail(from_addr, [to_addr], msg.as_string()) #发送邮件
server.quit()

我们用set_debuglevel(1)就可以打印出和SMTP服务器交互的所有信息。SMTP协议就是简单的文本命令和响应。login()方法用来登录SMTP服务器,sendmail()方法就是发邮件,由于可以一次发给多个人,所以传入一个list,邮件正文是一个str,as_string()把MIMEText对象变成str。

完整代码示例如下:

from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

import smtplib

def _format_addr(s): #格式化一个邮件地址
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))

from_addr = 'fengxinlinux@sina.com' #发送者邮箱地址
password = '******' #发送者邮箱密码,不告诉你密码=。=
to_addr = '903087053@qq.com' #接收者邮箱地址
smtp_server = 'smtp.sina.com' #发送者所在的邮箱供应商的MTA地址
#from_addr = input('From: ')
#password = input('Password: ')
#to_addr = input('To: ')
#smtp_server = input('SMTP server: ')

msg = MIMEText('hello, this is axin...', 'plain', 'utf-8') #邮件正文
msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #邮件头部,发送者信息
msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息
msg['Subject'] = Header('test', 'utf-8').encode() #邮件主题


server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
server.set_debuglevel(1) #打印出和SMTP服务器交互的所有信息
server.login(from_addr, password) #登录SMTP服务器
server.sendmail(from_addr, [to_addr], msg.as_string()) #发送邮件
server.quit()
1

运行程序,我们会发现我测试的邮箱中收到了一封新的邮件。

Python3利用SMTP协议发送E-mail电子邮件的方法

我们会发现,其他的信息都一样,但是收件人的信息不是我们程序里填写的axin。

因为很多邮件服务商在显示邮件时,会把收件人名字自动替换为用户注册的名字,但是其他收件人名字的显示不受影响。

我在测试时,有时候发送的邮件会被邮件服务商判定为垃圾邮件,直接被放到垃圾箱中了。。。至于什么情况会被认定为垃圾邮件,我也摸不到头绪。。

发送带附件的邮件

上面我们介绍了如何发送文本邮件,有了上面的知识后,发送带有附件的邮件其实也非常的简单。

带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart对象代表邮件本身,然后往里面加上一个MIMEText作为邮件正文,再继续往里面加上表示附件的MIMEBase对象即可:

# 邮件对象:
msg= MIMEMultipart()
msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #邮件头部,发送者信息
msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息
msg['Subject'] = Header('test', 'utf-8').encode() #邮件主题

# 邮件正文是MIMEText:
msg.attach(MIMEText('hello, this is axin...', 'plain', 'utf-8'))

# 添加附件就是加上一个MIMEBase,从本地读取一个图片:
with open('/home/fengxin/图片/11.jpg','rb') as fhandle:
mime = MIMEBase('image','jpeg',filename='11.jpg')
mime.add_header('Content-Disposition', 'attachment', filename='11.jpg')
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
# 把附件的内容读进来:
mime.set_payload(fhandle.read())
# 用Base64编码:
encoders.encode_base64(mime)
# 添加到MIMEMultipart:
msg.attach(mime)

然后,按正常发送流程把msg(注意类型已变为MIMEMultipart)发送出去,就可以收到带附件的邮件。

完整代码示例如下:

from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase


import smtplib

def _format_addr(s): #格式化一个邮件地址
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))

from_addr = '你的邮箱地址' #发送者邮箱地址
password = '你的邮箱密码' #发送者邮箱密码
to_addr = '903087053@qq.com' #接收者邮箱地址
smtp_server = 'smtp.sina.com' #发送者所在的邮箱供应商的MTA地址
#from_addr = input('From: ')
#password = input('Password: ')
#to_addr = input('To: ')
#smtp_server = input('SMTP server: ')


msg= MIMEMultipart()
msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #邮件头部,发送者信息
msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息
msg['Subject'] = Header('test', 'utf-8').encode() #邮件主题

msg.attach(MIMEText('hello, this is axin...', 'plain', 'utf-8'))

with open('/home/fengxin/图片/11.jpg','rb') as fhandle:
mime = MIMEBase('image','jpeg',filename='11.jpg')
mime.add_header('Content-Disposition', 'attachment', filename='11.jpg')
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
# 把附件的内容读进来:
mime.set_payload(fhandle.read())
# 用Base64编码:
encoders.encode_base64(mime)
# 添加到MIMEMultipart:
msg.attach(mime)

server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
server.set_debuglevel(1) #打印出和SMTP服务器交互的所有信息
server.login(from_addr, password) #登录SMTP服务器
server.sendmail(from_addr, [to_addr], msg.as_string()) #发送邮件
server.quit()
1

运行后。测试邮箱正确收到邮件,如图:

Python3利用SMTP协议发送E-mail电子邮件的方法

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python实现在目录中查找指定文件的方法
Nov 11 Python
python使用wxPython打开并播放wav文件的方法
Apr 24 Python
浅谈Scrapy框架普通反爬虫机制的应对策略
Dec 28 Python
Python WSGI的深入理解
Aug 01 Python
python调用opencv实现猫脸检测功能
Jan 15 Python
python制作简单五子棋游戏
Jun 18 Python
Python如何爬取微信公众号文章和评论(基于 Fiddler 抓包分析)
Jun 28 Python
详解python中各种文件打开模式
Jan 19 Python
python实现将两个文件夹合并至另一个文件夹(制作数据集)
Apr 03 Python
python名片管理系统开发
Jun 18 Python
python+excel接口自动化获取token并作为请求参数进行传参操作
Nov 10 Python
python dir函数快速掌握用法技巧
Dec 09 Python
Python字符编码与函数的基本使用方法
Sep 30 #Python
详谈Python高阶函数与函数装饰器(推荐)
Sep 30 #Python
深入浅出学习python装饰器
Sep 29 #Python
Python连接phoenix的方法示例
Sep 29 #Python
Python矩阵常见运算操作实例总结
Sep 29 #Python
利用python求解物理学中的双弹簧质能系统详解
Sep 29 #Python
python中装饰器级连的使用方法示例
Sep 29 #Python
You might like
php将会员数据导入到ucenter的代码
2010/07/18 PHP
destoon之一键登录设置
2014/06/21 PHP
php使用simplexml_load_file加载XML文件并显示XML的方法
2015/03/19 PHP
smarty模板引擎之内建函数用法
2015/03/30 PHP
PHP通过CURL实现定时任务的图片抓取功能示例
2016/10/03 PHP
PHP使用curl制作简易百度搜索
2016/11/03 PHP
PHP代码重构方法漫谈
2018/04/17 PHP
Laravel 添加多语言提示信息的方法
2019/09/29 PHP
jquery remove方法应用详解
2012/11/22 Javascript
JS实现适合于后台使用的动画折叠菜单效果
2015/09/21 Javascript
表单验证插件Validation应用的实例讲解
2015/10/10 Javascript
基于JavaScript实现一定时间后去执行一个函数
2015/12/14 Javascript
BootStrap入门教程(一)之可视化布局
2016/09/19 Javascript
websocket+node.js实现实时聊天系统问题咨询
2017/05/17 Javascript
node.js express框架实现文件上传与下载功能实例详解
2019/10/15 Javascript
nodejs+express最简易的连接数据库的方法
2020/12/23 NodeJs
Python实现读取目录所有文件的文件名并保存到txt文件代码
2014/11/22 Python
python根据开头和结尾字符串获取中间字符串的方法
2015/03/26 Python
Python实现删除文件但保留指定文件
2015/06/21 Python
Python cookbook(数据结构与算法)从任意长度的可迭代对象中分解元素操作示例
2018/02/13 Python
python ssh 执行shell命令的示例
2020/09/29 Python
利用canvas实现图片下载功能来实现浏览器兼容问题
2019/05/31 HTML / CSS
HTML5调用手机摄像头拍照的实现思路及代码
2014/06/15 HTML / CSS
HTML5 移动页面自适应手机屏幕四类方法总结
2017/08/17 HTML / CSS
META-INF文件夹中的MANIFEST.MF的作用
2016/06/21 面试题
高一历史教学反思
2014/01/13 职场文书
活动总结格式范文
2014/04/26 职场文书
班主任对学生的评语
2014/04/26 职场文书
教师职位说明书
2014/07/29 职场文书
公安机关查摆剖析材料
2014/10/10 职场文书
2015年度班主任自我评价
2015/03/11 职场文书
python中pandas.read_csv()函数的深入讲解
2021/03/29 Python
HTML中table表格拆分合并(colspan、rowspan)
2021/04/07 HTML / CSS
解决Pytorch半精度浮点型网络训练的问题
2021/05/24 Python
Python干货实战之八音符酱小游戏全过程详解
2021/10/24 Python
Redis模仿手机验证码发送的实现示例
2021/11/02 Redis