필터를 저장할 때 받은편지함에 이미 있는 메일에도 그 필터 하나를 적용한다. 엔진의 Sieve 는 받을 때만
돌고 엔진 검색은 낱말 단위라, 서버가 받은편지함을 읽어 Sieve 와 같은 규칙으로 판정한다.
- 계약 2절 "이미 받은 메일에 적용"(POST /api/mail-filter-runs): 판정 규칙은 실엔진 배달로 맞췄다 —
HTML 은 닫는 p · br 만 줄바꿈, style · script · head · template 은 글째 빼고, 속성이 붙은 태그는
엔진처럼 알아보지 않는다. 머리글은 접힌 줄을 띄어쓰기 하나로, 인코딩된 글은 홀로 선 것만 푼다
- 시작한 때 받은편지함에 있던 메일만 보고(위 경계), 마지막으로 남긴 메일이 빠지면 그 초부터 다시 읽는다.
본문 값은 한 통 1MiB 까지 — 바깥 메일 한 통으로 서버가 메모리를 크게 쓰지 않게
- 부재중 응답에 isActive(엔진에서 우리 규칙이 꺼졌는지), 엔진의 임시 업로드 한도, 바깥 주소 자동 전달은
허용하지 않는다는 정책(2026-10-29 결정)
- 디자인 캔버스 확정본 MailFilterApply · MailFilterApplyStates 와 README "7단계"(구현하며 정한 보완 포함)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
메일 필터(GET·PUT /api/mail-filters)와, 부재중 자동 응답의 저장 자리를 엔진의 Sieve
스크립트 하나로 옮기는 계약을 적는다. 확정한 캔버스 보드(SettingsFilter · MailFilterStates)와
구현하며 정한 보완도 함께 둔다.
- 엔진(Stalwart 0.16.27)은 계정마다 켜진 스크립트가 하나뿐이다. 엔진의 부재중도 스크립트라
따로 두면 하나를 켤 때 다른 하나가 꺼진다. 그래서 한 스크립트에 함께 둔다
- 스팸 막기는 엔진의 분류 표시(X-Spam-Score)로 한다. spamtest 는 점수를 정수로 내린 값이라
10 으로 막으면 5~10점 스팸을 놓친다(실엔진에서 확인)
- 모든 JSON 본문에 모양 한도(배열 1,000 · 값 10,000 · 깊이 32)를 걸고 UTF-8 만 받는다.
DTO 의 개수 한도로는 본문 검증 DoS 를 막지 못했다(리뷰 측정)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 계약 2절 "받는 사람별 결과" — 엔진이 제출 때 거절한 받는 사람(deliveryStatus)을 201 의 rejectedRecipients 로 알리고,
모두 거절이면 보내지 않은 것으로 다룬다(보낸 사본을 지우고 MAIL_010 · MAIL_011). 같은 키 재시도 · 분류 규칙 · 알려진 한계 · 로그
- 부재중 자동 응답 — 켤 때 제목 150 · 내용 600. 엔진이 UTF-8 511 · 2,047바이트로 막아 4단계의 200 · 4,000 은 한글로 저장되지 않았다.
꺼 둔 채로는 4단계 한도까지 받는다(켜진 옛 긴 글도 끌 수 있게)
- 엔진의 받는 쪽 한도는 로그인한 직원의 발송에 걸지 않는다(mail setup)
- 디자인 README — 일부 거절 알림 · MAIL_010 안내 띠 · 부재중 길이
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 계약 2절 "실시간 알림": GET /api/mail-events(SSE) — state(+inboxUnread) · new-mail · ping(upstream) · end 이벤트,
직원마다 엔진 연결 하나 · 연결 5개 · 25초 ping · 토큰 만료 30초 전 end, 새 메일 판단(10분 넘게 앞선 메일 제외) · 5분 안전판,
클라이언트 규칙(브라우저마다 연결 하나 · fetch 로 읽기 · 다시 잇기 · 1분 확인과의 관계 · 바탕화면 알림 조건)
- 엔진 확인 사실(Stalwart 0.16.27): EventSource 는 대리 접근으로 열린다, ping 은 30초보다 짧지 않다, EmailDelivery 는 초안에도 바뀐다,
스트림은 동시 요청 한도에 들지 않는다, 해석 못 하는 sinceState 는 400 notRequest
- 디자인 캔버스 5단계 보드(SettingsNotify · MailRealtime)와 README "5단계" · "5단계 구현하며 정한 보완"
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 계약 1절: PUT /api/auth/password — 지금 비밀번호 틀림은 400 AUTH_005(401 이면 클라이언트가 갱신 · 재시도한다),
로그인과 같은 실패 한도, 바뀌면 이 세션만 남기고 다른 로그인을 끊는다(결과를 모를 때도)
- 계약 2절: 메일함 관리(만들기 · 이름 바꾸기 · 지우기 · 모두 읽음 · 비우기 — 500통씩 · 한 요청 25초, 같은 메일함은 하나씩),
부재중 자동 응답(JMAP VacationResponse), 스팸 표시(isJunk) · 원문(.eml)
- 디자인 캔버스 4단계 보드(SettingsAccount · SettingsVacation · MailboxManage · MailActions4)와 README "4단계" · "4단계 구현하며 정한 보완"
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
캔버스 버전 21 로 확정한 3단계 화면(Search · BulkSelect · ListStates)과 계약 2절의 새 절(새 메일 확인 · 검색 · 여러 통 한꺼번에).
개발 엔진(Stalwart 0.16.27)에서 직접 확인한 검색 한계 — 낱말이 통째로 같을 때만 맞고 제목 맨 앞 말머리는 색인 밖이다 — 와
그 보완(조사 붙인 형태를 함께 찾기), 휴지통 전용 영구 삭제의 조건(ifInState)을 함께 적었다.
웹 화면은 DELETE /api/messages/{id} 를 쓰지 않는다 — 다른 창이 휴지통에 넣은 메일을 확인 없이 영구 삭제하지 않게.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
캔버스 19 에서 확정한 2단계 화면(Settings · ComposeAssist)을 저장소에 두고,
계약 2절에 임시 저장 · 서명 · 받는 사람 추천 절과 서식 본문의 서명 그림 예외를 더한다.
구현과 리뷰에서 정한 것도 함께 적는다:
- 엔진의 destroy 는 되돌릴 수 없어, 사용자 메일을 지우는 경로는 확인한 상태 그대로일 때만(ifInState) 지운다
- 본문에 그림으로 보인 부분은 첨부 목록·클립에서 뺀다(isInline · hasAttachment) — 서명 그림이 매번 첨부로 보이지 않게
- 서명 그림 한도(서명 3장 · 보관 10장 · 300KB · 4096px), 사내 추천은 최근 90일 로그인
- 저장하지 않는 경우(찾지 못한 첨부 · 본문 한도 초과)와 남의 저장본 원본 보존, 알려진 한계
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 계약 2절: MAIL_007 과 그 경우들, MessageDetail 의 isHtmlBodyOmitted·isBodyTruncated, 보여 줄 본문 규칙,
보내는 서식 본문의 보이지 않는 서식 하한(8px·알파 0.3 — 바탕과 같은 색은 막지 않는다)
- 디자인: 나가기 전 확인(문구·단추·묻지 않는 경우·보내는 중·알려진 한계), 읽기 화면 본문 안내,
내 메일 답장의 받는 사람, 인용할 원문 고르기, 본문 길이 띠의 MAIL_007 문구
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 계약 2절: 서식 본문(bodyHtml)의 허용 목록·값 형식·한도(VAL_001)·지문, 읽기 한도와 정화 전 검사(htmlBody null),
답장·전달 초안 길이 맞춤, 발송 JSON 4MB, 서식 본문 지문의 알려진 한계
- 디자인: 쓰기 화면 입력칸 포커스 규칙, 편집기 툴바·메뉴·단축키·좁은 폭 순서·팔레트, 원문 인용, 본문 이미지 → 첨부
(캔버스 Compose·ComposeEditor 보드와 구현하며 정한 것)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
사용자가 확정한 디자인 캔버스(버전 11)의 원본이다. 화면 구현의 기준으로 쓴다.
- 로그인·메일함(분할·목록 보기)·읽기·쓰기·상태 화면의 캔버스 원본과 자산 대응표
- 디자인 원칙(뱃지 없음·높은 밀도·콘텐츠 열 규칙·밀도 예외)과 구현하며 정한 보완
- 흰 로고 원본 (어두운 브랜드 바탕 전용)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>