前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python-Net编程

Python-Net编程

原创
作者头像
ruochen
修改2021-02-19 15:33:37
9990
修改2021-02-19 15:33:37
举报
文章被收录于专栏:若尘的技术专栏

网络编程

  • 网络:
  • 网络协议: 一套规则
  • 网络模型:
    • 七层模型-七层-理论
      • 物理层
      • 数据链路层
      • 网络层
      • 传输层
      • 会话层
      • 表示层
      • 应用层
    • 四层模型-实际应用
      • 链路层
      • 网络层
      • 传输层
      • 引用层
  • 每一层都有相应的协议负责交换信息或者协同工作
  • TCP/IP 协议族
  • IP地址:负责在网络上唯一定位一个机器
    • IP地址分ABCDE类
    • 是由四个数字段组成,每个数字段的取值是0-255
    • 192.168.xxx.xxx: 局域网ip
    • 127.0.0.1: 本机
    • IPv4, IPv6
  • 端口
    • 范围: 0-65535
      • 知名端口:0-1023
      • 非知名端口:1024-

ICP/UDP协议

  • UDP: 非安全的不面向链接的传输
    • 安全性差
    • 大小限制64kb
    • 没有顺序
    • 速度快
  • TCP
    • 基于链接的通信
  • SOCKET编程
    • socket(套接字):是一个网络通信的端点,能实现不同主机的进程通信,网络大多基于socket通信
    • 通过IP+端口定位对方并发送消息的通信机制
    • 分为UDP和TCP
    • 客户端Client,发起访问的一方
    • 服务器端Server,接受访问的一方
  • UDP编程
    • Server端流程
      1. 建立socket,socket是负责具体通信的一个实例
      2. 绑定,为创建的socket指派固定的端口和ip地址
      3. 接受对方发送内容
      4. 给对方发送反馈,此步骤为非必须步骤
    • Client端流程
      1. 建立通信的socket
      2. 发送内容到指定服务器
      3. 接受服务器给定的反馈内容
    • 服务器案例v01 ```python ''' Server端流程 1. 建立socket,socket是负责具体通信的一个实例 2. 绑定,为创建的socket指派固定的端口和ip地址 3. 接受对方发送内容 4. 给对方发送反馈,此步骤为非必须步骤 '''
代码语言:txt
复制
	# socket模块负责socket编程
代码语言:txt
复制
	import socket
代码语言:txt
复制
	# 模拟服务器的函数
代码语言:txt
复制
	def serverFunc():
代码语言:txt
复制
	    # 1. 建立socket
代码语言:txt
复制
	    # socket.AF_INET: 使用ipv4协议族
代码语言:txt
复制
	    # socket.SOCK_DGRAM: 使用UDP通信
代码语言:txt
复制
	    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
代码语言:txt
复制
	    # 2. 绑定ip和port
代码语言:txt
复制
	    # 127.0.0.1: 这个ip地址代表的是机器本身
代码语言:txt
复制
	    # 7852: 随机指定的端口号
代码语言:txt
复制
	    # 地址是一个tuple类型,(ip, port)
代码语言:txt
复制
	    addr = ("127.0.0.1", 7852)
代码语言:txt
复制
	    sock.bind(addr)
代码语言:txt
复制
	    # 3. 接受对方消息
代码语言:txt
复制
	    # 等待方式为死等,没有其他可能性
代码语言:txt
复制
	    # recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
代码语言:txt
复制
	    # 参数的含义是缓冲区大小
代码语言:txt
复制
	    # rst = sock.recvfrom(500)
代码语言:txt
复制
	    data, addr = sock.recvfrom(500)
代码语言:txt
复制
	    print(data)
代码语言:txt
复制
	    print(type(data))
代码语言:txt
复制
	    # 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
代码语言:txt
复制
	    # decode默认参数是utf8
代码语言:txt
复制
	    text = data.decode()
代码语言:txt
复制
	    print(type(text))
代码语言:txt
复制
	    print(text)
代码语言:txt
复制
	    # 给对方返回的消息
代码语言:txt
复制
	    rsp = "Ich hab keine Hunge"
代码语言:txt
复制
	    # 发送的数据需要编码成bytes格式
代码语言:txt
复制
	    # 默认是utf8
代码语言:txt
复制
	    data = rsp.encode()
代码语言:txt
复制
	    sock.sendto(data, addr)
代码语言:txt
复制
	if __name__ == '__main__':
代码语言:txt
复制
	    print("Starting server.........")
代码语言:txt
复制
	    serverFunc()
代码语言:txt
复制
	    print("Ending server...........")
代码语言:txt
复制
    ```
代码语言:txt
复制
- 客户端案例v02
    ```python
    import socket
	
代码语言:txt
复制
	'''
代码语言:txt
复制
	Client端流程
代码语言:txt
复制
	1. 建立通信的socket
	2. 发送内容到指定服务器
	3. 接受服务器给定的反馈内容
	'''
	
代码语言:txt
复制
	def clientFunc():
代码语言:txt
复制
	    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
代码语言:txt
复制
	    text = "I love you"
代码语言:txt
复制
	    # 发送的数据必须是bytes格式
代码语言:txt
复制
	    data = text.encode()
代码语言:txt
复制
	    # 发送
代码语言:txt
复制
	    sock.sendto(data, ("127.0.0.1", 7852))
代码语言:txt
复制
	    data, addr = sock.recvfrom(200)
代码语言:txt
复制
	    data = data.decode()
代码语言:txt
复制
	    print(data)
代码语言:txt
复制
	if __name__ == '__main__':
代码语言:txt
复制
	    clientFunc()
代码语言:txt
复制
    ```
代码语言:txt
复制
- 服务器程序要永久运行,一般用死循环处理
- 改造的服务器版本v03
    ```python
    '''
	Server端流程
	1. 建立socket,socket是负责具体通信的一个实例
	2. 绑定,为创建的socket指派固定的端口和ip地址
	3. 接受对方发送内容
	4. 给对方发送反馈,此步骤为非必须步骤
	'''
	
代码语言:txt
复制
	# socket模块负责socket编程
代码语言:txt
复制
	import socket
代码语言:txt
复制
	# 模拟服务器的函数
代码语言:txt
复制
	def serverFunc():
代码语言:txt
复制
	    # 1. 建立socket
代码语言:txt
复制
	    # socket.AF_INET: 使用ipv4协议族
代码语言:txt
复制
	    # socket.SOCK_DGRAM: 使用UDP通信
代码语言:txt
复制
	    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
代码语言:txt
复制
	    # 2. 绑定ip和port
代码语言:txt
复制
	    # 127.0.0.1: 这个ip地址代表的是机器本身
代码语言:txt
复制
	    # 7852: 随机指定的端口号
代码语言:txt
复制
	    # 地址是一个tuple类型,(ip, port)
代码语言:txt
复制
	    addr = ("127.0.0.1", 7852)
代码语言:txt
复制
	    sock.bind(addr)
代码语言:txt
复制
	    # 3. 接受对方消息
代码语言:txt
复制
	    # 等待方式为死等,没有其他可能性
代码语言:txt
复制
	    # recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
代码语言:txt
复制
	    # 参数的含义是缓冲区大小
代码语言:txt
复制
	    # rst = sock.recvfrom(500)
代码语言:txt
复制
	    data, addr = sock.recvfrom(500)
代码语言:txt
复制
	    print(data)
代码语言:txt
复制
	    print(type(data))
代码语言:txt
复制
	    # 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
代码语言:txt
复制
	    # decode默认参数是utf8
代码语言:txt
复制
	    text = data.decode()
代码语言:txt
复制
	    print(type(text))
代码语言:txt
复制
	    print(text)
代码语言:txt
复制
	    # 给对方返回的消息
代码语言:txt
复制
	    rsp = "Ich hab keine Hunge"
代码语言:txt
复制
	    # 发送的数据需要编码成bytes格式
代码语言:txt
复制
	    # 默认是utf8
代码语言:txt
复制
	    data = rsp.encode()
代码语言:txt
复制
	    sock.sendto(data, addr)
代码语言:txt
复制
	if __name__ == '__main__':
代码语言:txt
复制
	    import time
代码语言:txt
复制
	    while 1:
代码语言:txt
复制
	        try:
代码语言:txt
复制
	            serverFunc()
代码语言:txt
复制
	        except Exception as e:
代码语言:txt
复制
	            print(e)
代码语言:txt
复制
	        time.sleep(1)
代码语言:txt
复制
    ```
  • TCP编程
    • 面向链接的传输,即每次传输之前需要先建立一个链接
    • 客户端和服务端两个程序需要编写
    • Server端的编写流程
      1. 建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后重新建立的socket
      2. 绑定端口和地址
      3. 监听接入的访问socket
      4. 接受访问的socket,可以理解接受访问即建立了一个通讯的链接通路
      5. 接受对方的发送内容,利用接收到的socket接受内容
      6. 如果有必要,给对方发送反馈信息
      7. 关闭链接通路
    • Client端的编写流程
      1. 建立通信socket
      2. 链接对方,请求跟对方建立通路
      3. 发送内容到对方服务器
      4. 接受对方的反馈
      5. 关闭链接通路
    • 案例v04 ```python import socket
代码语言:txt
复制
	def tcp_srv():
代码语言:txt
复制
	    # 1. 建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后重新建立的socket
代码语言:txt
复制
	    # 需要用到两个参数
代码语言:txt
复制
	    # AF_INET: 含义同UDP一致
代码语言:txt
复制
	    # SOCK_STREAM: 表明使用的是TCP进行通信
代码语言:txt
复制
	    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
代码语言:txt
复制
	    # 2. 绑定端口和地址
代码语言:txt
复制
	    # 此地址信息是一个元组类型内容,元组分两部分,第一部分为字符串,代表ip,第二部分为端口,是一个整数,推荐大于10000
代码语言:txt
复制
	    addr = ("127.0.0.1", 8998)
代码语言:txt
复制
	    sock.bind(addr)
代码语言:txt
复制
	    # 3. 监听接入的访问socket
代码语言:txt
复制
	    sock.listen()
代码语言:txt
复制
	    while True:
代码语言:txt
复制
	        # 4. 接受访问的socket,可以理解为接受访问即建立了一个通讯的链接通路
代码语言:txt
复制
	        # accept返回的元组第一个元素赋值给skt,第二个赋值给addr
代码语言:txt
复制
	        skt, addr = sock.accept()
代码语言:txt
复制
	        # 5. 接受对方的发送内容,利用接受到的socket接受内容
代码语言:txt
复制
	        # 500代表接受使用的buffersize
代码语言:txt
复制
	        # msg = skt.receive(500)
代码语言:txt
复制
	        msg = skt.recv(500)
代码语言:txt
复制
	        # 接受到的是bytes格式内容
代码语言:txt
复制
	        # 想得到str格式,需要进行解码
代码语言:txt
复制
	        msg = msg.decode()
代码语言:txt
复制
	        rst = "Receive msg: {0} from {1}".format(msg, addr)
代码语言:txt
复制
	        print(rst)
代码语言:txt
复制
	        # 6. 如果有必要,给对方发送反馈信息
代码语言:txt
复制
	        skt.send(rst.encode())
代码语言:txt
复制
	        # 7. 关闭链接通路
代码语言:txt
复制
	        skt.close()
代码语言:txt
复制
	if __name__ == '__main__':
代码语言:txt
复制
	    print("Starting tcp server........")
代码语言:txt
复制
	    tcp_srv()
代码语言:txt
复制
	    print("Ending tcp server..........")
代码语言:txt
复制
    ```
代码语言:txt
复制
- 案例v05
    ```python
    import socket
代码语言:txt
复制
	def tcp_clt():
代码语言:txt
复制
	    # 1. 建立通信socket
代码语言:txt
复制
	    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
代码语言:txt
复制
	    # 2. 链接对方,请求跟对方建立通路
代码语言:txt
复制
	    addr = ("127.0.0.1", 8998)
代码语言:txt
复制
	    sock.connect(addr)
代码语言:txt
复制
	    # 3. 发送内容到对方服务器
代码语言:txt
复制
	    msg = "I love you"
代码语言:txt
复制
	    sock.send(msg.encode())
代码语言:txt
复制
	    # 4. 接受对方的反馈
代码语言:txt
复制
	    rst = sock.recv(500)
代码语言:txt
复制
	    print(rst.decode())
代码语言:txt
复制
	    # 5. 关闭链接通路
代码语言:txt
复制
	    sock.close()
代码语言:txt
复制
	if __name__ == '__main__':
代码语言:txt
复制
	    tcp_clt()
代码语言:txt
复制
    ```

FTP编程

  • FTP(FileTransferProtoacal)文件传输协议
  • 用途:定制一些特殊的上传下载文件的服务
  • 用户分类:登录FTP服务器必须有一个账号
    • Real账户:注册账户
    • Guest账户:可能临时对某一类人的行为进行授权
    • Anonymous账户:匿名账户,允许任何人
  • FIP工作流程
    1. 客户端链接远程主机上的FTP服务器
    2. 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
    3. 客户端和服务器进行各种文件传输和信息查询操作
    4. 客户端从远程FTP服务器退出,结束传输
  • FTP文件表示
    • 分三段表示FTP服务器上的文件
    • HOST:主机地址,类似于 ftp.mozilla.org, 以 ftp 开头
    • DIR:目录,表示文件所在本地的路径,例如 pub/android/focus/1.1-RC1
    • File:文件名称,例如 Klar-1.1-RC1.apk
    • 如果想完整精确表示ftp上某一文件,需要上述三部分组合到一起
    • 案例v06 ```python # 需要导入相应包,主要是ftplib import ftplib # 关于FTP的操作都在这个包里边 import os import socket
代码语言:txt
复制
	# 三部分精确表示在ftp服务器上的某一个文件
代码语言:txt
复制
	# 好多公开ftp服务器访问会出错或者没有反应
代码语言:txt
复制
	HOST = "ftp.acc.umu.se"
代码语言:txt
复制
	DIR = 'Public/EFLIB/'
代码语言:txt
复制
	FILE = 'README'
代码语言:txt
复制
	# 1. 客户端链接远程主机上的FTP服务器
代码语言:txt
复制
	try:
代码语言:txt
复制
	    f = ftplib.FTP()
代码语言:txt
复制
	    # 通过设置调试级别可以方便调试
代码语言:txt
复制
	    f.set_debuglevel(2)
代码语言:txt
复制
	    # 链接主机地址
代码语言:txt
复制
	    f.connect(HOST)
代码语言:txt
复制
	except Exception as e:
代码语言:txt
复制
	    print(e)
代码语言:txt
复制
	    exit()
代码语言:txt
复制
	print("***Connected to host {0}".format(HOST))
代码语言:txt
复制
	# 2. 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
代码语言:txt
复制
	try:
代码语言:txt
复制
	    # 登录如果没有输入用户信息,则默认使用匿名登录
代码语言:txt
复制
	    f.login()
代码语言:txt
复制
	except Exception as e:
代码语言:txt
复制
	    print(e)
代码语言:txt
复制
	    exit()
代码语言:txt
复制
	print("***Logged in as 'anonymous'")
代码语言:txt
复制
	# 3. 客户端和服务器进行各种文件传输和信息查询操作
代码语言:txt
复制
	try:
代码语言:txt
复制
	    # 更改当前目录到指定目录
代码语言:txt
复制
	    f.cwd(DIR)
代码语言:txt
复制
	except Exception as e:
代码语言:txt
复制
	    print(e)
代码语言:txt
复制
	    exit()
代码语言:txt
复制
	print("*** Changed dir to {0}".format(DIR))
代码语言:txt
复制
	try:
代码语言:txt
复制
	    # 从FTP服务器上下载文件
代码语言:txt
复制
	    # 第一个参数是ftp命令
代码语言:txt
复制
	    # 第二个参数是回调函数
代码语言:txt
复制
	    # 此函数的意思是,执行RETR命令,下载文件到本地后,运行回调函数
代码语言:txt
复制
	    f.retrbinary('RETR {0}'.format(FILE), open(FILE, 'wb').write)
代码语言:txt
复制
	except Exception as e:
代码语言:txt
复制
	    print(e)
代码语言:txt
复制
	    exit()
代码语言:txt
复制
	# 4. 客户端从远程FTP服务器退出,结束传输
代码语言:txt
复制
	f.quit()
代码语言:txt
复制
    ```

Mail编程

电子邮件的历史

  • 起源
    • 1969 Leonard K. 教授发给同事的 “LO”
    • 1971 美国国防部自主的阿帕网(Arpanet)的通讯机制
    • 通讯地址里用@
    • 1987年中国的第一份电子邮件 “Across the Great Wall we can reach every corner in the world”
  • 管理程序
    • Euroda使邮件普及
    • Netscape,outlook,forxmail后来居上
    • Hotmail使用浏览器发送邮件
  • 参考资料

邮件工作流程

  • MUA(MailUserAgent) 邮件用户代理
  • MTA(MailTransferAgent) 邮件传输代理
  • MDA(MailDeliveryAgent) 邮件投递代理
  • laoshi@qq.com,老师,北京海淀
  • xuesheng@sina.com,学生,上海江岸区
  • 流程
    1. MUA->MTA,邮件已经在服务器上了
    2. qq MTA->........-> sina MTA, 邮件在新浪的服务器上
    3. sina MTA-> sina MDA, 此时邮件已经在你的邮箱里了
    4. sina MDA -> MUA(Foxmail/Outlook), 邮件下载到本地电脑
  • 编写程序
    • 发送: MUA->MTA with SMTP: SimpleMailTransferProtocal, 包含MTA->MTA
    • 接受: MDA->MUA with POP3 and IMAP: PostOfficeProtocal v3 and InternetMessageAccessProtocal v4
  • 准备工作
    • 注册邮箱(以qq邮箱为例)
    • 第三方邮箱需要特殊设置,以qq邮箱为例
      • 进入设置中心
      • 取得授权码
  • Python for mail
    • SMTP协议负责发送邮件
      • 使用email模块构建邮件
        • 纯文本邮件
        • 案例v07 ```python # 导入相应的包 import smtplib from email.mime.text import MIMEText # MIMEText三个主要参数 # 1. 邮件内容 # 2. MIME子类型,在此案例我们用plain表示text类型 # 3. 邮件编码格式
代码语言:txt
复制
			msg = MIMEText("Hello, i am xxxx", "plain", "utf-8")
代码语言:txt
复制
			# 发送email地址
代码语言:txt
复制
			from_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 此处密码是经过申请设置后的授权码
代码语言:txt
复制
			from_pwd = "ajwvzqdlfigahiae"  # 授权码
代码语言:txt
复制
			# 收件人信息
代码语言:txt
复制
			# 此时使用qq邮箱
代码语言:txt
复制
			to_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 输入SMIP服务器地址
代码语言:txt
复制
			# 此处根据不同的邮件服务商有不同的值
代码语言:txt
复制
			# 现在基本任何一家邮件服务商,如果采用第三方收发邮件,都需要开启授权选项
代码语言:txt
复制
			# 腾讯qq邮箱所用的SMTP地址是 smtp.qq.com
代码语言:txt
复制
			smtp_srv = "smtp.qq.com"
代码语言:txt
复制
			try:
代码语言:txt
复制
			    # 两个参数
代码语言:txt
复制
			    # 第一个是服务器地址,但一定是bytes格式,所以需要编码
代码语言:txt
复制
			    # 第二个参数是服务器的接受访问端口
代码语言:txt
复制
			    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) # SMTP 协议默认端口25
代码语言:txt
复制
			    # 登录邮箱发送
代码语言:txt
复制
			    srv.login(from_addr, from_pwd)
代码语言:txt
复制
			    # 发送邮件
代码语言:txt
复制
			    # 三个参数
代码语言:txt
复制
			    # 1. 发送地址
代码语言:txt
复制
			    # 2. 接受地址,必须是list格式
代码语言:txt
复制
			    # 3. 发送内容,作为字符串发送
代码语言:txt
复制
			    srv.sendmail(from_addr, [to_addr], msg.as_string())
代码语言:txt
复制
			    srv.quit()
代码语言:txt
复制
			except Exception as e:
代码语言:txt
复制
			    print(e)
代码语言:txt
复制
            ```
代码语言:txt
复制
    - HTML格式邮件发送
        - 准备HTML代码作为内容
        - 把邮件的subtype设为html
        - 发送
        - 案例v08
            ```python
            from email.mime.text import MIMEText
代码语言:txt
复制
			mail_content = """
代码语言:txt
复制
			        <!DOCTYPE html>
代码语言:txt
复制
			        <html lang="en">
代码语言:txt
复制
			        <head>
代码语言:txt
复制
			            <meta charset="UTF-8">
代码语言:txt
复制
			            <title>Title</title>
代码语言:txt
复制
			        </head>
代码语言:txt
复制
			        <body>
代码语言:txt
复制
			        <h1> 这是一封HTML格式邮件</h1>
代码语言:txt
复制
			        </body>
代码语言:txt
复制
			        </html>
代码语言:txt
复制
			        """
代码语言:txt
复制
			msg = MIMEText(mail_content, "html", "utf-8")
代码语言:txt
复制
			# 构建发送者地址和登录信息
代码语言:txt
复制
			from_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 此处密码是经过申请设置后的授权码
代码语言:txt
复制
			from_pwd = "ajwvzqdlfigahiae"  # 授权码
代码语言:txt
复制
			# 构建邮件接受者信息
代码语言:txt
复制
			to_addr = "971254246@qq.com"
代码语言:txt
复制
			smtp_srv = "smtp.qq.com"
代码语言:txt
复制
			try:
代码语言:txt
复制
			    import smtplib
代码语言:txt
复制
			    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)
代码语言:txt
复制
			    srv.login(from_addr, from_pwd)
代码语言:txt
复制
			    srv.sendmail(from_addr, [to_addr], msg.as_string())
代码语言:txt
复制
			    srv.quit()
代码语言:txt
复制
			except Exception as e:
代码语言:txt
复制
			    print(e)
代码语言:txt
复制
            ```
代码语言:txt
复制
    - 发送带附件的邮件
        - 可以把邮件看作是一个文本邮件和一个附件的合体
        - 一封邮件如果涉及多个部分,需要使用MIMEMultipart格式构建
        - 添加一个MIMEText正文
        - 添加一个MIMEBase或者MIMEText作为附件
        - 案例v09
            ```python
            from email.mime.text import MIMEText # 构建附件使用
			from email.mime.multipart import MIMEBase, MIMEMultipart # 构建基础邮件使用
			
代码语言:txt
复制
			mail_mul = MIMEMultipart()
代码语言:txt
复制
			# 构建邮件正文
代码语言:txt
复制
			mail_text = MIMEText("Hello, i am xxxx", "plain", "utf-8")
代码语言:txt
复制
			# 把构建好的邮件正文附加入邮件中
代码语言:txt
复制
			mail_mul.attach(mail_text)
代码语言:txt
复制
			# 构建附加
代码语言:txt
复制
			# 构建附件,需要从本地读入附件
代码语言:txt
复制
			# 打开一个本地文件
代码语言:txt
复制
			# 以rb格式打开
代码语言:txt
复制
			with open("02.html", "rb") as f:
代码语言:txt
复制
			    s = f.read()
代码语言:txt
复制
			    # 设置附件的MIME和文件名
代码语言:txt
复制
			    m = MIMEText(s, 'base64', "utf-8")
代码语言:txt
复制
			    m["Content-Type"] = "application/octet-stream"
代码语言:txt
复制
			    # 需要注意
代码语言:txt
复制
			    # 1. attachment后分号为英文状态
代码语言:txt
复制
			    # 2. filename 后面需要用引号包裹,注意与外面引号错开
代码语言:txt
复制
			    m["Content-Disposition"] = "attachment; filename='02.html'"
代码语言:txt
复制
			    # 添加到MIMEMultipart
代码语言:txt
复制
			    mail_mul.attach(m)
代码语言:txt
复制
			# 发送email地址
代码语言:txt
复制
			from_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 此处密码是经过申请设置后的授权码
代码语言:txt
复制
			from_pwd = "ajwvzqdlfigahiae"  # 授权码
代码语言:txt
复制
			# 收件人信息
代码语言:txt
复制
			# 此时使用qq邮箱
代码语言:txt
复制
			to_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 输入SMIP服务器地址
代码语言:txt
复制
			# 此处根据不同的邮件服务商有不同的值
代码语言:txt
复制
			# 现在基本任何一家邮件服务商,如果采用第三方收发邮件,都需要开启授权选项
代码语言:txt
复制
			# 腾讯qq邮箱所用的SMTP地址是 smtp.qq.com
代码语言:txt
复制
			smtp_srv = "smtp.qq.com"
代码语言:txt
复制
			try:
代码语言:txt
复制
			    import  smtplib
代码语言:txt
复制
			    # 两个参数
代码语言:txt
复制
			    # 第一个是服务器地址,但一定是bytes格式,所以需要编码
代码语言:txt
复制
			    # 第二个参数是服务器的接受访问端口
代码语言:txt
复制
			    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) # SMTP 协议默认端口25
代码语言:txt
复制
			    # 登录邮箱发送
代码语言:txt
复制
			    srv.login(from_addr, from_pwd)
代码语言:txt
复制
			    # 发送邮件
代码语言:txt
复制
			    # 三个参数
代码语言:txt
复制
			    # 1. 发送地址
代码语言:txt
复制
			    # 2. 接受地址,必须是list格式
代码语言:txt
复制
			    # 3. 发送内容,作为字符串发送
代码语言:txt
复制
			    srv.sendmail(from_addr, [to_addr], mail_mul.as_string())
代码语言:txt
复制
			    srv.quit()
代码语言:txt
复制
			except Exception as e:
代码语言:txt
复制
			    print(e)
代码语言:txt
复制
            ```
代码语言:txt
复制
    - 添加邮件头,抄送等信息
        - mail["From"] 表示发送者信息,包括姓名和邮件
        - mail["To"] 表示接受者信息,包括姓名和邮件地址
        - mail["Subject"] 表示摘要或者主题信息
        - 案例v10
            ```python
            from email.mime.text import MIMEText
			from email.header import Header
			
代码语言:txt
复制
			msg = MIMEText("Hello world", "plain", "utf-8")
代码语言:txt
复制
			# 用utf-8编码是因为很可能内容包含非英文字符
代码语言:txt
复制
			header_from = Header("从A发送出去的<A@qq.cn>", "utf-8")
代码语言:txt
复制
			msg['From'] = header_from
代码语言:txt
复制
			# 填写接受者信息
代码语言:txt
复制
			header_to = Header("去往B<B@sina.com>", "utf-8")
代码语言:txt
复制
			msg['To'] = header_to
代码语言:txt
复制
			header_sub = Header("这是主题", "utf-8")
代码语言:txt
复制
			msg['Subject'] = header_sub
代码语言:txt
复制
			# 构建发送者地址和登录信息
代码语言:txt
复制
			from_addr = "1441865605@qq.com"
代码语言:txt
复制
			from_pwd = "ajwvzqdlfigahiae"
代码语言:txt
复制
			# 构建邮件接受者信息
代码语言:txt
复制
			to_addr = "1441865605@qq.com"
代码语言:txt
复制
			smtp_srv = "smtp.qq.com"
代码语言:txt
复制
			try:
代码语言:txt
复制
			    import smtplib
代码语言:txt
复制
			    srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)
代码语言:txt
复制
			    srv.login(from_addr, from_pwd)
代码语言:txt
复制
			    srv.sendmail(from_addr, [to_addr], msg.as_string())
代码语言:txt
复制
			    srv.quit()
代码语言:txt
复制
			except Exception as e:
代码语言:txt
复制
			    print(e)
代码语言:txt
复制
            ```
代码语言:txt
复制
    - 同时支持html和text格式
        - 构建一个MIMEMultipart格式邮件
        - MIMEMultipartd额subtype设置成alternative格式
        - 添加HTML和Text邮件
        - 案例v11
            ```python
            from email.mime.text import  MIMEText
			from email.mime.multipart import  MIMEMultipart
			
代码语言:txt
复制
			# 构建一个MIMEMultipart邮件
代码语言:txt
复制
			msg = MIMEMultipart("alternative")
代码语言:txt
复制
			# 构建一个HTML邮件内容
代码语言:txt
复制
			html_content = """
代码语言:txt
复制
			            <!DOCTYPE html>
代码语言:txt
复制
			            <html lang="en">
代码语言:txt
复制
			            <head>
代码语言:txt
复制
			                <meta charset="UTF-8">
代码语言:txt
复制
			                <title>Title</title>
代码语言:txt
复制
			            </head>
代码语言:txt
复制
			            <body>
代码语言:txt
复制
			            <h1> 这是一封HTML格式邮件</h1>
代码语言:txt
复制
			            </body>
代码语言:txt
复制
			            </html>
代码语言:txt
复制
			        """
代码语言:txt
复制
			#
代码语言:txt
复制
			msg_html = MIMEText(html_content, "html", "utf-8")
代码语言:txt
复制
			msg.attach(msg_html)
代码语言:txt
复制
			msg_text = MIMEText("just text content", "plain", "utf-8")
代码语言:txt
复制
			msg.attach(msg_text)
代码语言:txt
复制
			# 发送email地址
代码语言:txt
复制
			from_addr = "1441865605@qq.com"
代码语言:txt
复制
			from_pwd = "ajwvzqdlfigahiae"
代码语言:txt
复制
			# 收件人信息:
代码语言:txt
复制
			# 此处使用我的qq邮箱
代码语言:txt
复制
			to_addr = "1441865605@qq.com"
代码语言:txt
复制
			# 输入SMTP服务器地址:
代码语言:txt
复制
			# 此地址根据每隔邮件服务商有不同的值,这个是发信邮件服务商的smtp地址
代码语言:txt
复制
			# 我用的是qq邮箱发送,此处应该填写腾讯qq邮箱的smtp值,即smtp.163.com,
代码语言:txt
复制
			# 需要开启授权码,
代码语言:txt
复制
			smtp_srv = "smtp.qq.com"
代码语言:txt
复制
			try:
代码语言:txt
复制
			    import smtplib
代码语言:txt
复制
			    # 加密传输
代码语言:txt
复制
			    #server = smtplib.SMTP_SSL(smtp_srv.encode(), 465) # SMTP协议默认端口是25
代码语言:txt
复制
			    # qq邮箱要求使用 TLS加密传输
代码语言:txt
复制
			    server = smtplib.SMTP(smtp_srv.encode(), 25) # SMTP协议默认端口是25
代码语言:txt
复制
			    server.starttls()
代码语言:txt
复制
			    # 设置调试级别
代码语言:txt
复制
			    # 通过设置调试等级,可以清楚的看到发送邮件的交互步骤
代码语言:txt
复制
			    server.set_debuglevel(1)
代码语言:txt
复制
			    # 登录发送邮箱
代码语言:txt
复制
			    server.login(from_addr, from_pwd)
代码语言:txt
复制
			    server.sendmail(from_addr, [to_addr], msg.as_string())
代码语言:txt
复制
			    server.quit()
代码语言:txt
复制
			except Exception as e:
代码语言:txt
复制
			    print(e)
代码语言:txt
复制
            ```
代码语言:txt
复制
    - 使用smtplib模块发送邮件
- POP3协议负责接受邮件
    - 本质上是MDA到MUA的一个过程
    - 从 MDA 下载下来的是一个完整的邮件结构体,需要解析才能得到每个具体可读的内容
    - 步骤:
        1. 用poplib下载邮件结构体原始内容
            1. 准备相应的内容(邮件地址,密码,POP3实例)
            2. 身份认证
            3. 一般会先得到邮箱内邮件的整体列表
            4. 根据相应序号,得到某一封信的数据流
            5. 利用解析函数进行解析出相应的邮件结构体
        2. 用email解析邮件的具体内容
    - 案例v12
        ```python
        # 导入相关包
		# poplib负责从MDA到MUA下载
		import poplib
		
代码语言:txt
复制
		# 以下包负责相关邮件结构解析
代码语言:txt
复制
		from email.parser import Parser
代码语言:txt
复制
		from email.header import decode_header
代码语言:txt
复制
		from email.utils import parseaddr
代码语言:txt
复制
		# 得到邮件的原始内容
代码语言:txt
复制
		# 这个过程主要负责从MDA到MUA的下载并使用Parse粗略解析
代码语言:txt
复制
		def getMsg():
代码语言:txt
复制
		    # 准备相应的信息
代码语言:txt
复制
		    email = "1441865605@qq.com"
代码语言:txt
复制
		    # 邮箱的授权码
代码语言:txt
复制
		    pwd = "ajwvzqdlfigahiae"
代码语言:txt
复制
		    # pop3服务器地址
代码语言:txt
复制
		    pop3_srv = "pop.qq.com" # 端口995
代码语言:txt
复制
		    # ssl代表是安全通道
代码语言:txt
复制
		    srv = poplib.POP3_SSL(pop3_srv)
代码语言:txt
复制
		    # user代表email地址
代码语言:txt
复制
		    srv.user(email)
代码语言:txt
复制
		    # pass_代表密码
代码语言:txt
复制
		    srv.pass_(pwd)
代码语言:txt
复制
		    # 以下操作根据具体业务具体使用
代码语言:txt
复制
		    # stat返回邮件数量和占用空间
代码语言:txt
复制
		    # 注意stat返回一个tuple格式
代码语言:txt
复制
		    msgs, counts = srv.stat()
代码语言:txt
复制
		    print("Messages: {0}, Size: {1}".format(msgs, counts))
代码语言:txt
复制
		    # list返回所有邮件编号列表
代码语言:txt
复制
		    # mails是所有邮件编号列表
代码语言:txt
复制
		    rsp, mails, octets = srv.list()
代码语言:txt
复制
		    # 可以查看返回的mails列表类似[b'1 82923', b'2 2184', ...]
代码语言:txt
复制
		    print(mails)
代码语言:txt
复制
		    # 获取最新一封邮件,注意,邮件索引号是从1开始, 最新代表索引号最高
代码语言:txt
复制
		    index = len(mails)
代码语言:txt
复制
		    # retr负责返回一个具体索引号的一封信的内容,此内容不具有可读性
代码语言:txt
复制
		    # lines 存储邮件的最原始文本的每一行
代码语言:txt
复制
		    rsp, lines, octets = srv.retr(index)
代码语言:txt
复制
		    # 获得整个邮件的原始文本
代码语言:txt
复制
		    msg_count = b'\r\n'.join(lines).decode("utf-8")
代码语言:txt
复制
		    # 解析出邮件整个结构体
代码语言:txt
复制
		    # 参数是解码后的邮件整体
代码语言:txt
复制
		    msg = Parser().parsestr(msg_count)
代码语言:txt
复制
		    #关闭链接
代码语言:txt
复制
		    srv.quit()
代码语言:txt
复制
		    return msg
代码语言:txt
复制
		# 详细解析得到的邮件内容
代码语言:txt
复制
		# msg代表是邮件的原始内容
代码语言:txt
复制
		# idnent代表的是邮件嵌套的层级
代码语言:txt
复制
		def parseMsg(msg, indent=0):
代码语言:txt
复制
		    '''
代码语言:txt
复制
		    1. 邮件完全可能是有嵌套格式
		    2. 邮件只有一个From,To,Subject之类的信息
		    :param msg:
		    :param indent: 描述邮件里面有几个邮件MIMEXXX类型的内容,展示的时候进行相应缩进
		    :return:
		    '''
		
代码语言:txt
复制
		    # 想办法提取出头部信息
代码语言:txt
复制
		    # 只有在第一层的邮件中才会有相关内容,
代码语言:txt
复制
		    # 此内容只有一个
代码语言:txt
复制
		    if indent == 0:
代码语言:txt
复制
		        for header in ['From', "To", 'Subject']:
代码语言:txt
复制
		            # 使用get可以避免如果没有相关关键字报错的可能性
代码语言:txt
复制
		            # 如果没有 关键字”From“, 我们使用 msg["From"]会报错
代码语言:txt
复制
		            value = msg.get(header, '')
代码语言:txt
复制
		            if value:
代码语言:txt
复制
		                # Subject中的内容直接解码就可以,他是字符串类型
代码语言:txt
复制
		                if header == 'Subject':
代码语言:txt
复制
		                    value = decodeStr(value)
代码语言:txt
复制
		                # 如果是From和To字段,则内容大概是 "我的邮箱<xxxxx@qq.com>“这种格式
代码语言:txt
复制
		                else:
代码语言:txt
复制
		                    hdr, addr = parseaddr(value)
代码语言:txt
复制
		                    name = decodeStr(hdr)
代码语言:txt
复制
		                    # 最终返回形如  "我的邮箱<xxx@qq.com>的格式
代码语言:txt
复制
		                    value = "{0}<{1}>".format(name, addr)
代码语言:txt
复制
		            print("{0}, {1}: {2}".format(indent, header, value))
代码语言:txt
复制
		    # 下面代码关注邮件内容本身
代码语言:txt
复制
		    # 邮件内容中,有可能是multipart类型,也有可能是普通邮件类型
代码语言:txt
复制
		    # 下面的解析使用递归方式
代码语言:txt
复制
		    if (msg.is_multipart()):
代码语言:txt
复制
		        # 如果是multipart类型,则调用递归解析
代码语言:txt
复制
		        # 得到多部分邮件的一个基础邮件部分
代码语言:txt
复制
		        parts = msg.get_payload()
代码语言:txt
复制
		        # enumerate 函数是内置函数
代码语言:txt
复制
		        # 作用是将一个列表,此处是parts,生成一个有索引和parts原内容构成的新的列表
代码语言:txt
复制
		        # 例如 enumerate(['a', 'b', 'c']) 结果是:  [(1,'a'), (2, 'b'), (3, 'c')]
代码语言:txt
复制
		        for n,part in enumerate(parts):
代码语言:txt
复制
		            # 一个字符串乘以一个数字的意思是对这个字符串进行n倍扩展
代码语言:txt
复制
		            # 比如 ”aa" * 2 -> "aaaa"
代码语言:txt
复制
		            print("{0}spart: {1}".format(' '*indent, n))
代码语言:txt
复制
		            parseMsg(part, indent+1)
代码语言:txt
复制
		    else: # 基础类型
代码语言:txt
复制
		        # get_content_type是系统提供函数,得到内容类型
代码语言:txt
复制
		        content_type = msg.get_content_type()
代码语言:txt
复制
		        # text/plain 或者 text/html是固定值
代码语言:txt
复制
		        if content_type == 'text/plain' or content_type == 'text/html':
代码语言:txt
复制
		            content = msg.get_payload(decode=True)
代码语言:txt
复制
		            charset = guessCharset(msg)
代码语言:txt
复制
		            if charset:
代码语言:txt
复制
		                content = content.decode(charset)
代码语言:txt
复制
		            print("{0}Text: {1}".format(indent, content))
代码语言:txt
复制
		        else: #不是文本内容,则应该是附件
代码语言:txt
复制
		            print('{0}Attachment: {1}'.format(indent, content_type))
代码语言:txt
复制
		def decodeStr(s):
代码语言:txt
复制
		    '''
代码语言:txt
复制
		    s代表一封邮件中From,To,Subject中的任一项
代码语言:txt
复制
		    对s进行解码,解码是编码的逆过程
代码语言:txt
复制
		    :param s:
代码语言:txt
复制
		    :return:
代码语言:txt
复制
		    '''
代码语言:txt
复制
		    value, charset = decode_header(s)[0]
代码语言:txt
复制
		    # charset完全可能为空
代码语言:txt
复制
		    if charset:
代码语言:txt
复制
		        # 如果指定编码,则用指定编码格式进行解码
代码语言:txt
复制
		        value = value.decode(charset)
代码语言:txt
复制
		    return value
代码语言:txt
复制
		def guessCharset(msg):
代码语言:txt
复制
		    '''
代码语言:txt
复制
		    猜测邮件的编码格式
代码语言:txt
复制
		    :param msg:
代码语言:txt
复制
		    :return:
代码语言:txt
复制
		    '''
代码语言:txt
复制
		    # 调用现成的函数
代码语言:txt
复制
		    charset = msg.get_charset()
代码语言:txt
复制
		    if charset is None:
代码语言:txt
复制
		        # 找到内容类型,并转换成小写
代码语言:txt
复制
		        content_type = msg.get("Content-Type", "").lower()
代码语言:txt
复制
		        pos = content_type.find("charset=")
代码语言:txt
复制
		        if pos >= 0:
代码语言:txt
复制
		            # 如果包含chraset,则内容形如 charset=xxxx
代码语言:txt
复制
		            charset = content_type[pos+8:].strip()
代码语言:txt
复制
		    return  charset
代码语言:txt
复制
		if __name__ == "__main__":
代码语言:txt
复制
		    # 得到邮件的原始内容
代码语言:txt
复制
		    msg = getMsg()
代码语言:txt
复制
		    print(msg)
代码语言:txt
复制
		    # 精确解析邮件内容
代码语言:txt
复制
		parseMsg(msg, 0)
代码语言:txt
复制
        ```

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 网络编程
  • ICP/UDP协议
  • FTP编程
  • Mail编程
    • 电子邮件的历史
      • 邮件工作流程
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档