feat: add email notification service with SMTP support
Some checks failed
Build and Deploy GooSeek / build-and-deploy (push) Failing after 8m22s

- Create pkg/email package (sender, templates, types)
- SMTP client with TLS, rate limiting, async sending
- HTML email templates with GooSeek branding
- Integrate welcome + password reset emails in auth-svc
- Add limit warning emails (80%/100%) in llm-svc middleware
- Add space invite endpoint with email notification in thread-svc
- Add GetUserEmail helper in JWT middleware
- Add SMTP config to .env, config.go, K8s configmap

Made-with: Cursor
This commit is contained in:
home
2026-03-03 02:50:17 +03:00
parent 7a40ff629e
commit 52134df4d1
12 changed files with 767 additions and 92 deletions

View File

@@ -16,6 +16,7 @@ import (
"github.com/golang-jwt/jwt/v5"
"github.com/gooseek/backend/internal/auth"
"github.com/gooseek/backend/pkg/config"
"github.com/gooseek/backend/pkg/email"
_ "github.com/lib/pq"
)
@@ -73,6 +74,22 @@ func main() {
authRepo := auth.NewRepository(db)
emailSender := email.NewSender(email.SMTPConfig{
Host: cfg.SMTPHost,
Port: cfg.SMTPPort,
User: cfg.SMTPUser,
Password: cfg.SMTPPassword,
From: cfg.SMTPFrom,
TLS: cfg.SMTPTLS,
SiteURL: cfg.SiteURL,
SiteName: cfg.SiteName,
})
if emailSender.IsConfigured() {
log.Println("Email notifications enabled")
} else {
log.Println("Email notifications disabled (SMTP not configured)")
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
if err := authRepo.RunMigrations(ctx); err != nil {
log.Printf("Migration warning: %v", err)
@@ -150,6 +167,10 @@ func main() {
return c.Status(500).JSON(fiber.Map{"error": "Failed to generate tokens"})
}
emailSender.SendAsync(func() error {
return emailSender.SendWelcome(user.Email, user.Name)
})
return c.Status(201).JSON(tokens)
})
@@ -331,7 +352,10 @@ func main() {
if err == nil && user != nil {
token, err := authRepo.CreatePasswordResetToken(c.Context(), user.ID)
if err == nil {
log.Printf("Password reset token for %s: %s", req.Email, token.Token)
resetURL := fmt.Sprintf("%s/reset-password?token=%s", cfg.SiteURL, token.Token)
emailSender.SendAsync(func() error {
return emailSender.SendPasswordReset(user.Email, user.Name, resetURL)
})
}
}