musala/cmd/trello2mail/email.go
2018-11-23 12:41:54 +01:00

121 lines
3.2 KiB
Go

package main
// TODO: use https://github.com/domodwyer/mailyak as a base lib
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"log"
"math/rand"
"net/mail"
"strings"
)
type EmailHeaders map[string]string
type EmailConfig struct {
From string
To []string
Subject string
}
type EmailCtx struct {
Headers EmailHeaders
BodyPlain string
BodyHtml string
}
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
func (headers EmailHeaders) String() string {
var buffer bytes.Buffer
for k, v := range headers {
buffer.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
}
return buffer.String()
}
func NewEmail() *EmailCtx {
email := EmailCtx{}
email.Headers = make(EmailHeaders)
return &email
}
func encodeRFC2047(text string) string {
// use mail's rfc2047 to encode any string
addr := mail.Address{Name: text, Address: ""}
return strings.Trim(addr.String(), " \"<@>")
}
func (email *EmailCtx) SetHeaders(config EmailConfig) {
email.Headers["Return-Path"] = config.From
email.Headers["From"] = config.From
if len(config.To) < 1 {
errmsg := "EMAIL_TO must contain at least one value"
log.Panic(errors.New(errmsg))
}
email.Headers["To"] = config.To[0]
if len(config.To) > 1 {
email.Headers["Cc"] = strings.Join(config.To[1:], ",")
}
email.Headers["Subject"] = encodeRFC2047(config.Subject)
email.Headers["Content-Transfer-Encoding"] = "quoted-printable"
email.Headers["MIME-Version"] = "1.0"
return
}
func (email *EmailCtx) SetBody(html string, plain string) {
email.BodyPlain = plain
email.BodyHtml = html
return
}
func (email *EmailCtx) String() string {
var buffer bytes.Buffer
mixBoundary := RandStringBytes(16)
altBoundary := RandStringBytes(16)
buffer.WriteString(email.Headers.String())
buffer.WriteString(fmt.Sprintf("Content-Type: multipart/mixed;\r\n boundary=\"%s\"\r\n", mixBoundary))
buffer.WriteString("\r\n")
buffer.WriteString(fmt.Sprintf("--%s\r\n", mixBoundary))
buffer.WriteString(fmt.Sprintf("Content-Type: multipart/alternative;\r\n boundary=\"%s\"\r\n", altBoundary))
buffer.WriteString("\r\n")
buffer.WriteString(fmt.Sprintf("--%s\r\n", altBoundary))
buffer.WriteString(fmt.Sprintf("Content-Type: text/plain; charset=\"utf-8\"\r\n"))
buffer.WriteString(fmt.Sprintf("Content-Transfer-Encoding: base64\r\n"))
buffer.WriteString("\r\n")
buffer.WriteString(base64.StdEncoding.EncodeToString([]byte(email.BodyPlain)))
buffer.WriteString("\r\n")
buffer.WriteString("\r\n")
buffer.WriteString(fmt.Sprintf("--%s\r\n", altBoundary))
buffer.WriteString(fmt.Sprintf("Content-Type: text/html; charset=\"utf-8\"\r\n"))
buffer.WriteString(fmt.Sprintf("Content-Transfer-Encoding: base64\r\n"))
buffer.WriteString("\r\n")
buffer.WriteString(base64.StdEncoding.EncodeToString([]byte(email.BodyHtml)))
buffer.WriteString("\r\n")
buffer.WriteString("\r\n")
buffer.WriteString(fmt.Sprintf("--%s--\r\n", altBoundary))
buffer.WriteString("\r\n")
buffer.WriteString(fmt.Sprintf("--%s--\r\n", mixBoundary))
buffer.WriteString("\r\n")
return buffer.String()
}