You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

56 lines
2.1 KiB
Python

# backend/app/connectors/mail/real_imap.py — IMAP(HEY/일반) sync 커넥터 (phase-13)
# 로컬 우선 대안: OAuth 불필요. UID SEARCH SINCE 증분 → 동일 normalize_email 로 귀결.
import email as email_lib
import imaplib
from datetime import UTC, datetime
from sqlmodel import Session
from ...crypto import decrypt_token # token_enc 에 {host,user,password} 저장
from ..base import BaseConnector, NormalizedRecord, RawRecord
from .normalize import normalize_email, upsert_email
class ImapConnector(BaseConnector):
domain = "mail"
entity_type = "email"
def fetch(self, session: Session, *, full: bool = False):
creds = decrypt_token(self.account.token_enc)
if not creds:
raise PermissionError("imap credentials missing")
m = imaplib.IMAP4_SSL(creds["host"])
m.login(creds["user"], creds["password"])
m.select("INBOX")
crit = "ALL" if full else "UNSEEN"
_typ, data = m.search(None, crit)
for uid in data[0].split():
_t, msgdata = m.fetch(uid, "(RFC822)")
raw_bytes = msgdata[0][1]
msg = email_lib.message_from_bytes(raw_bytes)
payload = {
"from": msg.get("From", ""),
"subject": msg.get("Subject", ""),
"to": msg.get("To", ""),
"preview": (
(msg.get_payload(decode=False) or "")[:120] if not msg.is_multipart() else ""
),
"date": msg.get("Date", "방금"),
}
yield RawRecord(
external_id=msg.get("Message-ID", uid.decode()),
payload=payload,
etag=msg.get("Date", ""),
external_updated_at=datetime.now(UTC),
)
m.logout()
def normalize(self, raw: RawRecord) -> NormalizedRecord:
return normalize_email(self.account, raw, provider="imap")
def write(self, session: Session, norm: NormalizedRecord):
return upsert_email(session, norm)
def event_for(self, norm, entity_id):
return "mail.received"