使用Python设计一个基于SMTP协议的Internet 邮件发送客户程序(附源码)

设计原理

建立网络连接:客户程序首先需要建立与邮件服务器的网络连接。它可以使用标准的TCP/IP协议通过邮件服务器的标准SMTP端口(通常是25号端口)来建立连接。

发送邮件头部信息:客户程序需要构建合法的邮件头部信息。这包括发件人、收件人、主题、日期等。这些信息通常以文本形式编码,并遵循RFC 5322规范。

验证发件人身份:某些邮件服务器要求客户程序在发送邮件之前验证发件人的身份。这可以通过SMTP协议的认证机制实现,例如使用用户名和密码进行登录认证。

发送正文和附件:客户程序需要将邮件的正文内容和附件(如果有)编码,并通过SMTP协议发送给邮件服务器。正文内容通常使用MIME(Multipurpose Internet Mail Extensions)格式进行编码,以支持不同类型的内容,如纯文本、HTML、图像等。

处理错误和回应:客户程序在发送邮件后需要等待邮件服务器的响应。服务器可能返回成功的响应码(如250),表示邮件已成功发送,或返回错误的响应码(如550),表示发送失败。客户程序需要相应地处理这些响应,以便根据需要采取适当的行动。

断开连接:发送完邮件后,客户程序可以选择断开与邮件服务器的连接,释放资源,并结束与服务器的通信。

需要注意的是,SMTP是一个简单的文本协议,它定义了客户程序与邮件服务器之间的通信规则。因此,设计SMTP邮件发送客户程序时,需要遵循SMTP协议的规范,确保与邮件服务器之间的交互符合协议要求(如RFC5322、RFC2047 和 RFC822 标准协议等)。

程序流程图

开始

┌─────────────────────────────────────────────┐

│                 连接邮件服务器                    │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│          验证发件人身份(可选)                │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│            构建邮件头部信息                      │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│               发送正文和附件                      │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│              等待邮件服务器响应                     │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│              处理邮件服务器回应                     │

└─────────────────────────────────────────────┘

        │

        ▼

┌─────────────────────────────────────────────┐

│                断开与邮件服务器的连接               │

└─────────────────────────────────────────────┘

结束

设计步骤

导入所需的模块:代码开头导入了smtplib、sys以及来自email.mime.text、email.header和email.utils模块的特定类和函数。这些模块和类用于发送邮件和构建邮件内容。导入from tkinter import *,from tkinter import messagebox模块进行可视化设计。

定义send_email函数:函数接受发件人信息、收件人信息、主题、内容等参数,用于发送邮件。在函数内部,首先根据指定的smtp_server选择不同的SMTP服务器进行设置。

设置邮件内容:使用MIMEText类创建邮件正文内容,并设置发件人、收件人、主题等邮件头部信息。

根据smtp_server选择SMTP服务器:根据用户选择的smtp_server的值,设置相应的SMTP服务器地址和端口。对于某些SMTP服务器,还需要调用starttls()方法启用TLS加密。

建立连接并登录SMTP服务器:使用SMTP或SMTP_SSL类创建SMTP对象,并调用connect()方法连接到SMTP服务器。然后调用login()方法使用发件人的邮箱地址和密码进行登录。

发送邮件:调用sendmail()方法将邮件发送给收件人。其中,as_string()方法将msg对象转换为字符串形式。

处理异常:使用try-except块捕获SMTPException异常,打印发送失败的错误信息。

关闭连接:在finally块中,使用quit()方法关闭与SMTP服务器的连接。

主程序:获取用户输入的SMTP服务器选择以及发件人、收件人、主题、内容等信息,并调用send_email函数发送邮件。

使用方法说明

首先,因为我们使用的是基于SMTP协议的邮箱发送,所以在开始实验前要确保所使用的运营商要支持SMTP传输,这里我以QQ邮箱为例,它是支持SMTP传输的,但是需要自己打开。

这里QQ邮箱官方关于SMTP服务有明确的说明。设置完后我们会得到一个授权码,这个授权码就将作为为我们提供SMTP服务的实际“密码”。

 

这里我已经开启了SMTP服务,接下来实验我将以QQ邮箱为服务商进行演示。

运行SMTP_Email.py文件。运行界面如下:

 (界面设计的比较丑,因为就只是运用GUI最基础的部分,也没有封装函数,所有图形化设置都在main函数里实现)

 这里我们需要先在右上角选择邮箱运营商,这里我设置了4个可以使用SMTP的邮箱。如果不选邮箱就发送系统会提醒我们选择运营商:

这里我们选择QQ邮箱进行演示。

 显示我们已经切换成功了,接下来就是按照提示输入信息,且信息都不能为空,否则系统会进行提醒:

 我们按照提醒输入信息后发送:

这里系统提示我们已经发送成功

我们更改一下错误消息看它还能不能成功发送,我们先将发送方邮箱密码更改(为了保密密码输入时将变为‘*’):

 

系统提示我们连接失败,说明错误的密码(授权码)没有让我们登上QQ邮箱。

我接下来更改接收方的信息:

 

结果及分析

接下来我们进入QQ邮箱官网验证我们之前发出去的两封信是不是都发送到了。

通过查询发送记录,我们发现第一份信已经准确送达了:

 

由于接收方的邮箱地址不存在,邮件最后被退了回来,这也说明了SMTP传输服务只负责发出去,而不会验证接收方是否存在。 


#SMTP_Email.py文件代码如下:

from tkinter import *
from tkinter import messagebox

import smtplib
import sys
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr

#邮箱服务类型选择
smtp_server = '0'
def QQ():
    global smtp_server
    smtp_server='1'
    messagebox.showinfo('提醒','你已成功切换为QQ邮箱!')
def SOUHU():
    global smtp_server
    smtp_server='2'
    messagebox.showinfo('提醒','你已成功切换为搜狐邮箱!')
def GMAIL():
    global smtp_server
    smtp_server='3'
    messagebox.showinfo('提醒','你已成功切换为Gmail!')
def YAHOO():
    global smtp_server
    smtp_server='4'
    messagebox.showinfo('提醒','你已成功切换为雅虎邮箱!')


def send_email(sender, password, receiver, subject, message, smtp_server,user_name):
    # 邮件内容设置
    msg = MIMEText(message, 'plain', 'utf-8')
    msg['From'] = formataddr((str(Header(user_name, 'utf-8')), sender))
    msg['To'] = Header(receiver, 'utf-8')
    msg['Subject'] = Header(subject, 'utf-8')

    smtp_obj = None  # 初始化smtp_obj变量

    try:
        if smtp_server == '1':
            # QQ 邮箱的SMTP服务器设置
            SMTP_IP='smtp.qq.com'
            PORT=465
            smtp_obj = smtplib.SMTP_SSL('smtp.qq.com', 465)
        elif smtp_server == '2':
            # Sohu 邮箱的SMTP服务器设置
            SMTP_IP = 'smtp.sohu.com'
            PORT = 25
            smtp_obj = smtplib.SMTP('smtp.sohu.com', 25)
        elif smtp_server == '3':
            # Gmail 的SMTP服务器设置
            SMTP_IP = 'smtp.gmail.com'
            PORT = 587
            smtp_obj = smtplib.SMTP('smtp.gmail.com', 587)
            smtp_obj.starttls()
        elif smtp_server == '4':
            # yahoo 的SMTP服务器设置
            SMTP_IP = 'smtp.yahoo.cn'
            PORT = 465
            smtp_obj = smtplib.SMTP('smtp.yahoo.cn', 465)
            smtp_obj.starttls()
        else:
            #print("不支持的SMTP服务器")
            root1 = Tk()
            root1.geometry("400x20+500+200")
            root1.title('系统消息')
            label_3 = Label(root1, text='不支持的SMTP服务器!', font=("宋体", 10), fg='red')
            label_3.grid(row=1, column=1)
            root1.mainloop()
            return

        # 建立连接
        smtp_obj.connect(SMTP_IP, PORT)

        # 登录SMTP服务器
        smtp_obj.login(sender, password)

        # 发送邮件
        smtp_obj.sendmail(sender, receiver, msg.as_string())
        #print("邮件发送成功")
        root1 = Tk()
        root1.geometry("400x20+500+200")
        root1.title('系统消息')
        label_3 = Label(root1, text='邮件发送成功!', font=("宋体", 10), fg='red')
        label_3.grid(row=1, column=1)
        root1.mainloop()

    except smtplib.SMTPException as e:
        #print("邮件发送失败:" + str(e))
        root1 = Tk()
        root1.geometry("400x20+500+200")
        root1.title('系统消息')
        label_3 = Label(root1, text="邮件发送失败:!"+str(e), font=("宋体", 10), fg='red')
        label_3.grid(row=1, column=1)
        root1.mainloop()
    finally:
        if smtp_obj:
            # 关闭连接
            smtp_obj.quit()


def func():
    global smtp_server
    sender_email = str(entry_1.get())
    sender_password = str(entry_2.get())
    user_name = str(entry_3.get())
    receiver_email = str(entry_4.get())
    email_subject = str(entry_5.get())
    email_message = entry_6.get("1.0", "end")
    if smtp_server == '0':
        messagebox.showwarning('WARING!', '你还未选择邮箱运营商!')
    elif sender_email == "":
        messagebox.showwarning('WARING!', '发送邮箱地址不能为空!')
    elif sender_password == "":
        messagebox.showwarning('WARING!', '密码(授权码)不能为空!')
    elif user_name == "":
        messagebox.showwarning('WARING!', '用户名不能为空!')
    elif receiver_email == "":
        messagebox.showwarning('WARING!', '接收邮箱地址不能为空!')
    elif email_subject == "":
        messagebox.showwarning('WARING!', '邮件主题不能为空!')
    elif email_message == "":
        messagebox.showwarning('WARING!', '邮件内容不能为空!')
    else:
        send_email(sender_email, sender_password, receiver_email, email_subject, email_message, smtp_server, user_name)


if __name__ =='__main__':
    root=Tk()
    root.geometry("650x500+350+180")
    root.title('Internet 邮件发送客户程序(使用前请先确保您的邮箱开通了SMTP功能)')
    #标签
    label_1=Label(root,text='请输入发送方邮箱地址:',font=("楷书",10),fg="blue")
    label_1.grid(row=0,column=0)
    #输入框
    entry_1=Entry(root,font=("宋体",10),fg="red")
    entry_1.grid(row=1,column=0)

    label_2=Label(root,text='请输入发送方邮箱密码:',font=("楷书",10),fg="blue")
    label_2.grid(row=2,column=0)
    entry_2=Entry(root,font=("宋体",10),fg="red",show='*')
    entry_2.grid(row=3,column=0)

    label_3=Label(root,text='请输入发送方用户名:',font=("楷书",10),fg="blue")
    label_3.grid(row=4,column=0)
    entry_3=Entry(root,font=("宋体",10),fg="red")
    entry_3.grid(row=5,column=0)

    label_4=Label(root,text='请输入接收方邮箱地址:',font=("楷书",10),fg="blue")
    label_4.grid(row=6,column=0)
    entry_4=Entry(root,font=("宋体",10),fg="red")
    entry_4.grid(row=7,column=0)

    label_5=Label(root,text='请输入发送邮件的主题:',font=("楷书",10),fg="blue")
    label_5.grid(row=8,column=0)
    entry_5=Entry(root,font=("宋体",10),fg="red")
    entry_5.grid(row=9,column=0)

    label_6=Label(root,text='请输入发送邮件的内容:',font=("楷书",10),fg="blue")
    label_6.grid(row=10,column=0)
    entry_6=Text(root,font=("宋体",10),fg="red",width=80,height=40)
    entry_6.grid(row=11,column=0)

    #按钮
    button=Button(root,text='QQ邮箱',font=("楷书",10),fg="black",command=QQ)
    button.grid(row=0,column=2)
    button=Button(root,text='搜狐邮箱',font=("楷书",10),fg="black",command=SOUHU)
    button.grid(row=1,column=2)
    button=Button(root,text='Gmail',font=("楷书",10),fg="black",command=GMAIL)
    button.grid(row=2,column=2)
    button=Button(root,text='雅虎邮箱',font=("楷书",10),fg="black",command=YAHOO)
    button.grid(row=3,column=2)
    button=Button(root,text='发送',font=("楷书",25),fg="green",command=func)
    button.grid(row=10,column=2)
    root.mainloop()

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值