Python手搓邮件发送客户端

2025-01-21 16:50
文章标签 python 客户端 邮件 发送

本文主要是介绍Python手搓邮件发送客户端,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Python手搓邮件发送客户端》这篇文章主要为大家详细介绍了如何使用Python手搓邮件发送客户端,支持发送邮件,附件,定时发送以及个性化邮件正文,感兴趣的可以了解下...

1. 简介

这款邮件发送客户端是一款桌面应用程序,旨在提供一个简洁且高效的邮件发送界面,支持发送邮件、附件、定时发送以及个性化邮件正文。该应用支持通过SMTP协议发送电子邮件,提供丰富的配置选项,并支持附件管理。它还允许用户设置邮件签名,支持拖拽文件添加附件,能够根据用户设定的时间进行邮件的定时发送。界面设计采用了浅蓝色主题,用户体验友好。

2.主要功能

2.1.邮件发送功能

  • 输入邮件账号、授权码、SMTP服务器、端口等信息。
  • 填写邮件收件人、抄送人、邮件标题和正文。
  • 支持富文本格式邮件正文(支持html和图片)。
  • 可以添加附件,并在邮件中附加多个文件。
  • 用户点击发送邮件按钮时,send_email 函数会读取用户输入的邮件信息(账号、密码、SMTP信息等),创建一个 MIME
  • 格式的邮件对象。邮件正文以 HTML 格式发送,并添加附件(如果有)。
  • 通过 smtplib.SMTP_SSL 连接到SMTP服务器,并使用提供的邮件账号和授权码登录,最后将邮件发送出去。

2.2.个性签名功能

允许用户设置邮件的个性签名,支持HTML和图片:通过 signature_input 支持富文本,用户可以在其中插入HTML标签(包括 标签)。在发送邮件时,如果个性签名包含图片,这些图片会被作为附件嵌入到邮件中。

2.3.定时发送功能

用户可以设置定时发送邮件的时间。schedule_email_send

函数会根据当前时间和设定的时间差,利用定时器(QTimer)在指定时间调用 send_email 函数发送邮件。

为了支持定时发送邮件功能,需要在现有代码中添加一个定时器,允许用户设定发送时间,并在设定的时间自动发送邮件。我们可以通过 QTimer 来实现定时功能。

定时发送部分:

新增了 QDateTimeEdit 输入框,允许用户选择定时发送的日期和时间。

新增了一个 schedule_email_send() 函数,用来计算当前时间与目标发送时间的差距,并通过

QTimer.singleShot() 在设定的时间触发邮件发送。

定时发送邮件 按钮将调用 schedule_email_send() 函数。

相关定时器的实现:

使用 QTimer.singleShot() 来定时触发邮件发送。该函数接收时间间隔(以毫秒为单位)和要执行的回调函数(即send_email())。

2. 4.附件管理

支持通过文件选择框或者拖拽文件添加附件。

显示附件名称和文件大小。

支持清除附件功能。

一键多选附件:

China编程

附件添加:通过 add_attachment

函数,用户可以通过文件对话框选择一个或多个文件,添加到附件列表,并在表格中显示文件名和文件大小。

附件清除:通过 clear_attachments 函数,用户可以清空附件列表。

附件表格:attachment_table 用于显示附件信息,每个附件占一行,显示文件名和大小。

使用filedialog.askopenfilenames(),允许用户选择多个文件。

选择的每个文件的名称、路径和文件大小被添加到附件列表中。

使用tkinterdnd2库实现拖拽文件到程序中。 当文件被拖拽到窗口时,会显示附件的名称和文件大小。

2.5.配置加载功能

应用启动时,load_config 函数会检查当前路径是否存在 config.ini文件,如果存在,将从文件中读取邮件账号、授权码、SMTP服务器及端口,并自动填充输入框,且设置为只读。

配置文件格式 (config.ini): config.ini文件应包含如下内容:

sender_email:邮件账号。

sender_password:授权码。

smtp_server:SMTP服务器地址。

smtp_port:SMTP服务器端口号。

[Email]
sender_email = your_email@example.com
sender_password = your_authorization_code

[SMTP]
smtp_server = smtp.example.com
smtp_port = 465

自动加载当前路径配置文件(config.ini),填充发件人的邮件账号、授www.chinasem.cn权码等字段信息,并设置为只读。

2.6.主题设置和UI

使用 QvboxLayout 和 QHBoxLayout 布局管理器,组织各个控件的排版。

使用 QPalette 设置浅蓝色背景、按钮背景和输入框背景等颜色,并定义按钮文本为白色,使用 Segoe UI 字体。

2.7.错误处理与消息框

在遇到错误(如SMTP连接失败、配置文件读取失败等)时,使用 QMessageBox 弹出提示框显示错误信息。

2.8 日志保存功能

在当前路径生成 email_send.log日志文件,保存相关邮件发送信息等事件。

3. 运行效果

普通界面:

Python手搓邮件发送客户端

UI美化界面:

Python手搓邮件发送客户端

发送成功界面:

Python手搓邮件发送客户端

邮箱接收界面:

Python手搓邮件发送客户端

日志生成页面:

Python手搓邮件发送客户端

资源列表页面:

Python手搓邮件发送客户端

4.BUG修复之路

显示发送邮件失败,软件报错:getaddrinfo faied

后面检查发现是邮件服务器填写时候多敲了一个空格导致的报错,后面在发送邮件时,在send_email函数中,使用.strip()方法去除输入框内容的首尾空格和TAB字符。

邮件正文通过body_text.get(“1.0”, tk.END).strip()获取内容时,也会清除多余的空格和TAB字符。

附件发送比如.xlsx发出去变成未命名.bin文件

当发送 .xlsx 等 Office 类型附件时,附件变成 .bin 文件的原因,通常是因为邮件的 MIME类型没有正确指定,导致邮件客户端无法识别文件类型并将其处理为二进制流。因此,需要确保在附件添加时指定正确的 MIME 类型和内容类型。

对于 .xlsx 文件,我们需要确保 MIME 类型设置为application/vnd.openXMLpythonformats-officedocument.spreadsheetml.sheet。同样,其他Office 文件(如 .docx、.pptx)也有各自的 MIME 类型。

修改代码:正确设置 MIME 类型

我们可以修改附件的 MIME 类型来确保文件以原格式发送。以下是如何修复这个问题:

针对 Office 文件设置正确的 MIME 类型

根据附件的扩展名自动设置 MIME 类型

主要修改:

使用 mimetypes 识别文件类型:通过 mimetypes.guess_type() 函数识别文件的 MIME

类型。如果文件类型是已知的(例如 .xlsx),就会设置正确的 MIME 类型。

create_attachment 函数:这个函数根据文件类型创建附件并设置适当的 MIME 类型。如果是 .xlsx 文件,则设置application/vnd.openxmlformats-officedocument.spreadsheetml.sheet MIME 类型。

5.部分相关源码分享

# 读取config.ini文件并填充输入框
def load_config():
    config_file = "config.ini"
    if os.path.exists(config_file):
        config = configparser.ConfigParser()
        config.read(config_file)
        
        try:
            sender_email = config.get("Email", "sender_email")
            sender_password = config.get("Email", "sender_password")
            smtp_server = config.get("SMTP", "smtp_server")
            smtp_port = config.get("SMTP", "smtp_port")
            
            # 填充输入框并设置为只读
            sender_email_input.setText(sender_email)
            sender_password_input.setText(sender_password)
            smtp_server_input.setText(smtp_server)
            smtp_port_input.setText(smtp_port)
            
            # 设置输入框为只读
            sender_email_input.setReadOnly(True)
            sender_password_input.setReadOnly(True)
            smtp_server_input.setReadOnly(True)
            smtp_port_input.setReadOnly(True)
            
        except Exception as e:
            QMessageBox.critical(window, "错误", f"读取配置文件失败: {e}")
    else:
        # 如果没有config.ini文件,不做任何操作
        pass

# 发送邮件的函数
def send_email():
    sender_email = sender_email_input.text().strip()
    sender_password = sender_password_input.text().strip()
    smtp_server = smtp_server_input.text().strip()
    smtp_port = smtp_port_input.text().strip()
    recipient_email = recipient_input.text().strip()
    cc_email = cc_input.text().strip().replace(";", ",")  # 替换中文分隔符
    subject = subject_input.text().strip()
    body = body_input.toPlainText().strip()
    signature = signature_input.toHtml().strip()  # 获取个性签名HTML内容

    # 将个性签名添加到邮件正文
    if signature:
        body += f"<br><br>{signature}"

    # 检查SMTP端口是否有效
    if not smtp_port.isdigit():
        QMessageBox.critical(window, "错误", "请输入有效的SMTP端口号!")
        return

    # 创建邮件
    msg = MIMEMultipart("related")  # 允许邮件中包含HTML内容和附件
    msg['From'] = sender_email
    msg['To'] = recipient_email
    if cc_email:
        msg['Cc'] = cc_email  # 抄送多个邮箱
    msg['Subject'] = subject

    # 邮件正文
    msg_html = MIMEText(body, 'html', 'utf-8')  # 使用HTML格式发送邮件正文
    msg.attach(msg_html)

    # 添加附件
    for file in attachments:
        file_path = file['path']
        file_name = file['name']
        mime_type, _ = mimetypes.guess_type(file_path)  # 根据文件扩展名自动猜测 MIME 类型
        if mime_type is None:
            mime_type = 'application/octet-stream'  # 默认 MIME 类型
        
        main_type, sub_type = mime_type.split('/')
        part = MIMEBase(main_type, sub_type)
        with open(file_path, 'rb') as f:
            part.set_payload(f.read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition', f'attachment; filename="{file_name}"')
        msg.attach(part)

    try:
        # 设置SMTP服务器
        with smtplib.SMTP_SSL(smtp_server, int(smtp_port)) as server:
            server.login(sender_email, sender_password)
            # 发送邮件
            server.sendmail(sender_email, [recipient_email] + (cc_email.split(',') if cc_email else []), msg.as_string())
        
        QMessageBox.information(window, "成功", "邮件发送成功!")
        #clear_fields()  # 发送邮件后清除输入框和附件
    except Exception as e:
        QMessagehttp://www.chinasem.cnBox.critical(window, "错误", f"发送邮件失败: {e}")

# 添加附件的函数
def add_attachment():
    file_paths, _ = QFileDialog.getOpenFileNames(window, "选择附件", "", "All Files (*);;Text Files (*.txt);;Image Files (*.png *.jpg *.bmp);;Excel Files (*.xlsx);;PDF Files (*.pdf)")
    if file_paths:
        for file_path in file_paths:
            file_name = os.path.basename(file_path)
            file_size = os.path.getsize(file_path)
            attachments.append({"name": file_name, "path": file_path, "size": file_size})
            # 将附件信息添加到表格中
            row_position = attachment_table.rowCount()
            attachment_table.insertRow(row_position)
            attachment_table.setItem(row_position, 0, QTableWidgetItem(file_name))
            attachment_table.setItem(row_position, 1, QTableWidgetItem(f"{file_size // 1024} KB"))

# 清除附件的函数
def clear_attachments():
    attachments.clear()
    attachment_table.setRowCount(0)

# 清除所有输入框的内容和附件
def clear_fields():
    sender_email_input.clear()
    sender_password_input.clear()
    smtp_server_input.clear()
    smtp_port_input.clear()
    recipient_input.clear()
    cc_input.clear()
    subject_input.clear()
    body_input.clear()
    signature_input.clear()  # 清除个性签名输入框内容
    clear_attachments()  # 清除附件列表

# 设置定时发送的函数
def schedule_email_send():
    send_time = send_time_input.dateTime()
    current_time = QDateTime.currentDateTime()
    
    if send_time <= current_time:
        QMessageBox.critical(window, "错误", "请选择未来的时间!")
        return
    
    time_diff = current_time.msecsTo(send_time)  # 计算定时发送的时间差
    timer.singleShot(time_diff, send_email)  # 定时调用发送邮件函数
    QMessageBox.information(window, "成功", f"邮件将在 {send_time.toString()} 发送。")

# 创建主窗口
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle("邮件发送客户端")
window.setWindowIcon(QIcon("icon.png"))  # 可以设置一个图标
window.setGeometry(100, 100, 400, 700)  # 增加窗口高度,以适应新添加的个性签名文本框

# 创建浅蓝色主题
def set_light_blue_theme():
    palette = QPalette()
    palette.setColor(QPalette.Background, QColor(173, 216, 230))  # 浅蓝色背景
    palette.setColor(QPalette.WindowText, QColor(0, 0, 0))  # 黑色文本
    palette.setColor(QPalette.Button, QColor(73, 170, 160))  # 按钮背景色为 #49AAA0
    palette.setColor(QPalette.ButtonText, QColor(255, 255, 255))  # 按钮文本为白色
    palette.setColor(QPalette.Base, QColor(240, 248, 255))  # 浅蓝色输入框背景
    palette.setColor(QPalette.Text, QColor(0, 0, 0))  # 黑色文本
    window.setPawww.chinasem.cnlette(palette)

set_light_blue_theme()

# 设置字体为 Segoe UI
font = QFont("Segoe UI", 10)
window.setFont(font)

6.总结

总之这个邮件客户端不仅提供基础的邮件发送和附件管理功能,还集成了定时发送、个性签名等高级功能,兼具简洁的用户界面和较强的功能扩展性。界面采用简洁明了的浅蓝色主题,结合了现代UI设计理念和丰富的邮件配置选项,适合用户进行邮件发送和管理

以上就是python手搓邮件发送客户端的详细内容,更多关于Python邮件发送的资料请关注编程China编程(www.chinasem.cn)其它相关文章!

这篇关于Python手搓邮件发送客户端的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153166

相关文章

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

Python Jupyter Notebook导包报错问题及解决

《PythonJupyterNotebook导包报错问题及解决》在conda环境中安装包后,JupyterNotebook导入时出现ImportError,可能是由于包版本不对应或版本太高,解决方... 目录问题解决方法重新安装Jupyter NoteBook 更改Kernel总结问题在conda上安装了

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

Python安装时常见报错以及解决方案

《Python安装时常见报错以及解决方案》:本文主要介绍在安装Python、配置环境变量、使用pip以及运行Python脚本时常见的错误及其解决方案,文中介绍的非常详细,需要的朋友可以参考下... 目录一、安装 python 时常见报错及解决方案(一)安装包下载失败(二)权限不足二、配置环境变量时常见报错及

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操