2 // Copyright 2020 Blue Static <https://www.bluestatic.org>
3 // This program is free software licensed under the GNU General Public License,
4 // version 3.0. The full text of the license can be found in LICENSE.txt.
5 // SPDX-License-Identifier: GPL-3.0-only
21 "src.bluestatic.org/mailpopbox/smtp"
24 func TestVerifyAddress(t *testing.T) {
25 dir, err := ioutil.TempDir("", "maildrop")
27 t.Errorf("Failed to create temp dir: %v", err)
30 defer os.RemoveAll(dir)
34 Hostname: "mx.example.com",
37 Domain: "example.com",
45 if s.VerifyAddress(mail.Address{Address: "example@example.com"}) != smtp.ReplyOK {
46 t.Errorf("Valid mailbox is not reported to be valid")
48 if s.VerifyAddress(mail.Address{Address: "mailbox@example.com"}) != smtp.ReplyOK {
49 t.Errorf("Valid mailbox is not reported to be valid")
51 if s.VerifyAddress(mail.Address{Address: "hello@other.net"}) == smtp.ReplyOK {
52 t.Errorf("Invalid mailbox reports to be valid")
54 if s.VerifyAddress(mail.Address{Address: "hello@mx.example.com"}) == smtp.ReplyOK {
55 t.Errorf("Invalid mailbox reports to be valid")
57 if s.VerifyAddress(mail.Address{Address: "unknown"}) == smtp.ReplyOK {
58 t.Errorf("Invalid mailbox reports to be valid")
62 func TestMessageDelivery(t *testing.T) {
63 dir, err := ioutil.TempDir("", "maildrop")
65 t.Errorf("Failed to create temp dir: %v", err)
68 defer os.RemoveAll(dir)
72 Hostname: "mx.example.com",
75 Domain: "example.com",
84 MailFrom: mail.Address{Address: "sender@mail.net"},
85 RcptTo: []mail.Address{{Address: "receive@example.com"}},
86 Data: []byte("Hello, world"),
90 if rl := s.DeliverMessage(env); rl != nil {
91 t.Errorf("Failed to deliver message: %v", rl)
94 f, err := os.Open(filepath.Join(dir, "msgid.msg"))
96 t.Errorf("Failed to open delivered message: %v", err)
100 data, err := ioutil.ReadAll(f)
102 t.Errorf("Failed to read message: %v", err)
105 if !bytes.Contains(data, env.Data) {
106 t.Errorf("Could not find expected data in message")
110 func TestAuthenticate(t *testing.T) {
111 server := smtpServer{
115 Domain: "domain1.net",
116 MailboxPassword: "d1",
119 Domain: "domain2.xyz",
120 MailboxPassword: "d2",
126 authTests := []struct {
127 authz, authc, passwd string
130 {"foo@domain1.net", "mailbox@domain1.net", "d1", true},
131 {"", "mailbox@domain1.net", "d1", true},
132 {"foo@domain2.xyz", "mailbox@domain1.xyz", "d1", false},
133 {"foo@domain2.xyz", "mailbox@domain1.xyz", "d2", false},
134 {"foo@domain2.xyz", "mailbox@domain2.xyz", "d2", true},
135 {"invalid", "mailbox@domain2.xyz", "d2", false},
136 {"", "mailbox@domain2.xyz", "d2", true},
140 for i, test := range authTests {
141 actual := server.Authenticate(test.authz, test.authc, test.passwd)
142 if actual != test.ok {
143 t.Errorf("Test %d, got %v, expected %v", i, actual, test.ok)
148 type testMTA struct {
149 relayed chan smtp.Envelope
152 func (m *testMTA) RelayMessage(en smtp.Envelope) {
156 func newTestMTA() *testMTA {
158 relayed: make(chan smtp.Envelope),
162 func TestBasicRelay(t *testing.T) {
164 server := smtpServer{
169 buf := new(bytes.Buffer)
170 fmt.Fprintln(buf, "From: <mailbox@example.com>\r")
171 fmt.Fprintln(buf, "To: <dest@another.net>\r")
172 fmt.Fprintf(buf, "Subject: Basic relay\n\n")
173 fmt.Fprintln(buf, "This is a basic relay message")
176 MailFrom: mail.Address{Address: "mailbox@example.com"},
177 RcptTo: []mail.Address{{Address: "dest@another.com"}},
182 server.RelayMessage(en, en.MailFrom.Address)
184 relayed := <-mta.relayed
186 if !bytes.Equal(relayed.Data, en.Data) {
187 t.Errorf("Relayed message data does not match")
191 func TestSendAsRelay(t *testing.T) {
193 server := smtpServer{
198 buf := new(bytes.Buffer)
199 fmt.Fprintln(buf, "Received: msg from wherever")
200 fmt.Fprintln(buf, "From: <mailbox@example.com>")
201 fmt.Fprintln(buf, "To: <valid@dest.xyz>")
202 fmt.Fprintf(buf, "Subject: Send-as relay [sendas:source]\n\n")
203 fmt.Fprintln(buf, "We've switched the senders!")
206 MailFrom: mail.Address{Address: "mailbox@example.com"},
207 RcptTo: []mail.Address{{Address: "valid@dest.xyz"}},
212 server.RelayMessage(en, en.MailFrom.Address)
214 relayed := <-mta.relayed
216 replaced := "source@example.com"
217 original := "mailbox@example.com"
219 if want, got := replaced, relayed.MailFrom.Address; want != got {
220 t.Errorf("Want mail to be from %q, got %q", want, got)
223 if want, got := 1, len(relayed.RcptTo); want != got {
224 t.Errorf("Want %d recipient, got %d", want, got)
226 if want, got := "valid@dest.xyz", relayed.RcptTo[0].Address; want != got {
227 t.Errorf("Unexpected RcptTo %q", got)
230 msg := string(relayed.Data)
232 if strings.Index(msg, original) != -1 {
233 t.Errorf("Should not find %q in message %q", original, msg)
236 if strings.Index(msg, "\nFrom: <source@example.com>\n") == -1 {
237 t.Errorf("Could not find From: header in message %q", msg)
240 if strings.Index(msg, "\nSubject: Send-as relay \n") == -1 {
241 t.Errorf("Could not find modified Subject: header in message %q", msg)