import json from imap_client import ImapMailClient from ai_classifier import classify_email def load_config(path='config.json'): """설정 파일을 로드합니다.""" print(f"'{path}' 파일에서 설정 로드 중...") with open(path, 'r', encoding='utf-8') as f: return json.load(f) def load_rules(path='rules.json'): """규칙 파일을 로드합니다.""" print(f"'{path}' 파일에서 규칙 로드 중...") with open(path, 'r', encoding='utf-8') as f: return json.load(f) def check_conditions(email_details, conditions): """이메일이 주어진 조건을 만족하는지 확인합니다.""" for key, value in conditions.items(): if key == 'from_contains': if value.lower() not in email_details.get('from', '').lower(): return False elif key == 'subject_contains': if value.lower() not in email_details.get('subject', '').lower(): return False elif key == 'ai_classification_is': if value != email_details.get('ai_category'): return False # 여기에 'to_contains', 'body_contains' 등 다른 조건을 추가할 수 있습니다. return True def process_emails(imap_client, rules_config, gemini_api_key): """ 읽지 않은 이메일을 가져와서 규칙에 따라 처리합니다. """ unread_uids = imap_client.fetch_unread_emails() ai_categories = rules_config.get('ai_categories', []) for uid in unread_uids: email_details = imap_client.fetch_email(uid) if not email_details: continue print(f"\n[처리 시작] 메일 UID: {uid.decode()}, 제목: {email_details['subject']}") # AI 분류 실행 (필요한 경우) # AI 규칙이 하나라도 있을 때만 API를 호출하도록 최적화할 수 있음 email_details['ai_category'] = None if ai_categories: email_content_for_ai = f"Subject: {email_details['subject']}\n\nBody:\n{email_details['body']}" email_details['ai_category'] = classify_email(gemini_api_key, email_content_for_ai, ai_categories) # 규칙 검사 matched_rule = None for rule in rules_config.get('rules', []): if check_conditions(email_details, rule.get('conditions', {})): matched_rule = rule break action_info = None if matched_rule: print(f"-> 규칙 '{matched_rule.get('rule_name', '이름 없음')}'에 해당합니다.") action_info = matched_rule.get('action') else: print("-> 일치하는 규칙이 없어 기본 행동을 실행합니다.") action_info = rules_config.get('default_action') if action_info: execute_action(imap_client, email_details, action_info) else: print("-> 실행할 행동이 정의되지 않았습니다.") def execute_action(client, email, action): """규칙에 따른 행동을 실행합니다.""" action_type = action.get('type') params = action.get('parameters', {}) uid = email['uid'] if action_type == 'DEVONTHINK': print("-> 행동: DEVONthink로 저장") inbox_path = params.get('devonthink_inbox_path') if inbox_path: client.download_email(email, inbox_path) # 다운로드 후 메일 삭제 또는 다른 곳으로 이동 등 추가 행동을 원하면 여기에 구현 client.delete_email(uid) # 예: 다운로드 후 휴지통으로 이동 else: print("! 경고: 'devonthink_inbox_path'가 rules.json에 지정되지 않았습니다.") elif action_type == 'CATEGORIZE': target_mailbox = params.get('move_to_mailbox') # TODO: IMAP으로는 Synology의 '레이블'을 직접 제어하기 어려움. # 대신 메일함으로 이동하는 것으로 대체. print(f"-> 행동: '{target_mailbox}' 메일함으로 이동") if target_mailbox: client.move_email(uid, target_mailbox) else: print("! 경고: 'move_to_mailbox'가 rules.json에 지정되지 않았습니다.") elif action_type == 'REVIEW': target_mailbox = params.get('move_to_mailbox') print(f"-> 행동: '{target_mailbox}' 메일함으로 이동 (검토 필요)") if target_mailbox: client.move_email(uid, target_mailbox) else: print("! 경고: 'move_to_mailbox'가 rules.json에 지정되지 않았습니다.") elif action_type == 'TRASH': print("-> 행동: 휴지통으로 이동") client.delete_email(uid) else: print(f"! 경고: 알 수 없는 행동 타입 '{action_type}' 입니다.") def run_email_processing(): """메인 실행 함수""" config = load_config() rules_config = load_rules() imap_client = ImapMailClient( server=config['imap']['server'], port=config['imap']['port'], username=config['username'], password=config['password'] ) gemini_api_key = config.get('gemini_api_key') if imap_client.connect(): process_emails(imap_client, rules_config, gemini_api_key) imap_client.close() else: print("프로세스를 시작할 수 없습니다. IMAP 연결 정보를 확인하세요.")