大师兄的Python学习笔记(十六): FTP与ftplib
大师兄的Python学习笔记(十八): Python与HTTP
一、关于电子邮件
1. 电子邮件的传输概念
简称 | 全称 | 含义 |
---|---|---|
MUA | Mail User Agent | 接收邮件所使用的邮件客户端,使用IMAP或POP3协议与服务器通信 |
MTA | Mail Transfer Agent | 通过SMTP协议发送、转发邮件 |
MDA | Mail Deliver Agent | 将MTA接收到的邮件保存到磁盘或指定地方,通常会进行垃圾邮件及病毒扫描 |
MRA | Mail Receive Agent | 负责实现IMAP与POP3协议,与MUA进行交互 |
SMTP | Simple Mail Transfer Protocol | 传输发送邮件所使用的标准协议 |
IMAP | Internet Message Access Protocol | 接收邮件使用的标准协议之一 |
POP3 | Post Office Protocol 3 | 接收邮件使用的标准协议之一 |
2. 电子邮件的发送之路
1) Email从MUA发出
- 发送方客户端:比如outlook等。
2) Email发到MTA
- 发送方的Email服务提供商,比如hotmail、新浪等。
- 可能会途经多个MTA。
3)Email发送到MDA
- 接收方的Email服务提供商,比如网易、gamil等。
- 可能会途径多个MTA。
4)通过MUA将邮件接收到本地
接收方客户端:比如foxmail等
二、Mail编程
Mail编程只需要关注三个环节:
- 从发送方的MUA把邮件发到MTA
- 从接收方的MUA把邮件从MDA接收到本地
- 解析和撰写邮件
1. 发送邮件
1.1 关于SMTP协议
- SMTP是一种提供可靠且有效的电子邮件传输的协议。
- SMTP是建立在FTP文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。
- SMTP协议位于OSI七层模型的应用层。
1.2 关于smtplib模块
- smtplib模块是Python提供的工具,他对SMTP协议做了简单的封装。
- 全部方法参考Python官方手册。
1) smtplib.SMTP(host, port, local_hostname)对象
- 创建SMTP对象。
- host: SMTP服务器主机。
- port: SMTP服务使用的端口号,通常为25。
- local_hostname: 如果SMTP在本地,可以提供本地名称。
2) SMTP.sendmail(from, tos, msg)方法
- 发送邮件
- from: 发送方地址(可以不提供或自定义)
- tos:接收方地址
- msg:邮件内容,通常是Message对象。
3) SMTP.login(user,password)方法
- 如果SMTP服务器需要验证用户名密码。
4) SMTP.starttls(keyfile=None, certfile=None, context=None)方法
- 将连接加入TLS模式,对套接字进行SSL加密。
>>>import smtplib >>>from email.mime.text import MIMEText >>>host = "邮箱host,比如xxx@163.com" >>>port = "邮箱port,比如25" >>>user = '邮箱用户名' >>>pwd = '邮箱密码' >>>send_from = "发送方地址" >>>send_to = "接收方地址" >>>def sort_msg(func): >>> # 处理邮件内容 >>> def wrapper(arg): >>> func(MIMEText(arg, 'plain', 'utf-8')) >>> return wrapper >>>@sort_msg >>>def send_msg(msg): >>> try: >>> with smtplib.SMTP(host,port) as smtpObj: # 创建smtp对象 >>> print('登录邮件服务器.') >>> smtpObj.login(user,pwd) # 登录邮件服务器 >>> print('发送邮件...') >>> smtpObj.sendmail(send_from,send_to,msg.as_string()) # 发送邮件 >>> print('断开连接.') >>> except smtplib.SMTPException as e: >>> print(f'发送邮件失败:{e}') >>> >>>if __name__ == '__main__': >>> send_msg('发送邮件测试...') # msg也可以是更复杂的Message对象 登录邮件服务器. 发送邮件... 断开连接.
2. 接收邮件
2.1 关于POP协议
- POP协议,邮局协议(Post Office Protocol), 用于电子邮件的接收。
- 常用第三版 ,所以简称为POP3。
2.2 关于poplib模块
- poplib模块是Python提供的内置工具。
- 可以通过套接字将邮件从MDA抓取到本地。
- 全部方法参考Python官方手册。
1) poplib.POP3(host,port,timeout)
- 创建POP3连接对象。
2) poplib.POP3_SSL()
- SSL加密。
3) POP3.set_debuglevel(level)
- 设置调试模式,可以看到与服务器的交互信息。
4) POP3.getwelcome()
- 获取邮件服务器欢迎信息。
5) POP3.user(username)
- 用户名验证。
6) POP3.pass_(password)
- 密码验证。
7) POP3.apop(user, secret)
- 用更安全的apop模式登陆。
8) POP3.rpop(user)
- 用rpop模式登陆。
9) POP3.stat()
- 获取邮箱中信件信息。
10) POP3.list([which])
- 返回邮件数量和每个邮件的大小。
11) POP3.retr(which)
- 收取邮件。
12) POP3.dele(which)
- 删除邮件。
13) POP3.rset()
- 服务器将重置所有标记为删除的邮件,用于撤消POP3.dele()命令。
14) POP3.delePOP3.noop()
- 什么也不做,用于保持在线。
15) POP3.quit()
- 确认变更,登出邮箱,断开服务器。
16) POP3.top(which, howmuch)
- 检索邮件标题,以及<howmuch>行内容简要。
- 这个指令不会让邮件变成已读状态。
>>>import poplib >>>from pprint import pprint >>>class Client: >>> def __init__(self): >>> self.host = '邮箱地址' >>> self.user = '用户名' >>> self.pwd = '密码' >>> def login(self): >>> print('登录邮件服务...') >>> try: >>> server = poplib.POP3(self.host) >>> # 登录邮箱 >>> server.user(self.user) >>> server.pass_(self.pwd) >>> self.server = server >>> print(server.getwelcome()) >>> except Exception as e: >>> print(f'登录失败:e') >>> def get_mail_list(self): >>> # 获得邮箱目录 >>> if(not self.server): return >>> msgCount,msgBytes = self.server.stat() >>> print(f'共有:{msgCount}封邮件,大小:{msgBytes}字节') >>> print(self.server.list()) >>> print(f'{"-"*20}') >>> def get_last_mail(self): >>> # 读取最新的一封邮件 >>> if (not self.server): return >>> msgCount, msgBytes = self.server.stat() >>> head,msg,octets = self.server.retr(msgCount) >>> msg = b'\r\n'.join(msg).decode('utf-8') >>> print(f'邮件标题:{head.decode()}') >>> print(f'大小:{octets}字节') >>> pprint(f'{msg}') // msg还需要被解析成为Message对象 >>> def quit(self): >>> if (not self.server): return >>> self.server.quit() >>> print('断开服务器.') >>>if __name__ == '__main__': >>> client = Client() >>> client.login() >>> client.get_mail_list() >>> client.get_last_mail() >>> client.quit()
3. 解析和撰写邮件
3.1 关于email包
- email包是一个强大的工具集合,能够自动完成解析和撰写邮件信息背后的繁杂工作。
- email包的接口操作围绕着Message对象。
- email包的Python官方文档。
3.2 关于Message对象
- message对象的Python官方文档。
- message对象包含三类主要信息:
标题 | 说明 |
---|---|
类型 | 内容的类型,文本、HTML、图像,用MIME主类型及子类型表示,比如:text/html。 |
题头 | 一个类似字典的映射接口,比如From、to、Cc等常用邮件题头。 |
内容 | 可以是简单的字符串,也可以是Message对象组成的列表。 |
3.3 撰写邮件
1) 撰写简单邮件
>>>from email.message import Message >>>mail = Message() # 创建MESSAGE对象 >>>mail['subject'] = 'mail title' >>>mail['from'] = 'sender@test.com' >>>mail['to'] = 'receiver1@test.com' >>>mail['Cc'] = 'receiver2@test.com' >>>mail.set_payload('Hello World!') >>>print(mail) subject: mail title from: sender@test.com to: receiver1@test.com Cc: receiver2@test.com Hello World!
2) 撰写带附件的邮件
- Message对象的负载部分由字符串变为Message对象组成的列表。
>>>from email.mime.multipart import MIMEMultipart >>>from email.mime.text import MIMEText >>>import os >>># 根Message >>>mail_top = MIMEMultipart() >>>mail_top['subject'] = 'mail title' >>>mail_top['from'] = 'sender@test.com' >>>mail_top['to'] = 'receiver1@test.com' >>>mail_top['Cc'] = 'receiver2@test.com' >>># 子Message1,文字信息 >>>mail_sub1 = MIMEText('Hello World!\n') >>>mail_top.attach(mail_sub1) >>># 子Message2,附件 >>>mail_sub2 = MIMEText(open(os.path.join('d:\\','test.txt')).read()) >>>mail_sub2.add_header('Content-Disposition','attachment',fiename='test.txt') >>>mail_top.attach(mail_sub2) >>>print(mail_top) Content-Type: multipart/mixed; boundary="===============1263352342158858646==" MIME-Version: 1.0 subject: mail title from: sender@test.com to: receiver1@test.com Cc: receiver2@test.com --===============1263352342158858646== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Hello World! --===============1263352342158858646== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; fiename="test.txt" --===============1263352342158858646==--
3) 撰写带图片附件的邮件
>>>from email.mime.multipart import MIMEMultipart >>>from email.mime.image import MIMEImage >>>import os >>># 根Message >>>mail_top = MIMEMultipart() >>>mail_top['subject'] = 'mail title' >>>mail_top['from'] = 'sender@test.com' >>>mail_top['to'] = 'receiver1@test.com' >>>mail_top['Cc'] = 'receiver2@test.com' >>># 子Message图片附件 >>>mail_sub2 = MIMEImage(open(os.path.join('d:\\','test.jpg'),'rb').read()) >>>mail_sub2.add_header('Content-Disposition','attachment',fiename='test.jpg') >>>mail_top.attach(mail_sub2) >>>print(mail_top.as_string()) Content-Type: multipart/mixed; boundary="===============9092138279492849864==" MIME-Version: 1.0 subject: mail title from: sender@test.com to: receiver1@test.com Cc: receiver2@test.com > --===============9092138279492849864== Content-Type: image/png MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; fiename="test.jpg" iVBORw0KGgoAAAANSUhEUgAAAiwAAADrCAIAAAGyYGoNAAAAAXNSR0IArs4c6QAA>AARnQU1BAACx jwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAEdZSURBVHhe7Z35l61VeefzF/RavVb/>0qtXJyaU ... ...
3.4 解析邮件
- 将邮件内容解析成为Message对象。
1) 解析邮件
- 使用内置工具
Parser()
一步就可以将邮件解析成Message对象。- 即是是包含附件的邮件现在也可以解析。
>>>from email.parser import Parser >>>received_text= "subject: mail title,\nfrom: sender@test.com,\nto: receiver1@test.com,\nCc: >>>>receiver2@test.com,\nHello World!" # 示例字符串 >>>mail = Parser().parsestr(received_text) # 解析成为Message对象 >>>print(mail['subject']) >>>print(mail['to']) mail title, receiver1@test.com,
2) 解析地址
- 使用
email.tuils.parseaddr
函数可以将标准邮件地址解析成名字和地址。>>>from email.parser import Parser >>>from email.utils import parseaddr >>>text= mail_top.as_string() >>>mail = Parser().parsestr(text) # 解析成为Message对象 >>>print(mail['to']) # 获取的地址 "Donald Trump" <trump@dump.com> >>>name,addr = parseaddr(mail['to']) # 解析地址 >>>print(f'name:{name}') >>>print(f'address:{addr}') name:Donald Trump address:trump@dump.com
3) 名称解码
- 使用
email.header.decode_header
在不转码的情况下获得编码的邮件内容,比如subject。>>>from email.header import decode_header >>>s = decode_header('=?iso-8859-1?q?p=F6stal?=') >>>print(s) [(b'p\xf6stal', 'iso-8859-1')]
4) 遍历Message对象
- 可以使用
Message.walk()
方法获得Message对象树的生成器。>>>from email.mime.multipart import MIMEMultipart >>>from email.mime.image import MIMEImage >>>from email.mime.text import MIMEText >>>import os >>># 根Message >>>mail_top = MIMEMultipart() >>>mail_top['subject'] = b'+OK Welcome to coremail Mail Pop3 Server (163coms[10774b260cc7a37d26d71b52404dcf5cs])' >>>mail_top['from'] = 'test <test@test.com>' >>>mail_top['to'] = '"Donald Trump" <trump@dump.com>' >>>mail_top['Cc'] = 'receiver2@test.com' >>># 子Message文字部分 >>>mail_sub1 = MIMEText('Hello World!','plain', 'utf-8') >>>mail_top.attach(mail_sub1) >>># 子Message图片附件 >>>mail_sub2 = MIMEImage(open(os.path.join('d:\\','test.jpg'),'rb').read()) >>>mail_sub2.add_header('Content-Disposition','attachment',fiename='test.jpg') >>>mail_top.attach(mail_sub2) >>>for part in mail_top.walk(): # 获得对象树的生成器 >>> print(part.get_content_type()) multipart/mixed text/plain image/png
参考资料
- https://blog.csdn.net/u010138758/article/details/80152151 J-Ombudsman
- https://www.cnblogs.com/zhuluqing/p/8832205.html moisiet
- https://www.runoob.com 菜鸟教程
- http://www.tulingxueyuan.com/ 北京图灵学院
- http://www.imooc.com/article/19184?block_id=tuijian_wz#child_5_1 两点水
- https://blog.csdn.net/weixin_44213550/article/details/91346411 python老菜鸟
- https://realpython.com/python-string-formatting/ Dan Bader
- https://www.liaoxuefeng.com/ 廖雪峰
- https://blog.csdn.net/Gnewocean/article/details/85319590 新海说
- https://www.cnblogs.com/Nicholas0707/p/9021672.html Nicholas
- https://www.cnblogs.com/dalaoban/p/9331113.html 超天大圣
- https://blog.csdn.net/zhubao124/article/details/81662775 zhubao124
- https://blog.csdn.net/z59d8m6e40/article/details/72871485 z59d8m6e40
- 《Python学习手册》Mark Lutz
- 《Python编程 从入门到实践》Eric Matthes
本文作者:大师兄(superkmi)
网友评论