package wmail import ( "context" "time" "github.com/google/uuid" "github.com/warmbly/warmbly/internal/client/goog" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/models" ) // SendRequest contains all parameters needed to send an email type SendRequest struct { TaskID uuid.UUID To []string Cc []string Bcc []string MessageID string Subject string BodyPlain string BodyHTML string InReplyTo string Parent *models.EmailParent IsWarmup bool WarmupToken string } // SendResult contains the result of a send operation type SendResult struct { Success bool MessageID string ProviderMsgID string SentAt time.Time Error *errx.MailError } const maxSendRetries = 3 // Send attempts to send an email with retry for transient failures func (w *WMail) Send(ctx context.Context, req *SendRequest) *SendResult { // For warmup emails, ensure HTML is empty bodyHTML := req.BodyHTML if req.IsWarmup { bodyHTML = "" } var result *SendResult for attempt := 0; attempt <= maxSendRetries; attempt++ { result = &SendResult{Success: false, SentAt: time.Now()} switch w.EmailType { case models.InboxProviderGoogle: result = w.sendViaGmail(ctx, req, bodyHTML) case models.InboxProviderOutlook, models.InboxProviderSMTPIMAP: result = w.sendViaSMTP(ctx, req, bodyHTML) default: result.Error = errx.MError( errx.MailErrorCritical, errx.MailErrorCodeUnsupported, "Unsupported email provider", errx.MailErrorResolveMethodNone, ) return result } if result.Success { return result } // Don't retry critical/auth errors - only transient ones if result.Error != nil && result.Error.Type == errx.MailErrorCritical { return result } if attempt < maxSendRetries { backoff := time.Duration(1<