Python学习之旅(三十五)
Python基础知识(34):电子邮件(Ⅰ)
几乎所有的编程语言都支持发送和接收电子邮件
在使用Python收发邮件前,请先准备好至少两个电子邮件,如xxx@163.com
,xxx@sina.com
,xxx@qq.com
等,注意两个邮箱不要用同一家邮件服务商
电子邮件发送过程:
发件人email->MUA(mail user agent:邮件用户代理)->MTA(mail transfer agent:邮件传输代理)->MDA(mail delivery agent:邮件投递代理,即服务器)<-MUA<-收件人
使用SMTP发送邮件
SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件
Python对SMTP支持有smtplib
和email
两个模块,email
负责构造邮件,smtplib
负责发送邮件
注:以下所有代码本人未进行测试,故无法确定是否能够正常运行
一、发送邮件
1、构造邮件
from email.mime.text import MIMEText msg = MIMEText('Hello, world', 'plain', 'utf-8')
到构造MIMEText
对象时,第一个参数就是邮件正文,第二个参数是MIME的subtype,传入'plain'
表示纯文本,最终的MIME就是'text/plain'
,最后一定要用utf-8
编码保证多语言兼容性
2、通过SMTP发送邮件
SMTP.sendmail(from_addr, [to_addr], msg.as_string())
sendmail()
方法就是发邮件,由于可以一次发给多个人,所以传入一个list
,邮件正文是一个str
,as_string()
把MIMEText
对象变成str
必须把From
、To
和Subject
添加到MIMEText
中,才是一封完整的邮件
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr import smtplib # 考虑到编码的原因,这里统一将name属性值改成utf-8,地址的话一定是统一的邮箱地址结构,所以不考虑
def __format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr)) # 一些基本信息的定义
from_addr = input('From:')
password = input('Password:')
to_addr = input('To: ')
smtp_server = input('SMTP server: ') # 纯文本邮件定义
msg = MIMEText('Hello world!', 'plain', 'utf-8')
# 定义发送人,接收人,以及描述信息(主题)
msg['From'] = __format_addr('发件人 <%s>' % from_addr)
msg['To'] = __format_addr('收件人: <%s>' % to_addr)
msg['Subject'] = Header('SMTP......', 'utf-8').encode() print(msg)
结果如下
From:xxx@163.com
Password:1234
To: xxxxx@qq.com
SMTP server: smtp.163.com
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
From: =?utf-8?b?5Y+R5Lu25Lq6?= <xxx@163.com>
To: xxxxx@qq.com
Subject: =?utf-8?b?U01UUC4uLi4uLg==?= SGVsbG8gd29ybGQh
二、发送HTML邮件
在构造MIMEText
对象时,把HTML字符串传进去,再把第二个参数由plain
变为html
msg = MIMEText('<html><body><h1>Hello</h1>' +
'<p>send by <a href="http://www.python.org">Python</a>...</p>' +
'</body></html>', 'html', 'utf-8')
三、发送附件
带附件的邮件可以看做包含若干部分的邮件:文本和各个附件本身,所以,可以构造一个MIMEMultipart
对象代表邮件本身,然后往里面加上一个MIMEText
作为邮件正文,再继续往里面加上表示附件的MIMEBase
对象即可
# 邮件对象:
msg = MIMEMultipart()
msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode() # 邮件正文是MIMEText:
msg.attach(MIMEText('send with file...', 'plain', 'utf-8')) # 添加附件就是加上一个MIMEBase,从本地读取一个图片:
with open('/Users/michael/Downloads/test.png', 'rb') as f:
# 设置附件的MIME和文件名,这里是png类型:
mime = MIMEBase('image', 'png', filename='test.png')
# 加上必要的头信息:
mime.add_header('Content-Disposition', 'attachment', filename='test.png')
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '')
# 把附件的内容读进来:
mime.set_payload(f.read())
# 用Base64编码:
encoders.encode_base64(mime)
# 添加到MIMEMultipart:
msg.attach(mime)
按正常发送流程把msg
(注意类型已变为MIMEMultipart
)发送出去
四、发送图片
不能直接在HTML邮件中链接图片地址,因为大部分邮件服务商都会自动屏蔽带有外链的图片,因为不知道这些链接是否指向恶意网站
要把图片嵌入到邮件正文中,只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"
就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x
即可
把上面代码加入MIMEMultipart
的MIMEText
从plain
改为html
,然后在适当的位置引用图片
msg.attach(MIMEText('<html><body><h1>Hello</h1>' +
'<p><img src="cid:0"></p>' +
'</body></html>', 'html', 'utf-8'))
五、同时支持HTML和Plain格式
如果收件人使用的设备太古老,查看不了HTML邮件,必须在发送HTML的同时再附加一个纯文本,如果收件人无法查看HTML格式的邮件,就可以自动降级查看纯文本邮件
利用MIMEMultipart
就可以组合一个HTML和Plain,要注意指定subtype是alternative
msg = MIMEMultipart('alternative')
msg['From'] = ...
msg['To'] = ...
msg['Subject'] = ... msg.attach(MIMEText('hello', 'plain', 'utf-8'))
msg.attach(MIMEText('<html><body><h1>Hello</h1></body></html>', 'html', 'utf-8'))
# 正常发送msg对象...
六、加密SMTP
想要更安全地发送邮件,防止发送的邮件被窃听,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件
只需要在创建SMTP
对象后,立刻调用starttls()
方法,就创建了安全连接
smtp_server = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代码和前面的一模一样:
server.set_debuglevel(1)
Python学习之旅(三十五)的更多相关文章
- python学习之旅(十五)
Python基础知识(14):函数(Ⅴ) 一.装饰器 decorator:本质上就是函数,可以增强函数的功能. 定义起来虽然有点复杂,但使用起来非常灵活和方便 1.不修改被装饰函数的源代码 2.不修改 ...
- Python学习笔记(三十五)—内置模块(4)struct
摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431955007 ...
- Python学习笔记【第十五篇】:Python网络编程三ftp案例练习--断点续传
开发一个支持多用户在线的FTP程序-------------------主要是学习思路 实现功能点 1:用户登陆验证(用户名.密码) 2:实现多用户登陆 3:实现简单的cmd命令操作 4:文件的上传( ...
- Dynamic CRM 2013学习笔记(三十五)自定义审批流6 - 审批通过后,再审批 - 二次审批
最近有个特殊的需求,客户想做二次审批,就是审批通过后,再走一次审批流程.最开始一想,这还不简单,审批通过后,直接把状态改成draft就完了,后来一试,发现一堆问题,比如第一次审批完后,界面是不允许修改 ...
- Python学习之旅(十二)
Python基础知识(11):高级特性 一.分片(切片) 通过索引来获取一定范围内的元素 #字符串 s="Alice" s[0:4:2] 结果: 'Ai' #列表 l=[1,2,3 ...
- python接口自动化(三十五)-封装与调用--流程类接口关联(详解)
简介 流程相关的接口,主要用 session 关联,如果写成函数(如上篇),s 参数每个函数都要带,每个函数多个参数,这时候封装成类会更方便.在这里我们还是以博客园为例,带着小伙伴们实践一下. 接口封 ...
- 学习之路三十五:Android和WCF通信 - 大数据压缩后传输
最近一直在优化项目的性能,就在前几天找到了一些资料,终于有方案了,那就是压缩数据. 一丶前端和后端的压缩和解压缩流程 二丶优点和缺点 优点:①字符串的压缩率能够达到70%-80%左右 ②字符串数量更少 ...
- python学习之【第十五篇】:Python中的常用模块之time模块
1.前言 在Python中,对时间的表示或操作通常要使用到time模块.本篇博文就来记录一下time模块中常用的几种时间表示转换方法. 2. 三种时间表示形式 2.1 时间戳 从1970年1月1日零点 ...
- 流畅python学习笔记:第十五章:上下文管理器
在开始本章之前,我们首先来谈谈try-excep..final模块.在Python中,进行异常保护的最多就是用try..except..final.首先来看下下面的代码.进行一个简单的除法运算.为了防 ...
- Python之路(第三十五篇) 并发编程:操作系统的发展史、操作系统的作用
一.操作系统发展史 第一阶段:手工操作 —— 真空管和穿孔卡片 第一代之前人类是想用机械取代人力,第一代计算机的产生是计算机由机械时代进入电子时代的标志,从Babbage失败之后一直到第二次世界大 ...
随机推荐
- 使用python实现深度神经网络 4(转)
https://blog.csdn.net/oxuzhenyi/article/details/73026807 使用浅层神经网络识别图片中的英文字母 一.实验介绍 1.1 实验内容 本次实验我们正式 ...
- 机械臂运动学逆解(Analytical solution)
计算机器人运动学逆解首先要考虑可解性(solvability),即考虑无解.多解等情况.在机器人工作空间外的目标点显然是无解的.对于多解的情况从下面的例子可以看出平面二杆机械臂(两个关节可以360°旋 ...
- Xcode10.1 import头文件无法索引
如下路径,修改设置 Xcode --> File --> Workspace Settings --> Build System --> Legacy Build System
- m3u8转码
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 0 -hls_time 5 output.m3u8
- [转]linux用户管理
Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系统管理员对使用系统的用户进行 ...
- redis 4.0.8 源码包安装集群
系统:centos 6.9软件版本:redis-4.0.8,rubygems-2.7.7,gcc version 4.4.7 20120313,openssl-1.1.0h,zlib-1.2.11 y ...
- lua 源码分析之线程对象lua_State
lua_State 中放的是 lua 虚拟机中的环境表.注册表.运行堆栈.虚拟机的上下文等数据. 从一个主线程(特指 lua 虚拟机中的线程,即 coroutine)中创建出来的新的 lua_Stat ...
- C# 中字符串转换成日期
我们在处理字符串日期格式常用DateTime.Pares() 但是这个形式的转换是相当有限的,有些C#是会不懂你写入的日期格式的如20031231.那么类似 "20100101" ...
- Gradle 打可执行jar包
初次使用Gradle,想和maven一样,把gradle项目打成可执行jar包,具体步骤: 1.下载gradle 版本,并配置环境变量, 下载地址:https://gradle.org/release ...
- const的位置问题
来源:牛客网 下列哪两个是等同的 int b; 1.const int *a = &b; 2.const * int a = &b; 3.const int* const a = &a ...