feat: SMTP salida propio en webhook de soporte

This commit is contained in:
Lizandro Guarnizo
2026-07-30 12:19:56 -05:00
parent 333fe03de0
commit 03b18418eb
5 changed files with 203 additions and 10 deletions
+84 -2
View File
@@ -1,13 +1,95 @@
package services
import (
"crypto/tls"
"fmt"
"log"
"net/smtp"
"strings"
"github.com/sujit-baniya/fiber-boilerplate/app"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)
// soporteSendMail envía un correo usando la configuración SMTP del webhook de soporte.
// Si no hay SMTP configurado, usa app.Http.Mail como fallback.
func soporteSendMail(to, subject, htmlBody string) error {
cfg, err := models.GetSoporteWebhookActivo()
if err != nil || cfg == nil || cfg.SmtpHost == "" {
return app.Http.Mail.Send(to, subject, htmlBody)
}
from := cfg.SmtpFromAddr
if from == "" {
from = cfg.EmailDestino
}
if from == "" {
return app.Http.Mail.Send(to, subject, htmlBody)
}
fromName := cfg.SmtpFromName
if fromName == "" {
fromName = "Soporte"
}
port := cfg.SmtpPort
if port == 0 {
port = 587
}
auth := smtp.PlainAuth("", cfg.SmtpUsername, cfg.SmtpPassword, cfg.SmtpHost)
msg := []byte(fmt.Sprintf("From: %s <%s>\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s", fromName, from, to, subject, htmlBody))
addr := fmt.Sprintf("%s:%d", cfg.SmtpHost, port)
enc := strings.ToLower(cfg.SmtpEncryption)
if enc == "tls" {
tlsCfg := &tls.Config{ServerName: cfg.SmtpHost}
conn, err := tls.Dial("tcp", addr, tlsCfg)
if err != nil {
return fmt.Errorf("soporte SMTP TLS: %w", err)
}
client, err := smtp.NewClient(conn, cfg.SmtpHost)
if err != nil {
conn.Close()
return fmt.Errorf("soporte SMTP client: %w", err)
}
defer client.Close()
if err = client.Auth(auth); err != nil {
return fmt.Errorf("soporte SMTP auth: %w", err)
}
if err = client.Mail(from); err != nil {
return err
}
if err = client.Rcpt(to); err != nil {
return err
}
w, err := client.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
return w.Close()
}
if enc == "starttls" {
tlsCfg := &tls.Config{ServerName: cfg.SmtpHost}
conn, err := smtp.Dial(addr)
if err != nil {
goto fallback
}
if err = conn.StartTLS(tlsCfg); err != nil {
conn.Close()
goto fallback
}
if err = conn.Auth(auth); err != nil {
conn.Close()
return fmt.Errorf("soporte SMTP STARTTLS auth: %w", err)
}
return smtp.SendMail(addr, auth, from, []string{to}, msg)
}
return smtp.SendMail(addr, auth, from, []string{to}, msg)
fallback:
return app.Http.Mail.Send(to, subject, htmlBody)
}
// SendSoporteAutoRespuesta envía acuse de recibo automático al crear un ticket por email
func SendSoporteAutoRespuesta(ticket *models.ProyectoTicket) {
if ticket == nil || ticket.EmailFrom == "" {
@@ -39,7 +121,7 @@ func SendSoporteAutoRespuesta(ticket *models.ProyectoTicket) {
</div></body></html>`, ticket.AutorNombre, mensaje, ticket.ID, ticket.Titulo, ticket.Descripcion)
go func() {
if err := app.Http.Mail.Send(ticket.EmailFrom, subject, htmlBody); err != nil {
if err := soporteSendMail(ticket.EmailFrom, subject, htmlBody); err != nil {
log.Printf("[Soporte] Error enviando auto-respuesta a %s: %v", ticket.EmailFrom, err)
} else {
log.Printf("[Soporte] Auto-respuesta enviada a %s (ticket #%d)", ticket.EmailFrom, ticket.ID)
@@ -78,7 +160,7 @@ func SendSoporteNotifAdmin(ticket *models.ProyectoTicket) {
</div></body></html>`, ticket.AutorNombre, ticket.EmailFrom, ticket.Titulo, ticket.Descripcion, absAppURL(""), ticket.ID)
go func() {
if err := app.Http.Mail.Send(adminEmail, subject, htmlBody); err != nil {
if err := soporteSendMail(adminEmail, subject, htmlBody); err != nil {
log.Printf("[Soporte] Error notificando admin: %v", err)
}
}()