package email import ( "fmt" "net/mail" "strings" "time" ) type ComposeRequest struct { MessageID string FromAddress string FromName string ToAddresses string CcAddresses string Subject string HTMLBody string } func Compose(request ComposeRequest) []byte { var message strings.Builder fromHeader := formatMailAddress(request.FromName, request.FromAddress) message.WriteString(fmt.Sprintf("From: %s\r\n", fromHeader)) message.WriteString(fmt.Sprintf("To: %s\r\n", request.ToAddresses)) if request.CcAddresses != "" { message.WriteString(fmt.Sprintf("Cc: %s\r\n", request.CcAddresses)) } message.WriteString(fmt.Sprintf("Subject: %s\r\n", request.Subject)) message.WriteString(fmt.Sprintf("Date: %s\r\n", time.Now().Format(time.RFC1123Z))) message.WriteString(fmt.Sprintf("Message-ID: %s\r\n", request.MessageID)) message.WriteString("MIME-Version: 1.0\r\n") message.WriteString("Content-Type: text/html; charset=UTF-8\r\n") message.WriteString("\r\n") message.WriteString(request.HTMLBody) return []byte(message.String()) } func EnvelopeRecipients(toAddresses string, ccAddresses string, bccAddresses string) []string { var recipients []string for _, addressGroup := range []string{toAddresses, ccAddresses, bccAddresses} { if addressGroup == "" { continue } parsed, parseError := mail.ParseAddressList(addressGroup) if parseError != nil { for _, raw := range strings.Split(addressGroup, AddressJoiner) { trimmed := strings.TrimSpace(raw) if trimmed != "" { recipients = append(recipients, trimmed) } } continue } for _, address := range parsed { recipients = append(recipients, address.Address) } } return recipients } func formatMailAddress(displayName string, emailAddress string) string { if displayName == "" { return emailAddress } return fmt.Sprintf("\"%s\" <%s>", displayName, emailAddress) }