package smtp import ( "bytes" "html/template" "strings" "github.com/sirupsen/logrus" "github.com/wneessen/go-mail" "git.linuxforward.com/byom/byom-golang-lib/pkg/errors" ) // SMTPConfig holds the configuration for the SMTP service type SMTPConfig struct { Host string Port int Username string Password string From string } // EmailData holds the data for the default email template type EmailData struct { Subject string Body string } // VerificationData holds the data for the verification email template type VerificationData struct { VerificationURL string } // WelcomeData holds the data for the welcome email template type WelcomeData struct { Username string Password string WebAppURL string } // SMTPService handles email sending operations type SMTPService struct { client *mail.Client logger *logrus.Logger from string } // NewSMTPService creates a new SMTP service instance func NewSMTPService(config SMTPConfig, logger *logrus.Logger) (*SMTPService, error) { if logger == nil { return nil, errors.NewSMTPError("initialization", errors.ErrInvalidInput) } // Validate config if config.Host == "" || config.Port == 0 || config.Username == "" || config.Password == "" || config.From == "" { return nil, errors.NewSMTPError("initialization", errors.ErrInvalidInput) } // Create mail client with proper configuration client, err := mail.NewClient(config.Host, mail.WithPort(config.Port), mail.WithSMTPAuth(mail.SMTPAuthPlain), mail.WithUsername(config.Username), mail.WithPassword(config.Password), mail.WithTLSPolicy(mail.TLSMandatory), // Enforce TLS ) if err != nil { logger.WithError(err).Error("Failed to create SMTP client") return nil, errors.NewSMTPError("client creation", err) } return &SMTPService{ client: client, logger: logger, from: config.From, }, nil } // SendEmail sends a basic email using the default template func (s *SMTPService) SendEmail(to string, data EmailData) error { if strings.TrimSpace(to) == "" { return errors.NewSMTPError("send", errors.ErrInvalidInput) } // Parse and execute template tmpl, err := template.New("email").Parse(defaultTemplate) if err != nil { s.logger.WithError(err).Error("Failed to parse email template") return errors.NewSMTPError("template parsing", err) } var body bytes.Buffer if err := tmpl.Execute(&body, data); err != nil { s.logger.WithError(err).Error("Failed to execute email template") return errors.NewSMTPError("template execution", err) } // Create and configure message msg := mail.NewMsg() if err := msg.From(s.from); err != nil { return errors.NewSMTPError("message creation", err) } if err := msg.To(to); err != nil { return errors.NewSMTPError("message creation", err) } msg.Subject(data.Subject) msg.SetBodyString(mail.TypeTextHTML, body.String()) // Send email if err := s.client.DialAndSend(msg); err != nil { s.logger.WithError(err).Error("Failed to send email") return errors.NewSMTPError("sending", err) } s.logger.WithFields(logrus.Fields{ "to": to, "subject": data.Subject, }).Info("Email sent successfully") return nil } // SendVerificationEmail sends an email verification message func (s *SMTPService) SendVerificationEmail(to string, data VerificationData) error { if strings.TrimSpace(to) == "" || strings.TrimSpace(data.VerificationURL) == "" { return errors.NewSMTPError("send verification", errors.ErrInvalidInput) } // Parse and execute template tmpl, err := template.New("verification").Parse(verificationTemplate) if err != nil { s.logger.WithError(err).Error("Failed to parse verification template") return errors.NewSMTPError("template parsing", err) } var body bytes.Buffer if err := tmpl.Execute(&body, data); err != nil { s.logger.WithError(err).Error("Failed to execute verification template") return errors.NewSMTPError("template execution", err) } // Create and configure message msg := mail.NewMsg() if err := msg.From(s.from); err != nil { return errors.NewSMTPError("message creation", err) } if err := msg.To(to); err != nil { return errors.NewSMTPError("message creation", err) } msg.Subject("Verify Your Email Address") msg.SetBodyString(mail.TypeTextHTML, body.String()) // Send email if err := s.client.DialAndSend(msg); err != nil { s.logger.WithError(err).Error("Failed to send verification email") return errors.NewSMTPError("sending", err) } s.logger.WithFields(logrus.Fields{ "to": to, }).Info("Verification email sent successfully") return nil } // SendWelcomeEmail sends a welcome email with credentials func (s *SMTPService) SendWelcomeEmail(to string, data WelcomeData) error { if strings.TrimSpace(to) == "" || strings.TrimSpace(data.Username) == "" { return errors.NewSMTPError("send welcome", errors.ErrInvalidInput) } // Parse and execute template tmpl, err := template.New("welcome").Parse(welcomeTemplate) if err != nil { s.logger.WithError(err).Error("Failed to parse welcome template") return errors.NewSMTPError("template parsing", err) } var body bytes.Buffer if err := tmpl.Execute(&body, data); err != nil { s.logger.WithError(err).Error("Failed to execute welcome template") return errors.NewSMTPError("template execution", err) } // Create and configure message msg := mail.NewMsg() if err := msg.From(s.from); err != nil { return errors.NewSMTPError("message creation", err) } if err := msg.To(to); err != nil { return errors.NewSMTPError("message creation", err) } msg.Subject("Welcome to Our Platform!") msg.SetBodyString(mail.TypeTextHTML, body.String()) // Send email if err := s.client.DialAndSend(msg); err != nil { s.logger.WithError(err).Error("Failed to send welcome email") return errors.NewSMTPError("sending", err) } s.logger.WithFields(logrus.Fields{ "to": to, "username": data.Username, }).Info("Welcome email sent successfully") return nil } // Close closes the SMTP client connection func (s *SMTPService) Close() error { if s.client != nil { if err := s.client.Close(); err != nil { s.logger.WithError(err).Error("Failed to close SMTP client") return errors.NewSMTPError("close", err) } s.logger.Info("SMTP client closed successfully") } return nil }