package email import ( "fmt" "github.com/tuusuario/go-sync-service/internal/config" "github.com/tuusuario/go-sync-service/internal/domain/ports" "log" "time" "github.com/go-playground/validator/v10" "gopkg.in/gomail.v2" ) // EmailService define la interfaz para el envío de correos type EmailService interface { SendEmail(email EmailRequest) error } // SMTPEmailService implementa EmailService con SMTP type SMTPEmailService struct { Config *config.Config Validator *validator.Validate } // NewSMTPEmailService retorna una nueva instancia del servicio de email con validación func NewSMTPEmailService(cfg *config.Config) *SMTPEmailService { return &SMTPEmailService{ Config: cfg, Validator: validator.New(), // Inicializa el validador } } // EmailRequest estructura para la validación del email type EmailRequest struct { To string `json:"correoElectronico" validate:"required,email"` Subject string `json:"asunto" validate:"required,min=3,max=100"` Body string `json:"cuerpo" validate:"required"` } // SendEmail valida y envía un correo electrónico usando SMTP func (s *SMTPEmailService) SendEmail(email EmailRequest) error { // Validar la estructura antes de enviarla /* err := s.Validator.Struct(email) if err != nil { for _, err := range err.(validator.ValidationErrors) { log.Printf("❌ Error de validación en %s: %s", err.Field(), err.Tag()) } return fmt.Errorf("❌ Error en la validación del email: %v", err) } */ smtpHost := s.Config.EmailHost smtpPort := s.Config.EmailPort smtpUser := s.Config.EmailUser smtpPass := s.Config.EmailPassword emailFrom := s.Config.EmailFrom if smtpHost == "" || smtpUser == "" || smtpPass == "" || emailFrom == "" || smtpPort == 0 { log.Println("❌ ERROR: Faltan variables de entorno para SMTP") return fmt.Errorf("faltan variables de entorno para el envío de correos") } log.Printf("📧 Enviando correo desde: %s", emailFrom) mail := gomail.NewMessage() mail.SetHeader("From", emailFrom) mail.SetHeader("To", email.To) mail.SetHeader("Subject", email.Subject) mail.SetBody("text/html", email.Body) dialer := gomail.NewDialer(smtpHost, smtpPort, smtpUser, smtpPass) err := dialer.DialAndSend(mail) if err != nil { log.Printf("❌ Error enviando correo a %s: %s", email.To, err) return err } log.Printf("✅ Correo enviado con éxito a %s", email.To) return nil } func (s *SMTPEmailService) PrepareEmail(asunto string, mensaje string, cfg ports.RedisConfigProvider) error { // Validar la estructura antes de enviarla branding := LoadBrandingAsignation(cfg, s.Config.AppName) // Cargar destinatarios del entorno destinos := s.LoadDestinosCorreo(cfg) // Cargar datos para la plantilla data := TaskTplData{ AppName: branding.AppName, Nombre: "Administrador", TareaNombre: asunto, // Ejemplo Descripcion: mensaje, // Ejemplo FechaError: time.Now().Format("02/01/2006 15:04"), // Ejemplo ErrorDescripcion: mensaje, LinkTarea: "", LogoURL: branding.LogoURL, Direccion: branding.Direccion, Telefono: branding.Telefono, EmailContacto: branding.EmailContacto, Year: branding.Year, ColorHeaderBG: branding.ColorHeaderBG, ColorAccent: branding.ColorAccent, ColorFooterText: branding.ColorFooterText, ColorFooterMuted: branding.ColorFooterMuted, ColorBodyBG: branding.ColorBodyBG, } // Renderizar el correo body, err := RenderTaskEmailHTML("", data) if err != nil { return fmt.Errorf("error al renderizar la plantilla de tarea: %v", err) } // Crear el correo subject := BuildTaskSubject(branding.AppName) reqMail := EmailRequest{ To: *destinos, // Usamos la lista de destinos cargada Subject: subject, Body: body, } // Enviar el correo if err := s.SendEmail(reqMail); err != nil { return fmt.Errorf("error al enviar el correo de notificación de tarea: %v", err) } return nil } // Cargar los correos electrónicos desde la configuración func (s *SMTPEmailService) LoadDestinosCorreo(cfg ports.RedisConfigProvider) *string { destinos, err := cfg.GetString("SYNCRONIZADOR_EMAIL_DESTINOS") // Asumiendo que usas RedisConfigProvider if err != nil { log.Printf(" ERROR no se pudo cargar la lista de destinatarios: %v", err) destinos = s.Config.EmailAdmin } return &destinos }