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实现3行代码解简单的一元一次方程
Aug 18 Python
Python安装使用命令行交互模块pexpect的基础教程
May 12 Python
浅析python实现scrapy定时执行爬虫
Mar 04 Python
python用fsolve、leastsq对非线性方程组求解
Dec 15 Python
TensorFlow的reshape操作 tf.reshape的实现
Apr 19 Python
Python发起请求提示UnicodeEncodeError错误代码解决方法
Apr 21 Python
Python Mock模块原理及使用方法详解
Jul 07 Python
如何教少儿学习Python编程
Jul 10 Python
Python通过队列来实现进程间通信的示例
Oct 14 Python
如何设置PyCharm中的Python代码模版(推荐)
Nov 20 Python
python中time、datetime模块的使用
Dec 14 Python
详解python中的三种命令行模块(sys.argv,argparse,click)
Dec 15 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设计模式 注册表模式(多个类的注册)
2012/02/05 PHP
详解php中serialize()和unserialize()函数
2017/07/08 PHP
javascript forEach通用循环遍历方法
2010/10/11 Javascript
json2.js的初步学习与了解
2011/10/06 Javascript
Textbox控件注册回车事件及触发按钮提交事件具体实现
2013/03/04 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
2013/10/18 Javascript
JavaScript中Math对象方法使用概述
2014/01/02 Javascript
js由下向上不断上升冒气泡效果实例
2015/05/07 Javascript
jquery实现两个图片渐变切换效果的方法
2015/06/25 Javascript
js中使用使用原型(prototype)定义方法的好处详解
2016/07/04 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
wap手机端解决返回上一页的js实例
2016/12/08 Javascript
JavaScript数据结构之二叉树的计数算法示例
2017/04/13 Javascript
详解Node项目部署到云服务器上
2017/07/12 Javascript
JS中Promise函数then的奥秘探究
2018/07/30 Javascript
vue监听对象及对象属性问题
2018/08/20 Javascript
vue发送ajax请求详解
2018/10/09 Javascript
小程序getLocation需要在app.json中声明permission字段
2019/04/04 Javascript
vue项目中引入Sass实例方法
2019/08/27 Javascript
vue canvas绘制矩形并解决由clearRec带来的闪屏问题
2019/09/02 Javascript
Vue 中使用富文本编译器wangEditor3的方法
2019/09/26 Javascript
JavaScript隐式类型转换代码实例
2020/05/29 Javascript
ant design vue 表格table 默认勾选几项的操作
2020/10/31 Javascript
pandas数据框,统计某列数据对应的个数方法
2018/04/11 Python
Ubuntu下Python+Flask分分钟搭建自己的服务器教程
2019/11/19 Python
Python基础之高级变量类型实例详解
2020/01/03 Python
浅谈cv2.imread()和keras.preprocessing中的image.load_img()区别
2020/06/12 Python
keras自动编码器实现系列之卷积自动编码器操作
2020/07/03 Python
公司业务主管岗位职责
2013/12/07 职场文书
物业总经理岗位职责
2014/02/28 职场文书
植树造林的宣传标语
2014/06/23 职场文书
先进个人总结范文
2015/02/15 职场文书
2015年安全生产工作总结范文
2015/04/02 职场文书
优秀学生干部主要事迹材料
2015/11/04 职场文书
python实现web邮箱扫描的示例(附源码)
2021/03/30 Python
GPU服务器的多用户配置方法
2022/07/07 Servers