service.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package smtp
  2. import (
  3. "bytes"
  4. "embed"
  5. "fmt"
  6. "html/template"
  7. "net/smtp"
  8. "git.linuxforward.com/byom/byom-core/config"
  9. "github.com/sirupsen/logrus"
  10. )
  11. // EmailService defines the interface for email operations
  12. type EmailService interface {
  13. SendInviteEmail(to, token, workspace string) error
  14. Close() error
  15. }
  16. type Service struct {
  17. client *smtp.Client
  18. template *template.Template
  19. logger *logrus.Entry
  20. }
  21. //go:embed templates/invite.html
  22. var inviteTpl embed.FS
  23. type EmailData struct {
  24. Token string
  25. WorkspaceName string
  26. URL string
  27. }
  28. func NewService(cnf *config.Smtp) *Service {
  29. logger := logrus.WithField("core", "email")
  30. // If SMTP is not configured, return service with nil client
  31. if cnf == nil || cnf.Host == "" {
  32. logger.Info("SMTP not configured, email service will be disabled")
  33. return &Service{
  34. logger: logger,
  35. }
  36. }
  37. // Parse the email template
  38. tmpl, err := template.ParseFS(inviteTpl, "templates/invite.html")
  39. if err != nil {
  40. logger.WithError(err).Error("failed to parse email template")
  41. panic(err)
  42. }
  43. // Create SMTP client
  44. addr := fmt.Sprintf("%s:%d", cnf.Host, cnf.Port)
  45. client, err := smtp.Dial(addr)
  46. if err != nil {
  47. logger.WithError(err).Error("failed to connect to SMTP server")
  48. return &Service{
  49. logger: logger,
  50. template: tmpl,
  51. }
  52. }
  53. return &Service{
  54. logger: logger,
  55. client: client,
  56. template: tmpl,
  57. }
  58. }
  59. func (s *Service) SendEmail(to, subject, body string) error {
  60. s.logger.WithField("to", to).WithField("subject", subject).Info("sending email")
  61. //since we are not actually sending emails, we will just log the email
  62. s.logger.WithField("body", body).Info("email body")
  63. return nil
  64. }
  65. func (s *Service) SendInviteEmail(to, token, workspace string) error {
  66. var body bytes.Buffer
  67. data := EmailData{
  68. Token: token,
  69. WorkspaceName: workspace,
  70. URL: fmt.Sprintf("https://%s.domain.com/invite/%s", workspace, token),
  71. }
  72. if err := s.template.Execute(&body, data); err != nil {
  73. return fmt.Errorf("template execution failed: %w", err)
  74. }
  75. return s.SendEmail(to, "Join "+workspace+" workspace", body.String())
  76. }
  77. func (s *Service) Close() error {
  78. if s.client != nil {
  79. err := s.client.Close()
  80. if err != nil {
  81. s.logger.WithError(err).Error("failed to close SMTP client")
  82. return fmt.Errorf("close SMTP client: %w", err)
  83. }
  84. s.logger.Info("SMTP client closed successfully")
  85. }
  86. s.template = nil
  87. return nil
  88. }