Files
gochat/internal/service/contact_export_mailer.go
T

113 lines
3.2 KiB
Go

package service
import (
"context"
"fmt"
"net/mail"
"net/smtp"
"os"
"strconv"
"strings"
"github.com/gochat/gochat/internal/model"
)
const contactExportCompleteSubject = "Your contact's export file is available to download."
// ContactExportMailer delivers the administrator notification emitted by
// Chatwoot's Account::ContactsExportJob after the CSV artifact is attached.
type ContactExportMailer interface {
SendContactExportComplete(ctx context.Context, account *model.Account, user *model.User, export *model.ContactExport) error
}
type SMTPContactExportMailer struct {
Address string
Port int
Username string
Password string
From string
FrontendURL string
}
func NewEnvContactExportMailer() *SMTPContactExportMailer {
return &SMTPContactExportMailer{
Address: strings.TrimSpace(os.Getenv("SMTP_ADDRESS")),
Port: envInt("SMTP_PORT", 587),
Username: firstEnv("SMTP_USERNAME", "SMTP_LOGIN"),
Password: os.Getenv("SMTP_PASSWORD"),
From: firstEnv("MAILER_SENDER_EMAIL", "SMTP_FROM"),
FrontendURL: strings.TrimRight(os.Getenv("FRONTEND_URL"), "/"),
}
}
func (m *SMTPContactExportMailer) SendContactExportComplete(ctx context.Context, account *model.Account, user *model.User, export *model.ContactExport) error {
_ = ctx
if m == nil || strings.TrimSpace(m.Address) == "" || user == nil || strings.TrimSpace(user.Email) == "" || export == nil {
return nil
}
fromHeader := strings.TrimSpace(m.From)
if fromHeader == "" {
fromHeader = "Chatwoot <accounts@chatwoot.com>"
}
fromAddress := fromHeader
if parsed, err := mail.ParseAddress(fromHeader); err == nil {
fromAddress = parsed.Address
}
to := strings.TrimSpace(user.Email)
body := contactExportEmailBody(account, export, m.FrontendURL)
message := smtpMessage(fromHeader, to, contactExportCompleteSubject, body)
addr := fmt.Sprintf("%s:%d", strings.TrimSpace(m.Address), m.Port)
var auth smtp.Auth
if strings.TrimSpace(m.Username) != "" {
auth = smtp.PlainAuth("", strings.TrimSpace(m.Username), m.Password, strings.TrimSpace(m.Address))
}
return smtp.SendMail(addr, auth, fromAddress, []string{to}, []byte(message))
}
func contactExportEmailBody(account *model.Account, export *model.ContactExport, frontendURL string) string {
accountName := "your account"
if account != nil && strings.TrimSpace(account.Name) != "" {
accountName = account.Name
}
fileURL := export.FileURL
if frontendURL != "" && strings.HasPrefix(fileURL, "/") {
fileURL = frontendURL + fileURL
}
return fmt.Sprintf("The contact export for %s is ready.\n\nDownload: %s\n", accountName, fileURL)
}
func smtpMessage(from, to, subject, body string) string {
return strings.Join([]string{
"From: " + from,
"To: " + to,
"Subject: " + subject,
"MIME-Version: 1.0",
"Content-Type: text/plain; charset=UTF-8",
"",
body,
}, "\r\n")
}
func firstEnv(keys ...string) string {
for _, key := range keys {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
return value
}
}
return ""
}
func envInt(key string, fallback int) int {
value := strings.TrimSpace(os.Getenv(key))
if value == "" {
return fallback
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed <= 0 {
return fallback
}
return parsed
}