实验内容
使用网络相关原理,设计一个电子邮件客户端程序。
代码
入口主类
import tkinter as tk
import threading
from Test_5_Mail.recvMail import recv_email_by_imap4
from Test_5_Mail.sendMail import mailSocket
class Application(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
self.grid()
self.createWdiget()
def createWdiget(self):
tk.Label(self, text='收件人邮箱:').grid(row=0, column=1, sticky=tk.E)
self.RecvMail = tk.StringVar()
tk.Entry(self, textvariable=self.RecvMail).grid(row=0, column=2, sticky=tk.W)
tk.Label(self, text='主题:').grid(row=1, column=1, sticky=tk.E)
self.Subject = tk.StringVar()
tk.Entry(self, textvariable=self.Subject).grid(row=1, column=2, sticky=tk.W)
tk.Label(self, text='正文:').grid(row=2, column=1)
self.inputText = tk.Text(self, width=50, height=20)
self.inputText.grid(row=2, column=2)
self.showText = tk.Text(self, width=50, height=20)
self.showText.grid(row=2, column=3)
tk.Button(self, text='发送', command=self.sender).grid(row=3, column=2)
t1 = threading.Thread(target=self.receiveMail)
t1.start()
def sender(self):
print(self.RecvMail.get())
print(self.Subject.get())
print(self.inputText.get('1.0', 'end-1c'))
mailSocket(self.RecvMail.get(), self.Subject.get(), self.inputText.get('1.0', 'end-1c'))
def receiveMail(self):
bakup = 0
while True:
subject, fromP, text, backup = recv_email_by_imap4()
# print('backup: ', backup)
if bakup == backup:
continue
bakup = backup
print('bakup: ', bakup)
print(subject)
print(fromP)
print(text)
# 通过设置state属性设置textEdit可编辑
self.showText.config(state='normal')
content = "from: " + fromP + '\n' + "subject: " + subject.decode('gbk') + '\n'+ 'content: ' + text + '\n' + '-------------------------' + '\n';
# self.showText.insert(tk.END, "from: "+fromP+'\n', 'guest')
# self.showText.insert(tk.END, "subject: "+subject.decode('gbk')+'\n')
self.showText.insert(tk.END, content)
# 将滚动条拉到最后显示最新消息
self.showText.see(tk.END)
# 通过设置state属性设置textEdit不可编辑
self.showText.config(state='disabled')
root = tk.Tk()
root.title("MailClient")
root.geometry("800x400")
app = Application(root)
app.mainloop()
发送邮件部分
import base64
import smtplib
import socket
import ssl
from email.mime.text import MIMEText
_username = '**********@qq.com'
_password = '*****************' # 发送方QQ邮箱授权码,不是QQ邮箱密码。
def mailSocket(recver, _subject, text):
mailserver = ('smtp.qq.com', 465)
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sslclientSocket = ssl.wrap_socket(clientSocket, cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv23)
print('连接中.........')
sslclientSocket.connect(mailserver)
recv = sslclientSocket.recv(1024).decode('utf-8')
if recv[:3] != '220':
print('连接失败, 重新连接')
mailSocket()
print(recv) # 220 smtp.qq.com Esmtp QQ Mail Server
print('连接成功..........')
# 服务器响应
sslclientSocket.send(b'HELO qq.com\r\n')
recv = sslclientSocket.recv(1024).decode()
print(recv) # 250 smtp.qq.com
# 发送登录请求
sslclientSocket.send(b'AUTH login\r\n')
recv2 = sslclientSocket.recv(1024).decode('utf-8')
print(recv2) # 334 VXNlcm5hbWU6
# 开始登陆
username = b'%s\r\n' % base64.b64encode(_username.encode('utf-8'))
password = b'%s\r\n' % base64.b64encode(_password.encode('utf-8'))
sslclientSocket.send(username)
recv = sslclientSocket.recv(1024).decode('utf-8')
print('username = ', recv) # 334 UGFzc3dvcmQ6
sslclientSocket.send(password)
recv = sslclientSocket.recv(1024).decode()
print('password = ', recv) # 235 Authentication successful
if recv[:3] == '235':
send(sslclientSocket, recver, _subject, text)
def send(sslclientSocket, recver, _subject, text):
mailSender = b'MAIL FROM:<%s>\r\n' % _username.encode('utf-8')
sslclientSocket.send(mailSender)
# recver = 'lidonglei99@163.com'
recver = recver
mailrecv = b'RCPT TO:<%s>\r\n' % recver.encode('utf-8')
sslclientSocket.send(mailrecv)
recv = sslclientSocket.recv(1024).decode()
print(recv) # 250 OK
data = b'DATA\r\n'
sslclientSocket.send(data)
recv = sslclientSocket.recv(1024).decode()
print(recv) # 250 Ok
# 邮件主题 subject
_subject = _subject
subject = b'Subject: %s\r\n' % _subject.encode('utf-8')
sslclientSocket.send(subject)
msgtype = b"Content-Type: multipart/mixed;boundary='BOUNDARY'\r\n\r\n"
msgboundary = b'--BOUNDARY\r\n'
sslclientSocket.send(b"Content-Type: multipart/mixed;boundary='BOUNDARY'\r\n\r\n")
sslclientSocket.send(b'Content-Transfer-Encoding:7bit\r\n\r\n')
sslclientSocket.send(b'\r\n\r\n' + b'--BOUNDARY\r\n')
sslclientSocket.send(b'Content-Type: text/html;charset=utf-8\r\n')
sslclientSocket.send(b'Content-Transfer-Encoding:7bit\r\n\r\n')
# text = 'Hello, World, <h1 style="color:#c00">World</h1>'
_text = b'%s\r\n' % text.encode('utf-8')
sslclientSocket.send(_text)
print('发送结束...')
sslclientSocket.send(b'\r\n.\r\n')
sslclientSocket.send(b'QUIT\r\n')
if __name__ == '__main__':
mailSocket()
def sendMailBySMTPlib():
msg_from = '********@qq.com' # 发送方邮箱地址。
password = '********' # 发送方QQ邮箱授权码,不是QQ邮箱密码。
msg_to = '********@163.com' # 收件人邮箱地址。
subject = "你好" # 主题。
content = "i am zhangphil" # 邮件正文内容。
msg = MIMEText(content, 'plain', 'utf-8')
msg['Subject'] = subject
msg['From'] = msg_from
msg['To'] = msg_to
try:
client = smtplib.SMTP_SSL('smtp.qq.com', smtplib.SMTP_SSL_PORT)
print("连接到邮件服务器成功")
client.login(msg_from, password)
print("登录成功")
client.sendmail(msg_from, msg_to, msg.as_string())
print("发送成功")
except smtplib.SMTPException as e:
print("发送邮件异常")
finally:
client.quit()
接收邮件
import imaplib
import email
# 此函数通过使用imaplib实现接收邮件
from numpy import unicode
def recv_email_by_imap4():
# 要进行邮件接收的邮箱。改成自己的邮箱
email_address = "********@qq.com"
# 要进行邮件接收的邮箱的密码。改成自己的邮箱的密码
email_password = "********"
# 邮箱对应的imap服务器,也可以直接是IP地址
# 改成自己邮箱的imap服务器;qq邮箱不需要修改此值
imap_server_host = "imap.qq.com"
# 邮箱对应的pop服务器的监听端口。改成自己邮箱的pop服务器的端口;qq邮箱不需要修改此值
imap_server_port = 993
try:
# 连接imap服务器
email_server = imaplib.IMAP4_SSL(host=imap_server_host, port=imap_server_port)
except:
exit(1)
try:
# 验证邮箱及密码是否正确
email_server.login(email_address, email_password)
except:
exit(1)
backup = None
# 邮箱中其收到的邮件的数量
email_server.select()
email_count = len(email_server.search(None, 'ALL')[1][0].split())
backup = email_count
# 通过fetch(index)读取第index封邮件的内容;这里读取最后一封,也即最新收到的那一封邮件
typ, email_content = email_server.fetch(f'{email_count}'.encode(), '(RFC822)')
# 将邮件内存由byte转成str
email_content = email_content[0][1].decode()
msg = email.message_from_string(email_content)
text = parseBody(msg)
subject, fromP = parseHeader(msg)
# 关闭select
email_server.close()
# 关闭连接
email_server.logout()
return subject, fromP, text, backup
def parseBody(message):
""" 解析邮件/信体 """
# 循环信件中的每一个mime的数据块
for part in message.walk():
# 这里要判断是否是multipart,是的话,里面的数据是一个message 列表
if not part.is_multipart():
charset = part.get_charset()
# print 'charset: ', charset
contenttype = part.get_content_type()
# print 'content-type', contenttype
name = part.get_param("name") # 如果是附件,这里就会取出附件的文件名
if name:
# 有附件
# 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名
fh = email.Header.Header(name)
fdh = email.Header.decode_header(fh)
fname = fdh[0][0]
print('附件名:', fname)
# attach_data = par.get_payload(decode=True) # 解码出附件数据,然后存储到文件中
# try:
# f = open(fname, 'wb') #注意一定要用wb来打开文件,因为附件一般都是二进制文件
# except:
# print '附件名有非法字符,自动换一个'
# f = open('aaaa', 'wb')
# f.write(attach_data)
# f.close()
else:
# 不是附件,是文本内容
return part.get_payload(decode=True).decode('gbk')
# pass
# print '+'*60 # 用来区别各个部分的输出
def parseHeader(message):
""" 解析邮件首部 """
subject = message.get('subject')
h = email.header.Header(subject)
dh = email.header.decode_header(h)
subject = unicode(dh[0][0], dh[0][1]).encode('gb2312')
return subject, email.utils.parseaddr(message.get('from'))[1]
来源:CSDN
作者:_子沐_
链接:https://blog.csdn.net/qq_41953685/article/details/104024903