100 lines
3.2 KiB
Go
100 lines
3.2 KiB
Go
package mailkit
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestEnvelopeAddress covers the exact bug this fixes: a configured
|
|
// From address that includes a display name (a very natural thing to
|
|
// set ENKLY_SMTP_FROM to, e.g. "enkly <noreply@example.com>") must not
|
|
// be handed to MAIL FROM/RCPT TO as-is, or Gmail answers with "555
|
|
// 5.5.2 Syntax error, cannot decode response" because the envelope
|
|
// command only accepts a bare address (RFC 5321 §4.1.2).
|
|
func TestEnvelopeAddress(t *testing.T) {
|
|
cases := []struct{ in, want string }{
|
|
{"user@example.com", "user@example.com"},
|
|
{"enkly <user@example.com>", "user@example.com"},
|
|
{" enkly <user@example.com> ", "user@example.com"},
|
|
{"\"Enkly Notifications\" <user@example.com>", "user@example.com"},
|
|
// Not parseable as an address at all: returned unchanged so the
|
|
// SMTP server's own rejection explains the problem, rather than
|
|
// this function silently swallowing it.
|
|
{"not-an-address", "not-an-address"},
|
|
}
|
|
for _, c := range cases {
|
|
if got := envelopeAddress(c.in); got != c.want {
|
|
t.Errorf("envelopeAddress(%q) = %q, want %q", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestNewTrimsConfig guards against the same class of bug from a
|
|
// different angle: SMTP config values arriving from os.Getenv with
|
|
// stray whitespace or an embedded "\r" (e.g. a CRLF-saved .env or
|
|
// docker-compose.yml) must not reach the wire as part of an SMTP
|
|
// command line, or the server sees a corrupted command.
|
|
func TestNewTrimsConfig(t *testing.T) {
|
|
m := New(Config{
|
|
Host: " smtp.gmail.com\r\n",
|
|
Port: " 587 ",
|
|
Username: " user@example.com \r",
|
|
Password: " app-password \r",
|
|
From: " enkly <user@example.com> \r",
|
|
})
|
|
if m.cfg.Host != "smtp.gmail.com" {
|
|
t.Errorf("Host = %q", m.cfg.Host)
|
|
}
|
|
if m.cfg.Port != "587" {
|
|
t.Errorf("Port = %q", m.cfg.Port)
|
|
}
|
|
if m.cfg.Username != "user@example.com" {
|
|
t.Errorf("Username = %q", m.cfg.Username)
|
|
}
|
|
if m.cfg.Password != "app-password" {
|
|
t.Errorf("Password = %q", m.cfg.Password)
|
|
}
|
|
if m.cfg.From != "enkly <user@example.com>" {
|
|
t.Errorf("From = %q", m.cfg.From)
|
|
}
|
|
}
|
|
|
|
// TestNewDefaults checks the Gmail host/port/from defaults still apply
|
|
// after adding trimming, so a minimal config keeps working out of the
|
|
// box.
|
|
func TestNewDefaults(t *testing.T) {
|
|
m := New(Config{Username: "user@example.com", Password: "app-password"})
|
|
if m.cfg.Host != "smtp.gmail.com" {
|
|
t.Errorf("default Host = %q", m.cfg.Host)
|
|
}
|
|
if m.cfg.Port != "587" {
|
|
t.Errorf("default Port = %q", m.cfg.Port)
|
|
}
|
|
if m.cfg.From != "user@example.com" {
|
|
t.Errorf("default From = %q", m.cfg.From)
|
|
}
|
|
}
|
|
|
|
func TestConfigured(t *testing.T) {
|
|
if New(Config{}).Configured() {
|
|
t.Fatal("empty config must not report Configured")
|
|
}
|
|
if !New(Config{Username: "u", Password: "p"}).Configured() {
|
|
t.Fatal("username+password must report Configured")
|
|
}
|
|
}
|
|
|
|
func TestBuildMessageShape(t *testing.T) {
|
|
msg := buildMessage("enkly <from@example.com>", "to@example.com", "Subject line", "body text")
|
|
for _, want := range []string{
|
|
"From: enkly <from@example.com>\r\n",
|
|
"To: to@example.com\r\n",
|
|
"Subject: Subject line\r\n",
|
|
"\r\nbody text\r\n",
|
|
} {
|
|
if !strings.Contains(msg, want) {
|
|
t.Errorf("buildMessage output missing %q; got:\n%s", want, msg)
|
|
}
|
|
}
|
|
}
|