ea20f5b333
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.5 KiB
5.5 KiB
name, description, type
| name | description | type |
|---|---|---|
| IMX[계획] IMAP 메일 기능 확장 | 메일 삭제, SMTP 발송, 폴더 전환, 첨부파일 다운로드, 이동, 답장/전달 구현 | plan |
IMX 계획 — IMAP 메일 기능 확장
개요
기존 메일 조회/읽음처리만 되던 IMAP 페이지에 전체 메일 클라이언트 기능 추가. nodemailer(이미 설치), imapflow(이미 설치), TipTap v2(신규 설치) 기반.
현재 동작
- 계정 목록 조회
- 메일 스트리밍 목록
- 메일 상세 보기
- 읽음 처리
- 메일 삭제 (백엔드만, UI 버튼 있으나 실제 연동 확인 필요)
변경 후 동작
- 좌측 패널: 폴더 목록 (INBOX, Sent, Trash, Spam 등) + 미읽음 수
- 메일 상세 우측 버튼: 답장 / 전달 / 이동 / 삭제(→Trash)
- 하단 첨부파일 목록 + 다운로드 버튼
- 우상단
작성버튼 → Dialog (TipTap 에디터, to/cc/subject) - 답장/전달 시 원문 인용 자동 삽입
시각적 예시
┌──────────────────────────────────────────────────────────────────┐
│ 메일 관리 (IMAP) [작성] [계정추가] │
├──────────────┬───────────────────┬───────────────────────────────┤
│ [계정목록] │ [검색창] │ 제목: 보안 알림 │
│ │ │ From: Google │
│ Gmail │ ● Google 오후1:51 │ To: yechul@gmail.com │
│ Wace │ 보안 알림 │ Date: 2026-03-27 │
│ │ ● GitHub 오전9:48 │ [답장][전달][이동▼][삭제] │
│ ───────── │ Sudo code │ ───────────────────────────── │
│ [폴더목록] │ │ <HTML 본문> │
│ INBOX (3) │ │ │
│ Sent │ │ 📎 첨부파일 │
│ Trash │ │ file.pdf (120KB) [다운로드] │
│ Spam │ │ │
└──────────────┴───────────────────┴───────────────────────────────┘
아키텍처
graph TD
FE[page.tsx] -->|GET /folders| BE_CTRL[userMailController]
FE -->|POST /send| BE_CTRL
FE -->|POST /move| BE_CTRL
FE -->|GET /attachment| BE_CTRL
BE_CTRL --> IMAP[userMailImapService]
BE_CTRL --> SMTP[userMailSmtpService - 신규]
IMAP --> Pool[imapConnectionPool]
SMTP --> Nodemailer[nodemailer]
변경 파일
신규
backend-node/src/services/userMailSmtpService.ts— SMTP 발송 전용
수정
backend-node/src/services/userMailImapService.ts— 폴더목록, 이동, 첨부파일 추가backend-node/src/controllers/userMailController.ts— 신규 엔드포인트 핸들러backend-node/src/routes/userMailRoutes.ts— 신규 라우트 등록frontend/lib/api/userMail.ts— 신규 API 함수frontend/app/(main)/mail/imap/page.tsx— UI 전면 확장
신규 API 엔드포인트
| Method | Path | 설명 |
|---|---|---|
| GET | /user-mail/accounts/:id/folders |
폴더 목록 + 미읽음 수 |
| GET | /user-mail/accounts/:id/folders/:folder/mails/stream |
폴더별 메일 스트리밍 |
| POST | /user-mail/accounts/:id/mails/:seqno/move |
메일 이동 { targetFolder } |
| GET | /user-mail/accounts/:id/mails/:seqno/attachment/:partId |
첨부파일 다운로드 (스트리밍) |
| POST | /user-mail/accounts/:id/send |
메일 발송 { to, cc, subject, html, text, inReplyTo?, references? } |
코드 설계
userMailSmtpService.ts
// SMTP 포트 추론: useTls true → 465, false → 587
// Gmail: smtp.gmail.com, wace.me: mail.wace.me 또는 host 에서 도메인 추출
// nodemailer createTransport + sendMail
// 답장: inReplyTo, references 헤더 설정
userMailImapService.ts 추가 메서드
listFolders(account): Promise<{ path, name, unseen }[]> // client.list({ statusQuery })
moveMail(account, seqno, targetFolder): Promise<Result> // messageMove
downloadAttachment(account, seqno, partId, res): Promise<void> // download() + pipeline(res)
page.tsx 추가 UI
foldersstate: 폴더 목록currentFolderstate: 현재 폴더 (기본 INBOX)ComposeDialog: TipTap 에디터 + to/cc/subject 필드composeMode: 'new' | 'reply' | 'forward'- 메일 상세 버튼: 답장, 전달, 이동(DropdownMenu), 삭제
예상 문제
- Gmail SMTP 포트: Gmail은 587(STARTTLS) 또는 465(SSL). host에서 자동 추론.
- 폴더명 인코딩: 한글 폴더 등 UTF-7/UTF-8 혼용 → imapflow가 자동 처리
- 첨부파일 partId: bodyStructure 파싱이 복잡 →
client.download(seqno, partId)직접 사용 - TipTap SSR: Next.js에서 dynamic import 필요 (
ssr: false)
설계 원칙
- SMTP 서비스는 IMAP 서비스와 완전 분리 (파일 분리)
- 첨부파일은 서버에 저장하지 않고 스트리밍으로 직접 응답
- 답장/전달 인용:
<blockquote>+ RFC 2822 헤더 표준 준수 - TipTap은 dynamic import로 SSR 방지