package api import ( "encoding/json" "net/http" "archivmail/config" "archivmail/internal/audit" "archivmail/internal/smtpoutconfig" ) // handleGetSMTPOut returns the current SMTP-Out relay config (password masked). // GET /api/admin/smtp-out — superadmin only. func (s *Server) handleGetSMTPOut(w http.ResponseWriter, r *http.Request) { cfg, err := s.smtpOutStore.Get(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } if cfg == nil { writeJSON(w, http.StatusOK, map[string]interface{}{"configured": false}) return } writeJSON(w, http.StatusOK, map[string]interface{}{"configured": true, "config": cfg}) } // handleSaveSMTPOut upserts the SMTP-Out relay config and reloads the mailer. // PUT /api/admin/smtp-out — superadmin only. func (s *Server) handleSaveSMTPOut(w http.ResponseWriter, r *http.Request) { var body smtpoutconfig.SMTPOutConfig if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, http.StatusBadRequest, "invalid body") return } if body.Port == 0 { body.Port = 587 } sess := sessionFromCtx(r.Context()) if err := s.smtpOutStore.Save(r.Context(), body, sess.Username); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } // Reload the mailer at runtime — no restart needed if full, err := s.smtpOutStore.GetWithPassword(r.Context()); err == nil && full != nil { s.mailer.Reload(config.SMTPOutConfig{ Host: full.Host, Port: full.Port, User: full.User, Password: full.Password, TLS: full.TLS, From: full.From, }) } if s.audlog != nil { s.audlog.Log(audit.Entry{ EventType: "smtp_out_config_saved", Username: sess.Username, IPAddress: s.remoteIP(r), Success: true, }) } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) } // handleDeleteSMTPOut removes the SMTP-Out config and disables the mailer. // DELETE /api/admin/smtp-out — superadmin only. func (s *Server) handleDeleteSMTPOut(w http.ResponseWriter, r *http.Request) { if err := s.smtpOutStore.Delete(r.Context()); err != nil { writeError(w, http.StatusInternalServerError, err.Error()) return } // Disable mailer s.mailer.Reload(config.SMTPOutConfig{}) sess := sessionFromCtx(r.Context()) if s.audlog != nil { s.audlog.Log(audit.Entry{ EventType: "smtp_out_config_deleted", Username: sess.Username, IPAddress: s.remoteIP(r), Success: true, }) } writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true}) } // handleTestSMTPOut sends a test email to the logged-in admin. // POST /api/admin/smtp-out/test — superadmin only. func (s *Server) handleTestSMTPOut(w http.ResponseWriter, r *http.Request) { if !s.mailer.IsConfigured() { writeError(w, http.StatusServiceUnavailable, "SMTP-Out nicht konfiguriert") return } sess := sessionFromCtx(r.Context()) u, err := s.users.GetByUsername(sess.Username) if err != nil || u.Email == "" { writeError(w, http.StatusBadRequest, "Keine E-Mail-Adresse für diesen Account") return } html := `

Dies ist eine Test-E-Mail von archivmail.
Der SMTP-Relay ist korrekt konfiguriert.

` txt := "Dies ist eine Test-E-Mail von archivmail. Der SMTP-Relay ist korrekt konfiguriert." if err := s.mailer.Send(u.Email, "archivmail – SMTP-Test", html, txt); err != nil { writeError(w, http.StatusBadGateway, "Versand fehlgeschlagen: "+err.Error()) return } writeJSON(w, http.StatusOK, map[string]interface{}{ "ok": true, "sent_to": u.Email, }) }