50 lines
1.9 KiB
Go
50 lines
1.9 KiB
Go
package email
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"mime"
|
|
"mime/multipart"
|
|
"mime/quotedprintable"
|
|
"net/mail"
|
|
"net/textproto"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.sendico.io/tech/sxchnge/notifications/model"
|
|
merrors "git.sendico.io/tech/sxchnge/shared/errors"
|
|
)
|
|
|
|
func smtpMessage(s smtpSettings, key string, email model.Email) ([]byte, error) {
|
|
if !ValidAddress(email.Address) || strings.ContainsAny(email.Subject, "\r\n") || (email.Text == "" && email.HTML == "") {
|
|
return nil, merrors.InvalidArgument("invalid email content")
|
|
}
|
|
var body bytes.Buffer
|
|
parts := multipart.NewWriter(&body)
|
|
for _, part := range []struct{ kind, value string }{{"text/plain", email.Text}, {"text/html", email.HTML}} {
|
|
if part.value == "" {
|
|
continue
|
|
}
|
|
writer, err := parts.CreatePart(textproto.MIMEHeader{"Content-Type": {part.kind + "; charset=utf-8"}, "Content-Transfer-Encoding": {"quoted-printable"}})
|
|
if err != nil {
|
|
return nil, merrors.InternalWrap(err, "create email MIME part")
|
|
}
|
|
encoded := quotedprintable.NewWriter(writer)
|
|
if _, err = encoded.Write([]byte(part.value)); err != nil {
|
|
return nil, merrors.InternalWrap(err, "encode email MIME part")
|
|
}
|
|
if err = encoded.Close(); err != nil {
|
|
return nil, merrors.InternalWrap(err, "finish email MIME part")
|
|
}
|
|
}
|
|
if err := parts.Close(); err != nil {
|
|
return nil, merrors.InternalWrap(err, "finish email MIME body")
|
|
}
|
|
from := (&mail.Address{Name: s.SenderName, Address: s.SenderAddress}).String()
|
|
to := (&mail.Address{Address: email.Address}).String()
|
|
domain := s.SenderAddress[strings.LastIndex(s.SenderAddress, "@")+1:]
|
|
headers := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\nMessage-ID: <%x@%s>\r\nMIME-Version: 1.0\r\nContent-Type: multipart/alternative; boundary=%q\r\n\r\n", from, to, mime.QEncoding.Encode("utf-8", email.Subject), time.Now().UTC().Format(time.RFC1123Z), sha256.Sum256([]byte(key)), domain, parts.Boundary())
|
|
return append([]byte(headers), body.Bytes()...), nil
|
|
}
|