#!/usr/bin/env python3 # Path: testcase/imap_test.py """ IMAP-Verbindungstest für Social Media Account Generator. Dieses eigenständige Skript testet die IMAP-Verbindungsdaten aus der Konfigurationsdatei unter Verwendung der Logik aus email_handler.py. """ import imaplib import email import json import os import sys import time import re from email.header import decode_header from datetime import datetime, timedelta from typing import Dict, List, Any, Optional, Tuple, Union # Füge das Hauptverzeichnis zum Pythonpfad hinzu, um Zugriff auf die Konfigurationsdateien zu erhalten # Der Pfad wird relativ zum Skriptverzeichnis aufgelöst script_dir = os.path.dirname(os.path.abspath(__file__)) base_dir = os.path.dirname(script_dir) # Gehe eine Ebene hoch zum Hauptverzeichnis sys.path.insert(0, base_dir) class EmailTester: """ Tester für IMAP-Email-Funktionalität unter Verwendung der Logik aus email_handler.py. """ CONFIG_FILE = os.path.join(base_dir, "config", "email_config.json") def __init__(self): """Initialisiert den EmailTester und lädt die Konfiguration.""" self.config = self.load_config() # Typische Betreffzeilen für Verifizierungs-E-Mails nach Plattform self.verification_subjects = { "instagram": [ "Bestätige deine E-Mail-Adresse", "Bestätigungscode für Instagram", "Dein Instagram-Code", "Bestätige deinen Instagram-Account", "Verify your email address", "Instagram Verification Code", "Your Instagram Code", "Verify your Instagram account", "Instagram-Bestätigungscode", "Instagram security code" ], "facebook": [ "Bestätigungscode für Facebook", "Facebook-Bestätigungscode", "Dein Facebook-Code", "Facebook Verification Code", "Your Facebook Code" ], "twitter": [ "Bestätige dein Twitter-Konto", "Twitter-Bestätigungscode", "Verify your Twitter account", "Twitter Verification Code" ], "tiktok": [ "TikTok-Bestätigungscode", "Bestätige dein TikTok-Konto", "TikTok Verification Code", "Verify your TikTok account" ], "default": [ "Bestätigungscode", "Verification Code", "Account Verification", "Konto-Bestätigung", "Security Code", "Sicherheitscode" ] } print(f"EmailTester initialisiert, suche nach Konfiguration in: {self.CONFIG_FILE}") def load_config(self) -> Dict[str, Any]: """ Lädt die E-Mail-Konfiguration aus der Konfigurationsdatei. Returns: Dict[str, Any]: Die geladene Konfiguration oder Standardwerte """ default_config = { "imap_server": "imap.ionos.de", "imap_port": 993, "imap_user": "info@z5m7q9dk3ah2v1plx6ju.com", "imap_pass": "cz&ie.O9$!:!tYY@" } try: if os.path.exists(self.CONFIG_FILE): with open(self.CONFIG_FILE, "r", encoding="utf-8") as f: config = json.load(f) print(f"E-Mail-Konfiguration geladen aus: {self.CONFIG_FILE}") return config else: print(f"Konfigurationsdatei nicht gefunden: {self.CONFIG_FILE}") print("Verwende Standardkonfiguration:") print(json.dumps(default_config, indent=2)) return default_config except Exception as e: print(f"Fehler beim Laden der E-Mail-Konfiguration: {e}") print("Verwende Standardkonfiguration.") return default_config def test_connection(self) -> Dict[str, Any]: """ Testet die Verbindung zum IMAP-Server. Returns: Dict[str, Any]: Ergebnis des Tests """ try: print(f"Teste Verbindung zu {self.config['imap_server']}:{self.config['imap_port']}") print(f"Benutzer: {self.config['imap_user']}") # SSL-Verbindung zum IMAP-Server herstellen mail = imaplib.IMAP4_SSL(self.config["imap_server"], self.config["imap_port"]) # Anmelden mail.login(self.config["imap_user"], self.config["imap_pass"]) # Verfügbare Postfächer auflisten status, mailboxes = mail.list() if status == 'OK': print("\nVerfügbare Postfächer:") mailbox_count = 0 for mailbox in mailboxes: if isinstance(mailbox, bytes): try: # Decode von bytes zu string decoded_mailbox = mailbox.decode('utf-8') print(f" - {decoded_mailbox}") mailbox_count += 1 except: print(f" - [Nicht decodierbar: {mailbox}]") else: print(f" - {mailbox}") mailbox_count += 1 # INBOX auswählen mail.select("INBOX") # Abmelden mail.logout() print(f"\nVerbindungstest erfolgreich! {mailbox_count} Postfächer gefunden.") return { "success": True, "server": self.config["imap_server"], "port": self.config["imap_port"], "mailbox_count": mailbox_count } else: print(f"Fehler beim Abrufen der Postfächer: {status}") mail.logout() return { "success": False, "error": f"Fehler beim Abrufen der Postfächer: {status}" } except imaplib.IMAP4.error as e: print(f"IMAP-Fehler: {e}") return { "success": False, "error": f"IMAP-Fehler: {e}" } except Exception as e: print(f"Allgemeiner Fehler: {e}") return { "success": False, "error": f"Allgemeiner Fehler: {e}" } def _extract_email_from_addr(self, addr_str: str) -> str: """ Extrahiert die E-Mail-Adresse aus einem Adressstring im Format 'Name '. Args: addr_str: Adressstring Returns: str: Die extrahierte E-Mail-Adresse oder der ursprüngliche String """ # Regulärer Ausdruck für die Extraktion der E-Mail-Adresse email_pattern = r'?' match = re.search(email_pattern, addr_str) if match: return match.group(1).lower() return addr_str.lower() def search_emails(self, search_criteria: str = "ALL", max_emails: int = 5) -> List[Dict[str, Any]]: """ Sucht nach E-Mails mit den angegebenen Kriterien. Args: search_criteria: IMAP-Suchkriterien max_emails: Maximale Anzahl der abzurufenden E-Mails Returns: List[Dict[str, Any]]: Liste der gefundenen E-Mails """ try: print(f"Suche E-Mails mit Kriterien: {search_criteria}") print(f"Maximale Anzahl: {max_emails}") # Verbindung zum IMAP-Server herstellen mail = imaplib.IMAP4_SSL(self.config["imap_server"], self.config["imap_port"]) # Anmelden mail.login(self.config["imap_user"], self.config["imap_pass"]) # INBOX auswählen mail.select("INBOX") # Nach E-Mails suchen status, data = mail.search(None, search_criteria) emails = [] if status == 'OK': # E-Mail-IDs abrufen email_ids = data[0].split() if not email_ids: print("Keine E-Mails gefunden.") mail.logout() return [] # Newest emails first email_ids = list(reversed(email_ids)) # Begrenze die Anzahl der abzurufenden E-Mails if max_emails > 0: email_ids = email_ids[:max_emails] print(f"Gefunden: {len(email_ids)} E-Mails. Abrufen der Details...") for i, email_id in enumerate(email_ids): # E-Mail abrufen status, data = mail.fetch(email_id, '(RFC822)') if status == 'OK': print(f"Verarbeite E-Mail {i+1}/{len(email_ids)}...") # E-Mail-Inhalt parsen raw_email = data[0][1] msg = email.message_from_bytes(raw_email) # Betreff decodieren subject = decode_header(msg.get("Subject", ""))[0] if isinstance(subject[0], bytes): subject = subject[0].decode(subject[1] or 'utf-8', errors='replace') else: subject = subject[0] # Absender decodieren from_addr = decode_header(msg.get("From", ""))[0] if isinstance(from_addr[0], bytes): from_addr = from_addr[0].decode(from_addr[1] or 'utf-8', errors='replace') else: from_addr = from_addr[0] # Empfänger decodieren to_addr = decode_header(msg.get("To", ""))[0] if isinstance(to_addr[0], bytes): to_addr = to_addr[0].decode(to_addr[1] or 'utf-8', errors='replace') else: to_addr = to_addr[0] # Extrahiere E-Mail-Adresse aus dem To-Feld to_email = self._extract_email_from_addr(to_addr) # Datum decodieren date = msg.get("Date", "") # E-Mail-Text extrahieren body = "" if msg.is_multipart(): for part in msg.walk(): content_type = part.get_content_type() content_disposition = str(part.get("Content-Disposition")) if "attachment" not in content_disposition: if content_type == "text/plain": try: # Textinhalt decodieren charset = part.get_content_charset() or 'utf-8' body = part.get_payload(decode=True).decode(charset, errors='replace') break except: body = "[Fehler beim Decodieren des Inhalts]" elif content_type == "text/html" and not body: try: # HTML-Inhalt decodieren charset = part.get_content_charset() or 'utf-8' body = part.get_payload(decode=True).decode(charset, errors='replace') except: body = "[Fehler beim Decodieren des HTML-Inhalts]" else: try: # Einzel-Teil-E-Mail decodieren charset = msg.get_content_charset() or 'utf-8' body = msg.get_payload(decode=True).decode(charset, errors='replace') except: body = "[Fehler beim Decodieren des Inhalts]" # E-Mail-Informationen speichern email_info = { "id": email_id.decode(), "subject": subject, "from": from_addr, "to": to_addr, "to_email": to_email, "date": date, "body": body } # Nach Bestätigungscode im Inhalt suchen verification_code = self._extract_verification_code(body) if verification_code: email_info["verification_code"] = verification_code emails.append(email_info) # Abmelden mail.logout() print(f"Insgesamt {len(emails)} E-Mails verarbeitet") return emails except Exception as e: print(f"Fehler beim Suchen nach E-Mails: {e}") return [] def _is_subject_relevant(self, subject: str, platform: str) -> bool: """ Prüft, ob der Betreff relevant für eine Verifizierungs-E-Mail der angegebenen Plattform ist. Args: subject: Betreff der E-Mail platform: Plattform (instagram, facebook, twitter, etc.) Returns: bool: True, wenn der Betreff relevant ist, False sonst """ # Betreffzeilen für die angegebene Plattform und Standard subject_patterns = self.verification_subjects.get(platform.lower(), []) subject_patterns += self.verification_subjects["default"] # Prüfe auf exakte Übereinstimmung (schneller) for pattern in subject_patterns: if pattern.lower() in subject.lower(): print(f"Relevanter Betreff gefunden (exakte Übereinstimmung): {subject}") return True return False def _extract_verification_code(self, text: str, platform: str = "instagram") -> Optional[str]: """ Extrahiert einen Bestätigungscode aus einem Text. Args: text: Zu durchsuchender Text platform: Plattform (instagram, facebook, twitter, etc.) Returns: Optional[str]: Der gefundene Bestätigungscode oder None """ # Plattformspezifische Muster für Bestätigungscodes patterns = { "instagram": [ r"Dein Code ist (\d{6})", r"Your code is (\d{6})", r"Bestätigungscode: (\d{6})", r"Confirmation code: (\d{6})", r"(\d{6}) ist dein Instagram-Code", r"(\d{6}) is your Instagram code", r"Instagram-Code: (\d{6})", r"Instagram code: (\d{6})", r"Instagram: (\d{6})", r"[^\d](\d{6})[^\d]" # 6-stellige Zahl umgeben von Nicht-Ziffern ], "facebook": [ r"Dein Code ist (\d{5})", r"Your code is (\d{5})", r"Bestätigungscode: (\d{5})", r"Confirmation code: (\d{5})", r"Facebook-Code: (\d{5})", r"Facebook code: (\d{5})", r"Facebook: (\d{5})", r"[^\d](\d{5})[^\d]" # 5-stellige Zahl umgeben von Nicht-Ziffern ], "twitter": [ r"Code: (\d{6})", r"Verification code: (\d{6})", r"Twitter-Code: (\d{6})", r"Twitter code: (\d{6})", r"Twitter: (\d{6})", r"[^\d](\d{6})[^\d]" # 6-stellige Zahl umgeben von Nicht-Ziffern ], "tiktok": [ r"TikTok-Code: (\d{6})", r"TikTok code: (\d{6})", r"TikTok: (\d{6})", r"[^\d](\d{6})[^\d]" # 6-stellige Zahl umgeben von Nicht-Ziffern ], "default": [ r"Code[:\s]*(\d{4,8})", r"[Vv]erification [Cc]ode[:\s]*(\d{4,8})", r"[Bb]estätigungscode[:\s]*(\d{4,8})", r"(\d{4,8}) is your code", r"(\d{4,8}) ist dein Code", r"[^\d](\d{6})[^\d]", # 6-stellige Zahl umgeben von Nicht-Ziffern r"[^\d](\d{5})[^\d]" # 5-stellige Zahl umgeben von Nicht-Ziffern ] } # Plattformspezifische Muster verwenden platform_patterns = patterns.get(platform.lower(), []) # Alle Muster dieser Plattform durchsuchen for pattern in platform_patterns: match = re.search(pattern, text) if match: code = match.group(1) print(f"Code gefunden mit Muster '{pattern}': {code}") return code # Wenn keine plattformspezifischen Muster gefunden wurden, Default-Muster verwenden for pattern in patterns["default"]: match = re.search(pattern, text) if match: code = match.group(1) print(f"Code gefunden mit Default-Muster '{pattern}': {code}") return code # Generische Suche nach Zahlen (für die jeweilige Plattform typische Länge) code_length = 6 # Standard if platform.lower() == "facebook": code_length = 5 # Suche nach alleinstehenden Zahlen der richtigen Länge generic_pattern = r"\b(\d{" + str(code_length) + r"})\b" matches = re.findall(generic_pattern, text) if matches: # Nehme die erste gefundene Zahl code = matches[0] print(f"Code gefunden mit generischem Muster: {code}") return code return None def find_verification_codes(self, target_email: Optional[str] = None, platform: str = "instagram", max_emails: int = 10) -> List[Dict[str, Any]]: """ Sucht nach Bestätigungscodes in E-Mails. Args: target_email: Ziel-E-Mail-Adresse oder None für alle platform: Plattform (instagram, facebook, twitter, etc.) max_emails: Maximale Anzahl der zu durchsuchenden E-Mails Returns: List[Dict[str, Any]]: Liste der gefundenen E-Mails mit Bestätigungscodes """ # Letzter Tag als Suchkriterium today = datetime.now() yesterday = today - timedelta(days=1) date_str = yesterday.strftime("%d-%b-%Y") search_criteria = f'(SINCE "{date_str}")' if target_email: search_criteria = f'(SINCE "{date_str}" TO "{target_email}")' print(f"Suche nach E-Mails für {target_email} seit {date_str}") else: print(f"Suche nach allen E-Mails seit {date_str}") # Alle E-Mails abrufen emails = self.search_emails(search_criteria, max_emails=max_emails) # Relevante E-Mails filtern verification_emails = [] for email_info in emails: # Extrahierte E-Mail-Adresse des Empfängers to_email = email_info.get("to_email", "").lower() # Wenn eine bestimmte Ziel-E-Mail angegeben ist, prüfe auf Übereinstimmung if target_email and target_email.lower() != to_email: # Wenn Domain angegeben wurde, prüfe auf Domain-Übereinstimmung if '@' in target_email and '@' in to_email: target_domain = target_email.split('@')[1] email_domain = to_email.split('@')[1] if target_domain != email_domain: continue else: continue # Betreff auf Relevanz prüfen subject = email_info.get("subject", "") if self._is_subject_relevant(subject, platform): verification_emails.append(email_info) # Alternativ: In der E-Mail nach Bestätigungscodes suchen elif "verification_code" in email_info or self._extract_verification_code(email_info.get("body", ""), platform): verification_emails.append(email_info) print(f"Gefunden: {len(verification_emails)} E-Mails mit Bestätigungscodes oder relevanten Betreffs") return verification_emails def display_email(email_info, truncate_body=True): """ Zeigt eine E-Mail formatiert an. Args: email_info: E-Mail-Informationen truncate_body: Wenn True, wird der Body gekürzt """ print("\n" + "="*80) print(f"ID: {email_info.get('id', 'N/A')}") print(f"Von: {email_info.get('from', 'N/A')}") print(f"An: {email_info.get('to', 'N/A')}") print(f"Datum: {email_info.get('date', 'N/A')}") print(f"Betreff: {email_info.get('subject', 'N/A')}") # Bestätigungscode anzeigen, falls vorhanden verification_code = email_info.get("verification_code") if verification_code: print(f"\n>>> BESTÄTIGUNGSCODE GEFUNDEN: {verification_code} <<<\n") # Body anzeigen print("\nInhalt:") print("-"*80) body = email_info.get("body", "") if truncate_body and len(body) > 500: print(body[:500] + "...\n[Gekürzt - Vollständigen Inhalt mit Option 2 anzeigen]") else: print(body) print("="*80) def main(): """Hauptfunktion des Skripts.""" print("="*80) print("IMAP-Verbindungs- und E-Mail-Test") print("="*80) # EmailTester initialisieren tester = EmailTester() # Verbindung testen connection_result = tester.test_connection() if not connection_result["success"]: print("\nVerbindungstest fehlgeschlagen!") print(f"Fehler: {connection_result.get('error', 'Unbekannter Fehler')}") sys.exit(1) # Interaktives Menü while True: print("\n" + "="*80) print("MENU") print("="*80) print("1. Letzte E-Mails anzeigen") print("2. Vollständigen Inhalt einer E-Mail anzeigen") print("3. Nach Bestätigungscodes suchen") print("4. Bestätigungscodes für eine bestimmte E-Mail-Adresse suchen") print("5. Verbindungstest erneut durchführen") print("0. Beenden") print("="*80) choice = input("Wählen Sie eine Option: ") if choice == "1": # Letzte E-Mails anzeigen max_emails = int(input("Anzahl der anzuzeigenden E-Mails (Standard: 5): ") or "5") emails = tester.search_emails(max_emails=max_emails) if emails: print(f"\n{len(emails)} E-Mails gefunden:") for email_info in emails: display_email(email_info) else: print("Keine E-Mails gefunden.") elif choice == "2": # Vollständigen Inhalt einer E-Mail anzeigen email_id = input("Geben Sie die E-Mail-ID ein: ") if not email_id: print("Keine ID angegeben.") continue # Suche nach der E-Mail mit der angegebenen ID emails = tester.search_emails(search_criteria=f"(UID {email_id})", max_emails=1) if emails: display_email(emails[0], truncate_body=False) else: print(f"Keine E-Mail mit ID {email_id} gefunden.") elif choice == "3": # Nach Bestätigungscodes in allen E-Mails suchen platform = input("Plattform (instagram, facebook, twitter, tiktok, default): ") or "instagram" max_emails = int(input("Maximale Anzahl zu durchsuchender E-Mails (Standard: 10): ") or "10") verification_emails = tester.find_verification_codes(platform=platform, max_emails=max_emails) if verification_emails: print(f"\n{len(verification_emails)} E-Mails mit Bestätigungscodes oder relevanten Betreffs gefunden:") for email_info in verification_emails: display_email(email_info) else: print("Keine relevanten E-Mails mit Bestätigungscodes gefunden.") elif choice == "4": # Nach Bestätigungscodes für eine bestimmte E-Mail-Adresse suchen email_address = input("E-Mail-Adresse: ") if not email_address: print("Keine E-Mail-Adresse angegeben.") continue platform = input("Plattform (instagram, facebook, twitter, tiktok, default): ") or "instagram" max_emails = int(input("Maximale Anzahl zu durchsuchender E-Mails (Standard: 10): ") or "10") verification_emails = tester.find_verification_codes( target_email=email_address, platform=platform, max_emails=max_emails ) if verification_emails: print(f"\n{len(verification_emails)} E-Mails mit Bestätigungscodes für {email_address} gefunden:") for email_info in verification_emails: display_email(email_info) else: print(f"Keine relevanten E-Mails mit Bestätigungscodes für {email_address} gefunden.") elif choice == "5": # Verbindungstest erneut durchführen connection_result = tester.test_connection() if not connection_result["success"]: print("\nVerbindungstest fehlgeschlagen!") print(f"Fehler: {connection_result.get('error', 'Unbekannter Fehler')}") elif choice == "0": # Beenden print("Programm wird beendet.") break else: print("Ungültige Eingabe. Bitte versuchen Sie es erneut.") if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\nProgramm durch Benutzer abgebrochen. Auf Wiedersehen!") except Exception as e: print(f"\nUnerwarteter Fehler: {e}")