feat(PROJ-26): IMAP-Archive-Server Read-Only Zugriff auf archivierte Mails

- Neues Package internal/imapserver: vollständiger IMAP4rev1-Server (~700 Zeilen)
- Auth via bcrypt (userstore.VerifyPassword), Multi-Tenant-Isolation
- INBOX + INBOX/LabelName Ordnerstruktur
- FETCH mit BODY[], ENVELOPE, RFC822.SIZE, INTERNALDATE, FLAGS, UID
- SEARCH: ALL, FROM, TO, SUBJECT, SINCE, BEFORE + UID FETCH/SEARCH
- Read-Only: STORE, DELETE, COPY, MOVE, APPEND → NO [CANNOT]
- \Seen-Flag nicht persistent (GoBD-konform)
- Max 5 gleichzeitige Verbindungen pro User, 30min Idle-Timeout
- Audit-Log: imap_login / imap_login_failed Events
- Config: imap_server.enabled + imap_server.bind (default: 127.0.0.1:1143)
- Externe Ports: 9993 (primär) und 993 (alternativ) via nginx TLS-Terminierung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-03-18 11:42:35 +01:00
parent 5c25e3a7e7
commit 19a55a3166
5 changed files with 1324 additions and 13 deletions
+16
View File
@@ -23,6 +23,7 @@ import (
"github.com/archivmail/internal/audit"
"github.com/archivmail/internal/auth"
imapstore "github.com/archivmail/internal/imap"
"github.com/archivmail/internal/imapserver"
"github.com/archivmail/internal/index"
"github.com/archivmail/internal/labelstore"
ldapcfg "github.com/archivmail/internal/ldapconfig"
@@ -201,6 +202,21 @@ func main() {
defer labelSt.Close()
srv.SetLabels(labelSt)
// PROJ-26: IMAP Archive Server (read-only access for IMAP clients)
if cfg.IMAPServer.Enabled {
imapSrv := imapserver.New(cfg.IMAPServer, mailStore, users, labelSt, audlog, authMgr, logger)
if err := imapSrv.Start(); err != nil {
logger.Error("IMAP server failed to start", "err", err)
os.Exit(1)
}
defer imapSrv.Stop()
imapBind := cfg.IMAPServer.Bind
if imapBind == "" {
imapBind = "127.0.0.1:1143"
}
logger.Info("IMAP archive server started", "addr", imapBind)
}
// Start SMTP daemon with index worker integration
if cfg.SMTP.Bind == "" {
cfg.SMTP.Bind = fmt.Sprintf(":%d", cfg.Server.SMTPPort)