97 lines
3.0 KiB
Go
97 lines
3.0 KiB
Go
package mail
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"net/mail"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func sampleAnnouncement() Announcement {
|
|
return Announcement{
|
|
CategoryLabel: "New features",
|
|
Subject: "New in Vantage: scheduled workflows",
|
|
BodyMarkdown: "Workflows can now run **on a schedule**.\n\n<script>alert(1)</script>\n\n- cron syntax\n- time zones",
|
|
UnsubscribeURL: "https://api.example/email/unsubscribe?c=features&t=abc",
|
|
PreferencesURL: "https://hq.example/email-preferences?t=abc",
|
|
PostalAddress: "Hostxtra Ltd, 1 High Street, Leeds",
|
|
}
|
|
}
|
|
|
|
func TestRenderAnnouncement(t *testing.T) {
|
|
subject, html, text, err := RenderAnnouncement(sampleAnnouncement(), "https://hq.example")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if subject != "New in Vantage: scheduled workflows" {
|
|
t.Errorf("subject = %q", subject)
|
|
}
|
|
if !strings.Contains(html, "<strong>on a schedule</strong>") {
|
|
t.Error("markdown not rendered to html")
|
|
}
|
|
if strings.Contains(html, "<script>") {
|
|
t.Error("raw html from markdown reached the email")
|
|
}
|
|
for label, body := range map[string]string{"html": html, "text": text} {
|
|
for _, want := range []string{"email/unsubscribe?c=features", "email-preferences?t=abc", "New features", "Hostxtra Ltd"} {
|
|
if !strings.Contains(body, want) {
|
|
t.Errorf("%s body missing %q", label, want)
|
|
}
|
|
}
|
|
if strings.Contains(body, "\u2014") {
|
|
t.Errorf("%s body contains an em dash", label)
|
|
}
|
|
}
|
|
if !strings.Contains(text, "**on a schedule**") {
|
|
t.Error("text part should carry the markdown source")
|
|
}
|
|
}
|
|
|
|
func TestRenderAnnouncementWithoutPostalAddress(t *testing.T) {
|
|
a := sampleAnnouncement()
|
|
a.PostalAddress = ""
|
|
_, html, _, err := RenderAnnouncement(a, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(html, "<no value>") {
|
|
t.Error("empty postal address rendered as <no value>")
|
|
}
|
|
}
|
|
|
|
func TestSendAnnouncementRefusesListsAndMissingLink(t *testing.T) {
|
|
s := Sender{Host: "smtp.invalid", From: "updates@example.com"}
|
|
prepare := func(what string, err error) {
|
|
t.Helper()
|
|
var se *SendError
|
|
if !errors.As(err, &se) || se.Phase != PhasePrepare {
|
|
t.Errorf("%s: err = %v, want a *SendError at PhasePrepare", what, err)
|
|
}
|
|
}
|
|
prepare("a comma-separated To", s.SendAnnouncement("a@example.com, b@example.com", sampleAnnouncement()))
|
|
a := sampleAnnouncement()
|
|
a.UnsubscribeURL = ""
|
|
prepare("no unsubscribe URL", s.SendAnnouncement("a@example.com", a))
|
|
}
|
|
|
|
// Gmail and Yahoo require both headers of the RFC 8058 pair on bulk mail.
|
|
func TestSendAnnouncementPutsListUnsubscribeOnTheWire(t *testing.T) {
|
|
port, got := fakeSMTPData(t, nil)
|
|
s := Sender{Host: "127.0.0.1", Port: port, From: "updates@example.com"}
|
|
a := sampleAnnouncement()
|
|
if err := s.SendAnnouncement("a@example.com", a); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
msg, err := mail.ReadMessage(bytes.NewReader(<-got))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if h := msg.Header.Get("List-Unsubscribe"); h != "<"+a.UnsubscribeURL+">" {
|
|
t.Errorf("List-Unsubscribe = %q", h)
|
|
}
|
|
if h := msg.Header.Get("List-Unsubscribe-Post"); h != "List-Unsubscribe=One-Click" {
|
|
t.Errorf("List-Unsubscribe-Post = %q", h)
|
|
}
|
|
}
|