admin管理员组

文章数量:1530065

实验内容

使用网络相关原理,设计一个电子邮件客户端程序。

代码

入口主类

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'
_password = '*****************'  # 发送方QQ邮箱授权码,不是QQ邮箱密码。

def mailSocket(recver, _subject, text):
    mailserver = ('smtp.qq', 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 Esmtp QQ Mail Server
    print('连接成功..........')

    # 服务器响应
    sslclientSocket.send(b'HELO qq\r\n')
    recv = sslclientSocket.recv(1024).decode()
    print(recv)  # 250 smtp.qq
    # 发送登录请求
    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'
    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'  # 发送方邮箱地址。
    password = '********'  # 发送方QQ邮箱授权码,不是QQ邮箱密码。
    msg_to = '********@163'  # 收件人邮箱地址。

    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', 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"
    # 要进行邮件接收的邮箱的密码。改成自己的邮箱的密码
    email_password = "********"
    # 邮箱对应的imap服务器,也可以直接是IP地址
    # 改成自己邮箱的imap服务器;qq邮箱不需要修改此值
    imap_server_host = "imap.qq"
    # 邮箱对应的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]


本文标签: 计算机网络程序设计客户端课程设计电子邮件