Python学习之旅(三十五)

Python基础知识(34):电子邮件(Ⅰ)

几乎所有的编程语言都支持发送和接收电子邮件

在使用Python收发邮件前,请先准备好至少两个电子邮件,如[email protected][email protected][email protected]等,注意两个邮箱不要用同一家邮件服务商

电子邮件发送过程:

发件人email->MUA(mail user agent:邮件用户代理)->MTA(mail transfer agent:邮件传输代理)->MDA(mail delivery agent:邮件投递代理,即服务器)<-MUA<-收件人

使用SMTP发送邮件

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

Python对SMTP支持有smtplibemail两个模块,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,邮件正文是一个stras_string()MIMEText对象变成str

必须把FromToSubject添加到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:[email protected].com
Password:1234
To: [email protected]
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?= <[email protected]>
To: [email protected]
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‘, ‘0‘)
    # 把附件的内容读进来:
    mime.set_payload(f.read())
    # 用Base64编码:
    encoders.encode_base64(mime)
    # 添加到MIMEMultipart:
    msg.attach(mime)

按正常发送流程把msg(注意类型已变为MIMEMultipart)发送出去

四、发送图片

不能直接在HTML邮件中链接图片地址,因为大部分邮件服务商都会自动屏蔽带有外链的图片,因为不知道这些链接是否指向恶意网站

要把图片嵌入到邮件正文中,只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x即可

把上面代码加入MIMEMultipartMIMETextplain改为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)

原文地址:https://www.cnblogs.com/finsomway/p/10126024.html

时间: 2024-08-29 14:32:53

Python学习之旅(三十五)的相关文章

Python学习笔记(三十五)struct

摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431955007656a66f831e208e4c189b8a9e9f3f25ba53000 Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换. struct的pack函数把任意数据类型变成bytes: >>> import struct >>> struc

【WPF学习】第三十五章 资源字典

原文:[WPF学习]第三十五章 资源字典 如果希望在多个项目之间共享资源,可创建资源字典.资源字典只是XAML文档,除了存储希望使用的资源外,不做其他任何事情. 一.创建资源字典 下面是一个资源字典示例,它包含一个资源: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/wi

Dynamic CRM 2013学习笔记(三十五)自定义审批流6 - 审批通过后,再审批 - 二次审批

最近有个特殊的需求,客户想做二次审批,就是审批通过后,再走一次审批流程.最开始一想,这还不简单,审批通过后,直接把状态改成draft就完了,后来一试,发现一堆问题,比如第一次审批完后,界面是不允许修改的,直接改成draft就又可以修改了:再比如审批活动记录的查找以及死循环的问题等等.于是自己动手单独写了一个公用的再审批插件,下面介绍详细的实现步骤:   一.添加字段以控制再审批的次数 添加一个字段 new_approval_count, 再审批一次就把它加1.如果只要再审批一次,那么大于1就退出

Python学习之旅(十二)

Python基础知识(11):高级特性 一.分片(切片) 通过索引来获取一定范围内的元素 #字符串 s="Alice" s[0:4:2] 结果: 'Ai' #列表 l=[1,2,3,4,5,6] l[0:2] 结果: [1, 2] #元组 t=(1,2,3,"a","b","c") t[:] 结果: (1, 2, 3, 'a', 'b', 'c') 二.迭代 给定一个元组或列表,通过for循环遍历,这种遍历称为迭代 def t

python接口自动化(三十五)-封装与调用--流程类接口关联(详解)

简介 流程相关的接口,主要用 session 关联,如果写成函数(如上篇),s 参数每个函数都要带,每个函数多个参数,这时候封装成类会更方便.在这里我们还是以博客园为例,带着小伙伴们实践一下. 接口封装大致流程 1.在接口测试中,有些接口经常会被用到比如登录的接口,这时候我们可以每个接口都封装成一个方法,如:登录.保存草稿.发布随笔.删除随笔,这四个接口就可以写成四个方法 2.接口封装好了后,后面我们写用例那就直接调用封装好的接口就行了,有些参数,可以参数化,如保存草稿的 title 和 bod

Python学习笔记(二十五)序列化_JSON基础

摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143192607210600a668b5112e4a979dd20e4661cc9c97000 本文章完全用于个人复习使用,侵删: 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling. 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序

Python学习笔记(三十四)—内置模块(3)base64

摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431954588961d6b6f51000ca4279a3415ce14ed9d709000 Base64是一种用64个字符来表示任意二进制数据的方法. 用记事本打开exe.jpg.pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进

Python学习笔记(二十五)操作文件和目录

摘抄:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431925324119bac1bc7979664b4fa9843c0e5fcdcf1e000 Python内置的os模块也可以直接调用操作系统提供的接口函数. >>> import os >>> os.name # 操作系统类型 'nt' 如果是posix,说明系统是Linux.Unix或M

Python学习笔记(三十二)常用内建模块(1)— datetime

>>> from datetime import datetime >>> now = datetime.now() # 获取当前datetime >>> print(now) 2015-05-18 16:28:07.198690 >>> print(type(now)) <class 'datetime.datetime'> 获取指定日期和时间 要指定某个日期和时间,我们直接用参数构造一个datetime: >&g

Linux学习总结(三十五)lamp之访问日志配置

一 访问日志不记录静态文件访问信息 网站大多元素为静态文件,如图片.css.js等,记录这些访问信息对我们运维工作没有多大意义,如果一个站点访问量很大,那么一天就可以达到几GB.影响我们磁盘的工作效率,那么我们就可以配置虚拟主机限制记录这些信息.把虚拟主机配置文件改成如下: <VirtualHost *:80> DocumentRoot "/data/wwwroot/www.123.com" ServerName www.123.com ServerAlias 123.co