initial public commit
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/mail"
|
||||
)
|
||||
|
||||
// Mailer defines a base mail client interface.
|
||||
type Mailer interface {
|
||||
// Send sends an email with HTML body to the specified recipient.
|
||||
Send(
|
||||
fromEmail mail.Address,
|
||||
toEmail mail.Address,
|
||||
subject string,
|
||||
htmlBody string,
|
||||
attachments map[string]io.Reader,
|
||||
) error
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
var _ Mailer = (*Sendmail)(nil)
|
||||
|
||||
// Sendmail implements `mailer.Mailer` interface and defines a mail
|
||||
// client that sends emails via the `sendmail` *nix command.
|
||||
//
|
||||
// This client is usually recommended only for development and testing.
|
||||
type Sendmail struct {
|
||||
}
|
||||
|
||||
// Send implements `mailer.Mailer` interface.
|
||||
//
|
||||
// Attachments are currently not supported.
|
||||
func (m *Sendmail) Send(
|
||||
fromEmail mail.Address,
|
||||
toEmail mail.Address,
|
||||
subject string,
|
||||
htmlBody string,
|
||||
attachments map[string]io.Reader,
|
||||
) error {
|
||||
headers := make(http.Header)
|
||||
headers.Set("Subject", mime.QEncoding.Encode("utf-8", subject))
|
||||
headers.Set("From", fromEmail.String())
|
||||
headers.Set("To", toEmail.String())
|
||||
headers.Set("Content-Type", "text/html; charset=UTF-8")
|
||||
|
||||
cmdPath, err := findSendmailPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
|
||||
// write
|
||||
// ---
|
||||
if err := headers.Write(&buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := buffer.Write([]byte("\r\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := buffer.Write([]byte(htmlBody)); err != nil {
|
||||
return err
|
||||
}
|
||||
// ---
|
||||
|
||||
sendmail := exec.Command(cmdPath, toEmail.Address)
|
||||
sendmail.Stdin = &buffer
|
||||
|
||||
return sendmail.Run()
|
||||
}
|
||||
|
||||
func findSendmailPath() (string, error) {
|
||||
options := []string{
|
||||
"/usr/sbin/sendmail",
|
||||
"/usr/bin/sendmail",
|
||||
"sendmail",
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
path, err := exec.LookPath(option)
|
||||
if err == nil {
|
||||
return path, err
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("Failed to locate a sendmail executable path.")
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package mailer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/domodwyer/mailyak/v3"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
)
|
||||
|
||||
var _ Mailer = (*SmtpClient)(nil)
|
||||
|
||||
// regex to select all tabs
|
||||
var tabsRegex = regexp.MustCompile(`\t+`)
|
||||
|
||||
// NewSmtpClient creates new `SmtpClient` with the provided configuration.
|
||||
func NewSmtpClient(
|
||||
host string,
|
||||
port int,
|
||||
username string,
|
||||
password string,
|
||||
tls bool,
|
||||
) *SmtpClient {
|
||||
return &SmtpClient{
|
||||
host: host,
|
||||
port: port,
|
||||
username: username,
|
||||
password: password,
|
||||
tls: tls,
|
||||
}
|
||||
}
|
||||
|
||||
// SmtpClient defines a SMTP mail client structure that implements
|
||||
// `mailer.Mailer` interface.
|
||||
type SmtpClient struct {
|
||||
mail *mailyak.MailYak
|
||||
|
||||
host string
|
||||
port int
|
||||
username string
|
||||
password string
|
||||
tls bool
|
||||
}
|
||||
|
||||
// Send implements `mailer.Mailer` interface.
|
||||
func (m *SmtpClient) Send(
|
||||
fromEmail mail.Address,
|
||||
toEmail mail.Address,
|
||||
subject string,
|
||||
htmlBody string,
|
||||
attachments map[string]io.Reader,
|
||||
) error {
|
||||
smtpAuth := smtp.PlainAuth("", m.username, m.password, m.host)
|
||||
|
||||
// create mail instance
|
||||
var yak *mailyak.MailYak
|
||||
if m.tls {
|
||||
var tlsErr error
|
||||
yak, tlsErr = mailyak.NewWithTLS(fmt.Sprintf("%s:%d", m.host, m.port), smtpAuth, nil)
|
||||
if tlsErr != nil {
|
||||
return tlsErr
|
||||
}
|
||||
} else {
|
||||
yak = mailyak.New(fmt.Sprintf("%s:%d", m.host, m.port), smtpAuth)
|
||||
}
|
||||
|
||||
if fromEmail.Name != "" {
|
||||
yak.FromName(fromEmail.Name)
|
||||
}
|
||||
yak.From(fromEmail.Address)
|
||||
yak.To(toEmail.Address)
|
||||
yak.Subject(subject)
|
||||
yak.HTML().Set(htmlBody)
|
||||
|
||||
// set also plain text content
|
||||
policy := bluemonday.StrictPolicy() // strips all tags
|
||||
yak.Plain().Set(strings.TrimSpace(tabsRegex.ReplaceAllString(policy.Sanitize(htmlBody), "")))
|
||||
|
||||
for name, data := range attachments {
|
||||
yak.Attach(name, data)
|
||||
}
|
||||
|
||||
return yak.Send()
|
||||
}
|
||||
Reference in New Issue
Block a user