Python网络编程


此篇文章简约的介绍一下Python中的网络编程,至于复杂的网络结构,通信原理暂不叙述。

网络

  • 网络协议:一套规则
  • 网络模型:
    • 七层模型(理论)
      • 物理层
      • 数据链路层
      • 网络层
      • 传输层
      • 会话层
      • 表示层
      • 应用层
    • 四层模型(实际)
      • 链路层
      • 网络
      • 传输层
      • 应用层
  • 每一层都有相应的协议负责交换信息或者协同工作
  • TCP/IP协议族
    • IP地址:负责在网络上唯一定位一个机器
      • IP地址分ABCDE类
      • 是由四个数字段组成,每个数字段的取值是0-255
      • 192.168.xxx.xxx:局域网ip
      • 127.0.0.1:本机
      • IPv4,IPv6
  • 端口
    • 范围:0-65535
      • 知名端口:0-1023
      • 非知名端口:1024-65535
  • TCP/UDP协议
    • UDP:非安全的不面向链接的传输
      • 安全性差
      • 大小限制64kb
      • 大文件会以64kb为单位切割,没有顺序
      • 速度快
    • TCP:基于链接的通信
      • 特点与上述UDP相反

套接字:通信端点(socket)

  • socket(套接字):是一个网络通信的端点,能实现不同主机的进程通信
  • 通过IP+端口定位对方并发送消息的通信机制
  • 分为面向连接的(TCP)和无连接的(UDP)
  • 客户端Client:发起访问的一方
  • 服务器端Server:接收访问的一方(这种描述不是准确的,但是可以这么去理解)

Python中的网络编程

socket()模块函数

  • 要创建套接字,必须使用socket.socket()函数,一般语法如下:socket(socket_family, socket_type, protocol=0)其中,socket_family是AF_UNIX或AF_INET,socket_type是SOCK_STREAM或SOCK_DGRAM;protocol通常省略,默认是0。
  • 创建TCP/IP套接字:tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 创建UDP/IP套接字:tcpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • 由于socket模块有很多属性,因此可以使用from socket import *调入,并且把socket引入命名空间,缩近代码长度。

套接字对象(内置)方法

名称描述
s.bind()(服务器)将地址(主机名、端口号对)绑定到套接字上
s.listen()(服务器)设置并启动TCP监听器
s.accept()(服务器)被动接受TCP客户端连接,一直等待直到连接到达(阻塞)
s.connect()(客户端)主动发起TCP服务器连接
s.connect_ex()(客户端)connect()的扩张版本,此时会以错误码的形式返回问题,而不是抛出异常
s.recv()(普通)接收TCP消息
s.recv_into()(普通)接收TCP消息到指定的缓冲区
s.send()(普通)发送TCP消息
s.sendall()(普通)完整地发送TCP消息
s.recvfrom()(普通)接收UDP消息
s.recvfrom_into()(普通)接收UDP消息到指定的缓冲区
s.sendto()(普通)发送UDP消息
s.getpeername()(普通)连接到套接字(TCP)的远程地址
s.getsockname()(普通)当前套接字的地址
s.getsockopt(普通)返回给定套接字选项的值
s.setsockopt()(普通)设置给定套接字选项的值
s.shutdown()(普通)关闭连接
s.close()(普通)关闭套接字
s.detach()(普通)在未关闭文件描述符的情况下关闭套接字,返回文件描述符
s.ioctl()(普通)控制套接字的模式
s.setblocking()(面对阻塞)设置套接字的阻塞或非阻塞模式
s.settimeout()(面对阻塞)设置阻塞套接字操作的超时时间
s.gettimeout()(面对阻塞)获取阻塞套接字操作的超时时间
s.fileno()(面向文件)套接字的文件描述符
s.makefile()(面向文件)创建与套接字关联的文件对象
s.family()(数据属性)套接字家族
s.type()(数据属性)套接字类型
s.proto()(数据属性)套接字协议

TCP服务器/客户端

  • 面向链接的传输,即每次传输之前需要先建立一个链接
  • 客户端和服务器端两个程序需要编写
  • Server端的编写流程
    1. 建立socket负责具体通信,这个socket其实只是负责接收对方的请求
    2. 绑定端口和地址
    3. 监听接入的访问socket
    4. 接收访问的socket,可以理解接收访问即建立了一个通讯的链接通路
    5. 接收对方的发送内容,利用接收到的socket接收内容
    6. 如果有必要,给对方发送反馈信息
    7. 关闭链接通路
import socket

def tcp_srv():
	# 建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后
	# 需要用到两个参数,AF_INET:含义同udp一样;SOCK_STREAM:表明使用的是tcp进行通信
	sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	# 绑定端口和地址
	# 此地址是一个元组类型的内容,元组分为两部分,第一部分为字符串,代表ip,第二部分为端口
	addr = ("127.0.0.1",8998)
	sock.bind(addr)
	# 监听接入的访问socket
	sock.listen()

	while True:
		# 接受访问的socket,可以理解为接受访问即建立了一个通讯的链接通路
		# accept返回的元组第一个元素赋值给skt,第二个赋值给addr
		skt,addr = sock.accept()
		# 接受对方的发送内容,利用接受到的socket接受内容
		# 500代表接受使用的buffersize
		msg = skt.recv(500)
		# 接受到的是bytes格式内容,想得到str格式,需要进行解码
		msg = msg.decode()

		rst = "Received msg: {0} from {1}".format(msg,addr)
		print(rst)

		# 如果有必要,给对方发送反馈信息
		skt.send(rst.encode())

		# 关闭链接通路
		skt.close()

if __name__ == "__main__":
	print("Starting tcp server.......")
	tcp_srv()
	print("Ending tcp server......")
  • Client端流程
    1. 建立通信socket
    2. 链接对方,请求跟对方建立通路
    3. 发送内容到对方服务器
    4. 接收对方的反馈
    5. 关闭链接通路
import socket

def tcp_clt():
	# 建立通信socket
	sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
	# 链接对方,请求跟对方建立通信
	addr = ("127.0.0.1",8998)
	sock.connect(addr)
	# 发送内容到对方服务器
	msg = "I jdksj sa asldk "
	sock.send(msg.encode())
	# 接受对方的反馈
	rst = sock.recv(500)
	# 关闭链路通路
	sock.close()

if __name__ == "__main__":
	tcp_clt()

UDP服务器/客户端

  • Server端流程

    1. 建立socket,socket是负责具体通信的一个实例
    2. 绑定,为创建的socket指派固定的端口和ip地址
    3. 接受对方发送的内容
    4. 给对方发送反馈,此步骤为非必须步骤
    import socket
    # 模拟服务器的函数
    def serverFunc():
    	# 建立socket
    	# socket.AF_INET:使用IPv4协议族
    	# socket.SOCK_DGRAM:使用UDP通信
    	sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    	# 绑定ip和port
    	# 127.0.0.1:这个ip地址代表的是本机地址
    	# 7749:随手指定的端口号
    	# 地址是一个tuple类型,(ip,port)
    	addr = ("127.0.0.1",7749)
    	sock.bind(addr)
    
    	# 接受对方消息
    	# 等待方式为死等,没有其他的可能性
    	# recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
    	# 参数的含义是缓冲区大小
    	# rst = sock.recvfrom(500)
    	data,addr = sock.recvfrom(500)
    	print(data)
    	print(type(data))
    
    	# 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
    	# decode默认参数是utf-8
    	text = data.decode()
    	print(type(text))
    	print(text)
    
    	# 给对方返回消息
    	rsp = "Ich hab Keine Hunge"
    
    	# 发送的数据需要编码成bytes格式
    	# 默认是utf-8
    	data = rsp.encode()
    	sock.sendto(data,addr)
    
    if __name__ == "__main__":
    	print("Starting server........")
    	serverFunc()
    	print("Ending server.......")
    
  • Client端流程

    1. 建立通信的socket
    2. 发送内容到指定服务器
    3. 接受服务器给定的反馈内容
    import socket
    # 客户端函数
    def clientFunc():
    	sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    	
    	# 需要发送的文本信息
    	text = "i ssdka  skdlask!"
    	# 发送的数据必须是bytes格式
    	data = text.decode()
    
    	# 发送
    	sock.sendto(data,("127.0.0.1",7749)
    
    	data,addr = sock.recvfrom(200)
    	data = data.decode()
    	print(data)
    
    if __name__ == "__main__":
    	clientFunc()
    
  • 服务器程序要求永久运行,一般用死循环处理,将主程序进行修改

    import time 
    if __name__ == "__main__":
    	print("Starting server........")
    	while True:
    		try:
    			serverFunc()
    		except Exception as e:
    			print(e)
    		time.sleep(1)
    	print("Ending server.......")
    

FTP协议

  • FTP(FileTransferProtocal)文件传输协议

  • 用途:定制一些特殊的上传下载文件的服务

  • 用户分类:登录FTP服务器必须有一个账号

    • Real账户:注册账户
    • Guest账户:可能临时对某一类人的行为进行授权
    • Anonymous账户:匿名账户,允许任何人
  • FTP工作流程

    • 客户端链接远程主机上的FTP服务器
    • 客户端输入用户名和密码(或者“anonymous”和电子邮件地址)
    • 客户端和服务器进行各种文件传输和信息查询操作
    • 客户端从远程FTP服务器推出,结束传输
  • FTP文件表示

    • 分三段表示FTP服务器上的文件
    • HOST:主机地址,类似于 ftp.mozilla.org,以ftp开头
    • DIR:目录,表示文件所在本地的路径,例如pub/android/focus/klar-1.1-RC1.apk
    • File:文件名称,例如klar-1.1-RC1.apk
    • 如果完整精确表示ftp上某一个文件,需要上述三部分组合在一起

Python与FTP

  • 回顾FTP的流程:连接服务器 -> 登录 -> 发出服务请求(希望得到响应) -> 退出
  • 在使用Python的FTP支持时,所需要做的只是导入ftplib模块,并实例化一个ftplib.FTP类对象。所有的FTP操作都要使用这个对象完成。

ftplib.FTP类的方法

方法描述
login(user=‘anonymous’, passwd=", acct=")登录FTP服务器,所有参数都是可选的
pwd()获得当前工作目录
cwd(path)把当前工作目录设置为path所示的路径
dir ([path[,…[,cb]])显示path目录里的内容,可选的参数cb是一个回调函数,会床底给retrlines()方法
nlst ([path[,…]])与dir()类似,但返回一个文件名列表,而不是显示这些文件名
retrlins(cmd[,cb])给定FTP命令(如"RETR filename"),用于下载文件。可选的回调函数cb用于处理文件的每一行
retrbinary(cmd, cb[,bs=8192[,ra]])与retrlines()类似,只是这个指令处理二进制文件。回调函数cb用于处理每一块(块大小默认为8KB)下载的数据
storlines(cmd,f)给定FTP命令(如"STOR filename"),用来上传文本文件。要给定一个文件对象f
storbinary(cmd, f[,bs=8192])与storlines()类似,只是这个指令处理二进制文件。要给定一个文件对象f,上传块大小bs默认为8KB)
rename(old, new)远程重命名
delete(path)删除位于path的远程文件
mkd(directory)创建远程目录
rmd(directory)删除远程目录
quit()关闭连接并退出

客户端FTP程序

# 需要导入相对应的包,主要是ftplib
# 关于FTP的操作都在这个包里面
import ftplib
import os
import socket

# 三部分精确表示在ftp服务器上的某一个文件
# 好多公开ftp服务器访问会出错或者没有反应
HOST = "ftp.acc.umu.se"
DIR = 'Public/EFLIB'
FILE = 'README'

# 客户端链接远程主机上的FTP服务器
try:
    f = ftplib.FTP()
    # 通过设置调试级别可以方便调试
    f.set_debuglevel(2)
    #  链接本地地址
    f.connect(HOST)
except Exception as e:
    print(e)
    exit()
print("*** Connected to host {0}".format(HOST))

# 客户端和服务器进行各种文件传输和信息查询操作
try:
    # 更改当前目录到指定目录
    f.cwd(DIR)
except Exception as e:
    print(e)
    exit()
print("*** Changed dir to {0}".format(DIR))

try:
    '''
    从FTP服务器上下载文件
    第一个参数是ftp命令
    第二个参数是回调函数
    此函数的意思是:执行RETR命令,下载文件到本地后,运行回调函数
    '''
    f.retrbinary('RETR {0}'.format(FILE),open(FILE,"wb").write)
except Exception as e:
    print(e)
    exit()

# 客户端从远程FTP服务器退出,结束传输
f.quit()

网络新闻

网络新闻协议(NNTP)

  • 作为客户端/服务器架构的另一个例子,NNTP和FTP的操作方式类似。FTP中,登录、传输数据和控制需要使用不同的端口。NNTP只使用一个标准端口119来通信。

Python和NNTP

  • 导入nntplib库,并实例化一个nttplib.NNTP类。
  • 协议:
    • 连接到服务器
    • 登录(根据需要)
    • 发出服务请求
    • 退出
  • 协议内容跟FTP协议极其类似,但是唯一的区别就是NNTP服务器的登录,这一步是可选的。

nntplib.NNTP类方法

方法描述
group(name)选择一个组的名字,返回一个元组(rsp, ct, fst, lst, group),分别表示服务器响应信息、文章数量、第一个和最后一个文章的编号、组名,所有数据都是字符串。(返回的group与传进去的name应该是相同的)
xhdr(hdr, artrg[, ofile])返回文章范围artrg(“头-尾”的格式)内文章hdr头的列表,或者把数据输出到文件ofile中
body(id[, ofile])根据id获取文章正文,id可以是消息的ID(放在尖括号里),也可以是文章编号(以字符串形式表示),返回一个元组(rsp,anum,mid,data),分别表示服务器响应信息,文章编号(以字符串形式表示)、消息ID(放在尖括号里)、文章所有行的列表,或把数据输出到文件ofile中
head(id)与 body()类似,返回相同的元组,只是返回的行列表中只包括文章标题
article(id)同样与 body()类似,返回相同的元组,只是返回的行列表中同时包括文章标题和正文
stat(id)让文章的“指针”指向 id(即前面的消息 ID 或文章编号)。返回一个与 body()相同的元组(rsp, anum, mid),但不包含文章的数据
next()用法和 stat()类似,把文章指针移到下一篇文章,返回与 stat()相似的元组
last()用法和 stat()类似,把文章指针移到最后一篇文章,返回与 stat()相似的元组
post(ufile)上传 ufile文件对象里的内容(使用 ufile.readline()),并发布到当前新闻组中
quit()关闭连接并退出

客户端程序示例

import nntplib
import socket

HOST = "your.nntp.server"
GRNM = "comp.lang.python"
USER = "myuser"
PASS = "youpassword"

def main():
	try:
		n = nntplib.NNTP(HOST)
	except socket.gaierror as e:
		print("ERROR: cannot reach host '%s' " %HOST)
		print("('%s')" % eval(str(e))[1])
		return
	except nntplib.NNTPPermanentError as e:
		print("ERROR: access denied on '%s' " %HOST)
		print("('%s')" % str(e))
		return
	print(" *** Connected to host %s" % GRNM)
	try:
		rsp, ct, fst, lst, grp = n.group(GRNM)
	except nntplib.NNTPTemporaryError as ee:
		print("ERROR: cannot load group '%s'" % GRNM)
		print("(%s)" % str(e))
		print("Server may require authentication")
		print("Uncomment/edit login line above")
		n.quit()
		return
	except nntplib.NNTPTemporaryError as ee:
		print("ERROR: group '%s' unavailable" % GRNM)
		print('("%s")' % str(e))
		n.quit()
		return
	print(" *** Found newsgroup '%s'" % GRNM)

	rng = '%s-%s' % (lst, lst)
	rsp, frm = n.xhdr('from', rng)
	rsp, sub = n.xhdr('subject', rng)
	rsp, dat = n.xhdr('date', rng)
	print(" *** Found last article (#%s): From: %s \n  Subject: %s \n Date: %s \n " % (lst, from[0][1], sub[0][1], dat[0][1])
	rsp, anum, mid, data = n.body(lst)
	displayFirst20(data)
	n.quit()

def displayFirst20(data):
	count = 0
	lines = (line.rstrip() for line in data)
	lastBlank = True
	for line in lines:
		if line:
			lower = line.lower()
			if (lower.startswith('>') and not \
				lower.startswith('>>>') or \
				lower.startswith('|') or \
				lower.startswith('in article') or \
				lower.endswith('writes:') or \
				lower.endswith('wrote:'):
					continue
			if not lastBlank or (lastBlank and line):
				print('%s' % line)
				 if line:
				 	count += 1
				 	lastBlank = False
				 else:
				 	lastBlank = True
			if count == 20:
				break
	
if __name__ == "__main__":
	main()

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 使用浏览器发送邮件
  • 参考资料
    • [官网] (https://docs.python.org/3/library/email.mime.html)

邮件工作流程

  • MUA(MailUserAgent) 邮件用户代理
  • MTA(MailTransferAgent)邮件传输代理
  • MDA(MailDeliveryAgent)邮件投递代理
  • laoshi@qq.com,老师,安徽合肥
  • xuesheng@sina.com,学生,广东中山
  • 流程
    • MUA -> MTA,邮件已经在服务器上了
    • qq MTA -> …-> sina MTA,邮件在新浪的服务器上
    • sina MTA -> sina MDA,此时邮件已经在你邮箱里了
    • sina MDA -> MUA(Foxmail/Outlook),邮件下载到本地电脑
  • 编写程序
    • 发送:MUA -> MTA with SMTP:SimpleMainTransferProtocal,包含MTA -> MTA
    • 接收:MDA -> MUA with POP3 and IMAP: PostOfficeProtocal v3
  • 准备工作
    • 注册邮箱
    • 第三方邮箱需要特殊设置
      • 进入设置中心
      • 取得授权码

Python和SMTP

  • Python中也有一个 smtplib 模块和一个需要实例化的 smtplib.SMTP 类。
  • 过程:
    • 连接到服务器。
    • 登录(根据需要)
    • 发出服务请求。
    • 退出。
  • 像NNTP一样,登录是可选的,只有在服务器启动了SMTP(SMTP-AUTH)身份验证时才要登录。SMTP-AUTH在RFC 2554中定义。SMTP通信时也需要一个端口。

smtplib.SMTP类方法

方法描述
sendmail(from, to, msg[, mopts, ropts])将msg从from发送到至to(以列表或元组表示),还可以选择性地设置ESMTP邮件(mopts)和收件人(ropts)选项
ehlo()或helo()使用EHLO或HELO初始化SMTP或ESMTP服务器的会话。这是可选的,因为sendmail()会在需要时自动调用相关内容
starttls(keyfile=None, certfile=None)让服务器启用 TLS 模式。如果给定了 keyfile 或 certfile,则它们用来创建安全套接字
set_debuglevel(level)为服务器通信设置调试级别
quit()关闭连接并退出
login(user, passwd)使用用户名和密码登录 SMTP 服务器 (只用于SMTP-AUTH)
  • Python for mail
    • SMTP协议负责发送邮件
      • 使用email模块构建邮件

        • 纯文本邮件
        import smtplib
        from email.mime.text import MIMEText
        """
        MIMEText三个主要参数:
        邮件内容
        MIME子类型,在此案例使用plain表示text类型
        邮件编码格式
        """
        msg = MIMEText("Hello, i am xxx","plain","utf-8")
        
        # 发送Email地址,此处地址直接使用qq邮箱,密码一般要临时输入
        from_addr = "1235646466@qq.com"
        # 此处密码使经过申请设置后的授权码,并不是邮箱密码
        from_pwd = "sdasdjsajdfkf"
        
        # 收件人信息
        # 此处使用qq邮箱,给自己发送
        to_addr = "1235646466@qq.com"
        
        # 输入SMTP服务器地址
        # 此处根据不同的邮件服务器有不同的值
        # 现在基本任何一家邮件服务商,如果采用第三方发邮件,都需要开启授权选项
        # 腾讯qq邮件的SMTP地址是 smtp.qq.com
        
        smtp_srv = "smtp.qq.com"
        
        try:
            srv = smtplib.SMTP_SSL(smtp_srv.encode(),465) #smtp默认端口25
            # 登录邮箱发送
            srv.login(from_addr,from_pwd)
            """
            发送邮件,三个参数
            发送地址
            接收地址,必须是list形式
            发送内容,作为字符串发送
            """
            srv.sendmail(from_addr,[to_addr],msg.as_string())
            srv.quit()
        except Exception as e:
            print(e)
        
        
      • HTML格式邮件发送

        • 准备HTML代码作为内容
        • 把邮件的subtype设为html
        • 发送
        from email.mime.text import MIMEText
        
        mail_content = """
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="utf-8">
                    <title>Title</title>
                </head>
                <body>
                
                <h1> 这是一封HTML格式邮件</h1>
                
                </body>
                </html>
                """
        msg = MIMEText(mail_content,"html","utf-8")
        
        # 构建发送者地址和登录信息
        from_addr = "2467930184@qq.com"
        from_pwd = "sadjkasjdkasja"
        
        # 构建邮件接收者信息
        to_addr = "2467930184@qq.com"
        
        smtp_srv = "smtp.qq.com"
        
        try:
            import  smtplib
            srv = smtplib.SMTP_SSL(smtp_srv.encode(),465)
        
            srv.login(from_addr,from_pwd)
            srv.sendmail(from_addr,[to_addr],msg.as_string())
            srv.quit()
        except Exception as e:
            print(e)
            
        
        • 发送带有附件的邮件

          • 可以把邮件看作是一个文本邮件和一个附件的合体
          • 一封邮件如果涉及多个部分,需要使用MIMEMultipart格式创建
          • 添加一个MIMEText正文
          • 添加一个MIMEBase或者MIMEText作为附件
          from email.mime.text import MIMEText
          from email.mime.multipart import MIMEBase,MIMEMultipart
          
          mail_mul = MIMEMultipart()
          # 构建邮件正文
          mail_text = MIMEText("Hello, i am adkjks","plain","utf-8")
          # 把构建好的邮件正文附加入邮件中
          mail_mul.attach(mail_text)
          
          # 构建附加
          # 构建附件,需要从文本读入附件
          # 打开一个本地文件
          # 以rb格式打开
          with open("02.html","rb") as f:
              s = f.read()
              # 设置组件的MIME和文件名
              m = MIMEText(s,"base64","utf-8")
              m["Content-Type"] = "application/octet-stream"
              # 需要注意:
              # attachment后面的分号是英文状态
              # filename 后面需要引号包裹,注意与外面引号错开
              m["Content-Disposition"] = "attachment;filename='02.html"
              # 添加到MIMEMulipart
              mail_mul.attach(m)
          
          # 发送email地址,此处地址直接使用qq邮箱
          from_addr = "2467930184@qq.com"
          # 此处密码使经过申请设置后的授权码,并不是邮箱密码
          from_pwd = "sdasdjsajdfkf"
          
          # 收件人信息
          # 此处使用qq邮箱,给自己发送
          to_addr = "2467930184@qq.com"
          
          smtp_srv = "smtp.qq.com"
          
          try:
              srv = smtplib.SMTP_SSL(smtp_srv.encode(),465) #smtp默认端口25
              # 登录邮箱发送
              srv.login(from_addr,from_pwd)
              """
              发送邮件,三个参数
              发送地址
              接收地址,必须是list形式
              发送内容,作为字符串发送
              """
              srv.sendmail(from_addr,[to_addr],msg.as_string())
              srv.quit()
          except Exception as e:
              print(e)
          
      • 添加邮件头,抄送等信息

        • mail[“From”] 表示发送者信息,包括姓名和邮件
        • mail[“To”] 表示接收者信息,包括姓名和邮件地址
        • mail[“Subject”] 表示摘要或者主题信息
        from email.mime.text import MIMEText
        from email.header import Header
        
        msg = MIMEText("Hello world","plain","utf-8")
        
        # 填写发送者信息
        header_from = Header("这里是发送者邮箱<2467930184@qq.com>","utf-8")
        msg['From'] = header_from
        
        # 填写接收者信息
        header_to = Header('这里是接收者邮箱<2467930184@qq.com>','utf-8')
        msg['to'] = header_to
        
        header_sub = Header("这是个演示",'utf-8')
        msg['Subject'] = header_sub
        
        # 构建发送者地址和登录信息
        from_addr = "2467930184@qq.com"
        from_pwd = "sadjkasjdkasja"
        
        # 构建邮件接收者信息
        to_addr = "2467930184@qq.com"
        
        smtp_srv = "smtp.qq.com"
        ...
        
      • 同时支持html和text格式

        • 构建一个MIMEMultipart格式邮件
        • MIMEMultipart的subtype设置成alternative格式
        • 添加Html和Text邮件
        from email.mime.text import MIMEText
        from email.mime.multipart import MIMEMultipart
        
        # 构建一个MIMEMultipart邮件
        msg = MIMEMultipart("alternative")
        
        # 构建一个HTML邮件内容
        html_content = """
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="UTF-8">
                    <title>Title</title>
                </head>
                <body>
                <h1>这是一封HTML格式邮件</h1>
                </body>
                </html>
                """
        msg_html = MIMEText(mail_content,"html","utf-8")
        msg.attach(msg_html)
        
        msg_text = MIMEText("Hello, i am xxx","plain","utf-8")
        msg.attach(msg_text)
        
        #后面都一样
        ...
        
      • 使用smtplib模块发送邮件

    • POP3协议接收邮件
      • 本质上是MDA到MUA的一个过程
      • 从MDA下载下来的是一个完整的邮件结构体,需要解析才能得到每个具体邮件信息
        • 用poplib下载邮件结构体原始内容
          1. 准备相应的内容(邮件地址,密码,POP3实例)
          2. 身份认证
          3. 一般会先得到邮箱内邮件的整体列表
          4. 根据相应序号,得到某一个邮件的数据流
          5. 利用解析函数进行解析出相应的邮件结构体
        • 用email解析邮件的具体内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值