2018-08-21 17:21:46 +00:00
|
|
|
package main
|
|
|
|
|
2018-08-22 16:57:50 +00:00
|
|
|
// TODO: use https://github.com/domodwyer/mailyak as a base lib
|
|
|
|
|
2018-08-21 17:21:46 +00:00
|
|
|
import (
|
2018-08-22 10:29:14 +00:00
|
|
|
"bytes"
|
2018-08-22 16:57:50 +00:00
|
|
|
"encoding/base64"
|
2018-09-11 15:17:30 +00:00
|
|
|
"errors"
|
2018-08-22 10:29:14 +00:00
|
|
|
"fmt"
|
2018-08-22 16:57:50 +00:00
|
|
|
// "github.com/davecgh/go-spew/spew"
|
2018-09-11 15:17:30 +00:00
|
|
|
"log"
|
2018-08-22 12:01:44 +00:00
|
|
|
"strings"
|
2018-08-22 10:29:14 +00:00
|
|
|
// "strconv"
|
2018-08-22 16:57:50 +00:00
|
|
|
"math/rand"
|
2018-08-22 10:29:14 +00:00
|
|
|
"net/mail"
|
2018-08-21 17:21:46 +00:00
|
|
|
)
|
|
|
|
|
2018-08-22 10:29:14 +00:00
|
|
|
type EmailHeaders map[string]string
|
2018-08-21 17:21:46 +00:00
|
|
|
|
|
|
|
type EmailCtx struct {
|
2018-08-22 16:57:50 +00:00
|
|
|
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)
|
2018-08-22 10:29:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2018-08-21 17:21:46 +00:00
|
|
|
func NewEmail() *EmailCtx {
|
2018-08-22 10:29:14 +00:00
|
|
|
email := EmailCtx{}
|
|
|
|
email.Headers = make(EmailHeaders)
|
|
|
|
return &email
|
2018-08-21 17:21:46 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 10:29:14 +00:00
|
|
|
func encodeRFC2047(text string) string {
|
|
|
|
// use mail's rfc2047 to encode any string
|
2018-09-11 15:17:30 +00:00
|
|
|
addr := mail.Address{Name: text, Address: ""}
|
2018-08-22 10:29:14 +00:00
|
|
|
return strings.Trim(addr.String(), " \"<@>")
|
|
|
|
}
|
|
|
|
|
2018-08-22 16:57:50 +00:00
|
|
|
func (email *EmailCtx) SetHeaders(config EmailConfig) {
|
2018-08-22 10:29:14 +00:00
|
|
|
email.Headers["Return-Path"] = config.From
|
2018-08-21 17:21:46 +00:00
|
|
|
email.Headers["From"] = config.From
|
2018-09-11 15:17:30 +00:00
|
|
|
fmt.Printf("config.To %#v\n", config.To)
|
|
|
|
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:], ",")
|
|
|
|
}
|
2018-08-22 10:29:14 +00:00
|
|
|
email.Headers["Subject"] = encodeRFC2047(config.Subject)
|
2018-08-22 16:57:50 +00:00
|
|
|
email.Headers["Content-Transfer-Encoding"] = "quoted-printable"
|
2018-08-22 10:29:14 +00:00
|
|
|
email.Headers["MIME-Version"] = "1.0"
|
2018-08-21 17:21:46 +00:00
|
|
|
|
2018-08-22 10:29:14 +00:00
|
|
|
return
|
2018-08-21 17:21:46 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 16:57:50 +00:00
|
|
|
func (email *EmailCtx) SetBody(html string, plain string) {
|
|
|
|
email.BodyPlain = plain
|
|
|
|
email.BodyHtml = html
|
2018-08-22 10:29:14 +00:00
|
|
|
return
|
2018-08-21 17:21:46 +00:00
|
|
|
}
|
2018-08-22 16:57:50 +00:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|