Add dual authentication support and comprehensive provider examples

Core functionality:
- Add dual authentication support (username + email fallback)
- Enhance IMAPConnection to try username first, then email
- Add SOURCE_USERNAME and DEST_USERNAME configuration options
- Improve authentication error handling and logging

Configuration updates:
- Add Host Europe to Securehost.de migration examples
- Include authentication method explanations for various providers
- Add comprehensive provider-specific settings (Host Europe, Securehost.de, etc.)
- Document username vs email login methods with examples

Documentation updates:
- Add dual authentication section in README
- Include Host Europe and Securehost.de specific examples
- Expand troubleshooting section with authentication help
- Add provider-specific troubleshooting guidance
- Include migration best practices

Features:
- Automatic fallback from username to email authentication
- Enhanced logging showing which authentication method succeeded
- Support for various hosting providers and their login requirements
- Improved error messages for authentication failures
This commit is contained in:
Elmar Sönser 2025-09-24 14:16:49 +02:00
commit 1d7fe31845
3 changed files with 211 additions and 53 deletions

View file

@ -30,10 +30,11 @@ def setup_logging(log_level):
return logging.getLogger(__name__)
class IMAPConnection:
def __init__(self, server, port, email_addr, password, use_ssl=True, timeout=60):
def __init__(self, server, port, email_addr, username, password, use_ssl=True, timeout=60):
self.server = server
self.port = port
self.email = email_addr
self.username = username
self.password = password
self.use_ssl = use_ssl
self.timeout = timeout
@ -49,8 +50,34 @@ class IMAPConnection:
self.connection = imaplib.IMAP4(self.server, self.port)
self.connection.sock.settimeout(self.timeout)
self.connection.login(self.email, self.password)
self.logger.info(f"Connected to {self.server} as {self.email}")
# Try authentication with username first (if provided), then fall back to email
login_success = False
login_user = None
if self.username and self.username.strip():
try:
self.connection.login(self.username, self.password)
login_user = self.username
login_success = True
self.logger.info(f"Connected to {self.server} using username: {self.username}")
except Exception as username_error:
self.logger.debug(f"Username login failed for {self.username}: {username_error}")
# If username login failed or no username provided, try email
if not login_success:
try:
self.connection.login(self.email, self.password)
login_user = self.email
login_success = True
self.logger.info(f"Connected to {self.server} using email: {self.email}")
except Exception as email_error:
self.logger.error(f"Email login failed for {self.email}: {email_error}")
if not login_success:
self.logger.error(f"Failed to authenticate with {self.server} using both username and email")
return False
return True
except Exception as e:
self.logger.error(f"Failed to connect to {self.server}: {e}")
@ -144,7 +171,10 @@ class EmailMigrator:
if not self.import_folder_name:
self.import_folder_name = None
self.logger.info(f"Import folder configuration: {'All emails will be imported to subfolders within \"' + self.import_folder_name + '\"' if self.import_folder_name else 'All emails will be imported directly to INBOX'}")
if self.import_folder_name:
self.logger.info(f"Import folder configuration: All emails will be imported to subfolders within \"{self.import_folder_name}\"")
else:
self.logger.info("Import folder configuration: All emails will be imported directly to INBOX")
include_str = config.get('INCLUDE_FOLDERS', '')
exclude_str = config.get('EXCLUDE_FOLDERS', '')
@ -158,6 +188,7 @@ class EmailMigrator:
config['SOURCE_IMAP_SERVER'],
int(config['SOURCE_IMAP_PORT']),
config['SOURCE_EMAIL'],
config.get('SOURCE_USERNAME', ''),
config['SOURCE_PASSWORD'],
config.get('SOURCE_IMAP_USE_SSL', 'True').lower() == 'true',
timeout
@ -167,6 +198,7 @@ class EmailMigrator:
config['DEST_IMAP_SERVER'],
int(config['DEST_IMAP_PORT']),
config['DEST_EMAIL'],
config.get('DEST_USERNAME', ''),
config['DEST_PASSWORD'],
config.get('DEST_IMAP_USE_SSL', 'True').lower() == 'true',
timeout