Improve encapsulation in IMAP classes

Make all attributes private (_host, _imap, etc.) and remove redundant
public connect/disconnect methods. Connection management is now handled
internally by the orchestrator calling private _connect/_disconnect.

Changes:
- Privatize ImapClient attributes and methods
- Update EmailForwarder to call private connection methods
- Enhance encapsulation without changing functionality
This commit is contained in:
Jeena 2026-01-04 16:48:57 +09:00
parent f70f1853f0
commit f2bc700939

40
main.py
View file

@ -15,34 +15,26 @@ class ImapClient:
"""Base class for IMAP operations.""" """Base class for IMAP operations."""
def __init__(self, host: str, port: int, user: str, password: str): def __init__(self, host: str, port: int, user: str, password: str):
self.host = host self._host = host
self.port = port self._port = port
self.user = user self._user = user
self.password = password self._password = password
self.imap = None self._imap = None
def connect(self):
"""Establish IMAP connection."""
self._connect()
def disconnect(self):
"""Close IMAP connection."""
self._disconnect()
def _connect(self): def _connect(self):
"""Private: Connect and login to IMAP.""" """Private: Connect and login to IMAP."""
self.imap = imaplib.IMAP4_SSL(self.host, self.port) self._imap = imaplib.IMAP4_SSL(self._host, self._port)
self.imap.login(self.user, self.password) self._imap.login(self._user, self._password)
def _disconnect(self): def _disconnect(self):
"""Private: Logout and close connection.""" """Private: Logout and close connection."""
if self.imap: if self._imap:
self.imap.logout() self._imap.logout()
self.imap = None self._imap = None
def _list_folders(self): def _list_folders(self):
"""Private: List all folders.""" """Private: List all folders."""
typ, data = self.imap.list() typ, data = self._imap.list()
if typ != "OK": if typ != "OK":
raise Exception("Failed to list folders") raise Exception("Failed to list folders")
folders = [] folders = []
@ -56,20 +48,20 @@ class ImapClient:
def _select_folder(self, folder: str): def _select_folder(self, folder: str):
"""Private: Select a folder.""" """Private: Select a folder."""
typ, _ = self.imap.select(folder) typ, _ = self._imap.select(folder)
if typ != "OK": if typ != "OK":
raise Exception(f"Failed to select folder {folder}") raise Exception(f"Failed to select folder {folder}")
def _search(self, criteria: str): def _search(self, criteria: str):
"""Private: Search emails.""" """Private: Search emails."""
typ, data = self.imap.search(None, criteria) typ, data = self._imap.search(None, criteria)
if typ != "OK": if typ != "OK":
raise Exception(f"Search failed: {criteria}") raise Exception(f"Search failed: {criteria}")
return data[0].split() return data[0].split()
def _fetch(self, uid: str): def _fetch(self, uid: str):
"""Private: Fetch raw email.""" """Private: Fetch raw email."""
typ, data = self.imap.fetch(uid, "(RFC822)") typ, data = self._imap.fetch(uid, "(RFC822)")
if typ != "OK": if typ != "OK":
raise Exception(f"Failed to fetch UID {uid}") raise Exception(f"Failed to fetch UID {uid}")
return data[0][1] return data[0][1]
@ -120,13 +112,13 @@ class DestImap(ImapClient):
def _create_folder(self, folder: str): def _create_folder(self, folder: str):
"""Private: Create a folder.""" """Private: Create a folder."""
typ, _ = self.imap.create(folder) typ, _ = self._imap.create(folder)
if typ != "OK": if typ != "OK":
raise Exception(f"Failed to create folder {folder}") raise Exception(f"Failed to create folder {folder}")
def _append(self, folder: str, msg: bytes): def _append(self, folder: str, msg: bytes):
"""Private: Append message to folder.""" """Private: Append message to folder."""
self.imap.append(folder, "", None, msg) self._imap.append(folder, "", None, msg)
class EmailForwarder: class EmailForwarder: