diff --git a/.env.example b/.env.example index 3dd8036..1ff7352 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,7 @@ DEST_PORT=993 DEST_USER=your@mxroute.com DEST_PASS=password FOLDERS=INBOX,Sent +STATE_DIR=./state DRY_RUN=false UPTIME_SUCCESS_URL=https://your-uptime-instance.com/api/push/your-token?status=up&msg=OK&ping= UPTIME_FAIL_URL=https://your-uptime-instance.com/api/push/your-token?status=down&msg=Failed \ No newline at end of file diff --git a/README.md b/README.md index f281f25..8767976 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This will set up the virtual environment, systemd services, and provide post-ins - `DEST_USER`: Destination email/username - `DEST_PASS`: Destination password - `FOLDERS`: Folders to sync (default "INBOX,Sent"; use "all" for all folders or comma-separated list) +- `STATE_DIR`: Directory for state files (default "./state") - `DRY_RUN`: Set to `true` for testing without forwarding (default false) - `UPTIME_SUCCESS_URL`: URL for success ping - `UPTIME_FAIL_URL`: URL for failure ping diff --git a/email_forwarder/email_forwarder.py b/email_forwarder/email_forwarder.py index 712206e..d7d0625 100644 --- a/email_forwarder/email_forwarder.py +++ b/email_forwarder/email_forwarder.py @@ -126,6 +126,10 @@ class EmailForwarder: def __init__(self, config: dict): self.config = config + self.state_dir = config["state_dir"] + os.makedirs(self.state_dir, exist_ok=True) + self.processed_file = os.path.join(self.state_dir, "processed_message_ids.txt") + self.last_run_file = os.path.join(self.state_dir, "last_run.txt") self.source = SourceImap( config["source_host"], config["source_port"], @@ -144,23 +148,21 @@ class EmailForwarder: def load_state(self): """Load last run and processed IDs.""" - last_run_file = self.config["last_run_file"] - if os.path.exists(last_run_file): - with open(last_run_file) as f: + if os.path.exists(self.last_run_file): + with open(self.last_run_file) as f: last_run_str = f.read().strip() self.last_run = datetime.fromisoformat(last_run_str) else: self.last_run = datetime.now(timezone.utc) - processed_file = self.config["processed_file"] - if os.path.exists(processed_file): - with open(processed_file, "r") as f: + if os.path.exists(self.processed_file): + with open(self.processed_file, "r") as f: self.processed_ids = set(filter(None, (line.strip() for line in f))) def save_state(self): """Save last run and processed IDs.""" if not self.dry_run: - with open(self.config["last_run_file"], "w") as f: + with open(self.last_run_file, "w") as f: f.write(datetime.now(timezone.utc).isoformat()) def sync_all_folders(self): @@ -209,7 +211,7 @@ class EmailForwarder: if not self.dry_run: self.dest.append_email(folder, raw_msg) self.processed_ids.add(msg_id) - with open(self.config["processed_file"], "a") as f: + with open(self.processed_file, "a") as f: f.write(msg_id + "\n") forwarded += 1 logging.info(f"Forwarded {msg_id} from {folder}") @@ -239,8 +241,7 @@ def load_config(): "dest_user": os.getenv("DEST_USER"), "dest_pass": os.getenv("DEST_PASS"), "folders": os.getenv("FOLDERS", "INBOX"), - "processed_file": "processed_message_ids.txt", - "last_run_file": "last_run.txt", + "state_dir": os.getenv("STATE_DIR", "./state"), "dry_run": os.getenv("DRY_RUN", "false").lower() == "true", } # Validate required