Python基于SMTP协议实现发送邮件功能详解


Posted in Python onAugust 14, 2018

本文实例讲述了Python基于SMTP协议实现发送邮件功能。分享给大家供大家参考,具体如下:

SMTP(Simple Mail Transfer Protocol),即简单邮件传输协议,它是一组由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。

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

Python创建SMTP语法如下:

import smtplib
smtpObj = mstplib.SMTP(host,port)

创建具有SSL协议的SMTP:

import smtplib
smtpObj = mstplib.SMTP_SSL(host,port)

使用SMTP对象发送邮件:

# from_addr:发送者邮箱
# to_addrs:接收者邮箱,list
# msg:消息体
smtpObj.sendmail(from_addr, to_addrs, msg, mail_options=[],
         rcpt_options=[])

接下来的示例都是以网易邮箱作为邮箱服务器来写的,网易163免费邮箱相关服务器信息如下:

Python基于SMTP协议实现发送邮件功能详解

使用网易邮箱作为发送者邮箱时应注意,邮箱密码并非为邮箱的登录密码,而是客户端授权密码。

发送纯文本邮件

首先,我们需要构造一个消息体:

from email.header import Header
from email.mime.text import MIMEText
# 第一个参数为邮件正文,第二个参数为MINE的subtype,传入‘plain',最终的MINE就是‘text/plain',最后参数为编码
msg = MIMEText('hello email','palin','utf-8')
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
# 发送者昵称
msg['From'] = _format_addr('发送者昵称 <%s>'%from_addr) 
# 接收者昵称
msg['To'] = _format_addr('接收者昵称 <%s>'%to_addr)
# 标题
msg['Subject'] = Header('标题','utf-8').encode()

此时就构造了一个简单的消息体。切记,如果未指定标题以及昵称,并且将其格式化编码,有可能会被认为是辣鸡邮件而导致发送失败!!!

以下就是发送纯文本邮件示例的完整代码:

import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.utils import formataddr,parseaddr
host = 'smtp.163.com'
port = 25
from_addr = 'xxxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxxx@qq.com'
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
msg = MIMEText('hello email','palin','utf-8')
msg['From'] = _format_addr('发送者昵称 <%s>'%from_addr) 
msg['To'] = _format_addr('接收者昵称 <%s>'%to_addr)
msg['Subject'] = Header('标题','utf-8').encode()
smtpObj = smtplib.SMTP(host,25)
smtpObj.set_debuglevel(1)
smtpObj.login(sender,password)
smtpObj.sendmail(sender, [receivers], message.as_string())
smtoObj.quit()

值得注意的是,调用sendmail方法时,接收者邮箱为一个list类型,用于群发功能。

发送HTML邮件

如果有发送HTML邮件的需求,此时我们仍需先够着一个MIMEText对象,将html字符串传递进来,如下:

htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>Hello SMTP</h1>
  <p>点击<a href="https://www.baidu.com" rel="external nofollow" rel="external nofollow" >链接</a></p>
</body>
</html>'''
msg = MIMEText(htmlStr,'html','utf-8')

完整代码如下:

import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr,parseaddr
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>Hello SMTP</h1>
  <p>点击<a href="https://www.baidu.com" rel="external nofollow" rel="external nofollow" >链接</a></p>
</body>
</html>'''
msg = MIMEText(htmlStr,'html','utf-8')
msg['From'] = _format_addr("发送者 <%s>"%from_addr)
msg['To'] = _format_addr("接收者 <%s>"%to_addr)
msg['Subject'] = Header('一个简单的标题','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

发送附件邮件

如果我们有发送附件的需求时,我们该如何改造消息体呢?我们此时可以用MIMEMultipart构造邮件的本身,传递一个MIMEText对象来写入邮件的正文,再用MIMEBase对象存储附件的信息即可,代码如下:

msg = MIMEMultipart()
msg.attach(MIMEText('发送一个附件...','plain','utf-8'))
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  # 设置附件的MIME
  mime = MIMEBase('image','png',filename='1.png')
  # 加上必要的头信息
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  # 读取文件内容
  mime.set_payload(f.read())
  # 使用base64编码
  encode_base64(mime)
  msg.attach(mime)

完整代码如下:

import smtplib,os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart,MIMEBase
from email.header import Header
from email.encoders import encode_base64
from email.utils import formataddr,parseaddr
msg = MIMEMultipart()
msg.attach(MIMEText('发送一个附件...','plain','utf-8'))
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  mime = MIMEBase('image','png',filename='1.png')
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  mime.set_payload(f.read())
  encode_base64(mime)
  msg.attach(mime)
msg['From'] = _format_addr("发送者 <%s>"%from_addr)
msg['To'] = _format_addr("接收者 <%s>"%to_addr)
msg['Subject'] = Header('一个简单的附件邮件','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

发送图片邮件

如果我们需要在一段文本中插入图片作为邮件正文,那么我们该如何实现呢?有人会想用HTML,在里面嵌一个img标签就可以了,但是这样有一个问题,因为img标签是引用一个图片路径的,我们总不能将图片文件也发送过去吧。那么久没有办法了吗,当然有,我们可以结合HTML与附件邮件发送方式来发送图片邮件,首先我们将图片以附件的形式添加进来,再以HTML中img标签引用src='cid:0',就可以将图片引用进来了,如下:

msg = MIMEMultipart()
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  mime = MIMEBase('image','png',filename='1.png')
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  mime.set_payload(f.read())
  encode_base64(mime)
  msg.attach(mime)
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>图片标题</h1>
  <p>插入一个图片<img src="cid:0"/></p>
</body>
</html>'''
msg.attach(MIMEText(htmlStr,'html','utf-8'))

完整代码如下:

import smtplib,os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart,MIMEBase
from email.header import Header
from email.encoders import encode_base64
from email.utils import parseaddr,formataddr
server = 'smtp.163.com'
from_addr = 'xxx@163.com'
from_addr_pwd = 'xxxxxx'
to_addr = 'xxx1@qq.com'
def _format_addr(s):
  name,addr = parseaddr(s)
  return formataddr((Header(name,'utf-8').encode(),addr.encode('utf-8') if isinstance(addr,unicode) else addr))
msg = MIMEMultipart()
path = os.path.join(os.getcwd(),'1.png')
with open(path,'rb') as f:
  # 设置附件的MIME
  mime = MIMEBase('image','png',filename='1.png')
  # 加上必要的头信息
  mime.add_header('Content-Disposition','attachment',filename='1.png')
  mime.add_header('Content-ID','<0>')
  mime.add_header('X-Attachment-Id','0')
  # 读取文件内容
  mime.set_payload(f.read())
  # 使用base64编码
  encode_base64(mime)
  msg.attach(mime)
htmlStr = '''
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>图片标题</h1>
  <p>插入一个图片<img src="cid:0"/></p>
</body>
</html>'''
msg.attach(MIMEText(htmlStr,'html','utf-8'))
msg['From'] = _format_addr('发送者 <%s>'%from_addr)
msg['To'] = _format_addr('接收者 <%s>'%to_addr)
msg['Subject'] = Header('发送图片邮件','utf-8').encode()
smtpObj = smtplib.SMTP(server,25)
smtpObj.set_debuglevel(1)
smtpObj.login(from_addr,from_addr_pwd)
smtpObj.sendmail(from_addr,[to_addr],msg.as_string())
smtpObj.quit()

如果有多个图片,给它们依次编号,然后引用不同的cid:x即可。

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python实现的tab文件操作类分享
Nov 20 Python
Python中支持向量机SVM的使用方法详解
Dec 26 Python
python自动查询12306余票并发送邮箱提醒脚本
May 21 Python
python3爬虫怎样构建请求header
Dec 23 Python
python3中类的继承以及self和super的区别详解
Jun 26 Python
Django 开发环境配置过程详解
Jul 18 Python
Python 实现文件读写、坐标寻址、查找替换功能
Sep 11 Python
Django实现分页显示效果
Oct 31 Python
python中round函数如何使用
Jun 19 Python
一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系
Jul 03 Python
python 使用elasticsearch 实现翻页的三种方式
Jul 31 Python
Python监听剪切板实现方法代码实例
Nov 11 Python
selenium+python实现1688网站验证码图片的截取功能
Aug 14 #Python
django+xadmin+djcelery实现后台管理定时任务
Aug 14 #Python
Python延时操作实现方法示例
Aug 14 #Python
详解PyCharm配置Anaconda的艰难心路历程
Aug 13 #Python
python 实现A*算法的示例代码
Aug 13 #Python
Python绘制KS曲线的实现方法
Aug 13 #Python
Python标准库shutil用法实例详解
Aug 13 #Python
You might like
PHP脚本的10个技巧(2)
2006/10/09 PHP
php调用mysql存储过程
2007/02/14 PHP
使用 PHPStorm 开发 Laravel
2015/03/24 PHP
thinkphp中多表查询中防止数据重复的sql语句(必看)
2016/09/22 PHP
php中各种定义变量的方法小结
2017/10/18 PHP
stripos函数知识点实例分享
2019/02/11 PHP
PHP中上传文件打印错误错误类型分析
2019/04/14 PHP
PHP与Web页面的交互示例详解二
2020/08/04 PHP
javascript 事件绑定问题
2011/01/01 Javascript
jQuery基础框架浅入剖析
2012/12/27 Javascript
基于JQuery的列表拖动排序实现代码
2013/10/01 Javascript
JS 弹出层 定位至屏幕居中示例
2014/05/21 Javascript
Javascript中的关键字和保留字整理
2014/10/16 Javascript
express的中间件cookieParser详解
2014/12/04 Javascript
深入了解JavaScript中的Symbol的使用方法
2015/07/28 Javascript
个人网站留言页面(前端jQuery编写、后台php读写MySQL)
2016/05/03 Javascript
学习Angularjs分页指令
2016/07/01 Javascript
JS正则匹配URL网址的方法(可匹配www,http开头的一切网址)
2017/01/06 Javascript
js 原型对象和原型链理解
2017/02/09 Javascript
webpack学习教程之前端性能优化总结
2017/12/05 Javascript
使用vue自定义指令开发表单验证插件validate.js
2019/05/23 Javascript
vue 清空input标签 中file的值操作
2020/07/21 Javascript
vue-cli3中配置alias和打包加hash值操作
2020/09/04 Javascript
Python用list或dict字段模式读取文件的方法
2017/01/10 Python
CentOS中升级Python版本的方法详解
2017/07/10 Python
python 利用栈和队列模拟递归的过程
2018/05/29 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
利物浦足球俱乐部官方网上商店:Liverpool FC Official Store
2018/01/13 全球购物
声明struct x1 { . . . }; 和typedef struct { . . . }x2;有什么不同
2012/06/02 面试题
写一个在SQL Server创建表的SQL语句
2012/03/10 面试题
挂职思想汇报
2013/12/31 职场文书
入党现实表现材料
2014/12/23 职场文书
商业计划书之服装
2019/09/09 职场文书
MySQL 覆盖索引的优点
2021/05/19 MySQL
【2·13】一图读懂中国无线电发展
2022/02/18 无线电
python内置模块之上下文管理contextlib
2022/06/14 Python