mirror of
https://github.com/emersion/go-smtp
synced 2026-07-02 01:04:40 +00:00
210 lines
5.2 KiB
Go
210 lines
5.2 KiB
Go
package smtp_test
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
"net"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/emersion/go-smtp"
|
|
)
|
|
|
|
func testServerGreetedLMTP(t *testing.T, fn ...serverConfigureFunc) (be *backend, s *smtp.Server, c net.Conn, scanner *bufio.Scanner) {
|
|
be, s, c, scanner = testServer(t, fn...)
|
|
|
|
scanner.Scan()
|
|
if scanner.Text() != "220 localhost LMTP Service Ready" {
|
|
t.Fatal("Invalid greeting:", scanner.Text())
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func sendDeliveryCmdsLMTP(t *testing.T, scanner *bufio.Scanner, c io.Writer) {
|
|
sendLHLO(t, scanner, c)
|
|
|
|
io.WriteString(c, "MAIL FROM:<root@nsa.gov>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "RCPT TO:<root@bnd.bund.de>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "DATA\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "Hey <3\r\n")
|
|
io.WriteString(c, ".\r\n")
|
|
}
|
|
|
|
func sendLHLO(t *testing.T, scanner *bufio.Scanner, c io.Writer) {
|
|
io.WriteString(c, "LHLO localhost\r\n")
|
|
scanner.Scan()
|
|
if scanner.Text() != "250-Hello localhost" {
|
|
t.Fatal("Invalid LHLO response:", scanner.Text())
|
|
}
|
|
for scanner.Scan() {
|
|
s := scanner.Text()
|
|
|
|
if strings.HasPrefix(s, "250 ") {
|
|
break
|
|
} else if !strings.HasPrefix(s, "250-") {
|
|
t.Fatal("Invalid capability response:", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestServer_LMTP(t *testing.T) {
|
|
be, s, c, scanner := testServerGreetedLMTP(t, func(s *smtp.Server) {
|
|
s.LMTP = true
|
|
be := s.Backend.(*backend)
|
|
be.implementLMTPData = true
|
|
be.lmtpStatus = []struct {
|
|
addr string
|
|
err error
|
|
}{
|
|
{"root@gchq.gov.uk", errors.New("nah")},
|
|
{"root@bnd.bund.de", nil},
|
|
}
|
|
})
|
|
defer s.Close()
|
|
defer c.Close()
|
|
|
|
sendDeliveryCmdsLMTP(t, scanner, c)
|
|
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "554 5.0.0 <root@gchq.gov.uk>") {
|
|
t.Fatal("Invalid DATA first response:", scanner.Text())
|
|
}
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "250 ") {
|
|
t.Fatal("Invalid DATA second response:", scanner.Text())
|
|
}
|
|
|
|
if len(be.messages) != 0 || len(be.anonmsgs) != 1 {
|
|
t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs)
|
|
}
|
|
}
|
|
|
|
func TestServer_LMTP_Early(t *testing.T) {
|
|
// This test confirms responses are sent as early as possible
|
|
// e.g. right after SetStatus is called.
|
|
|
|
lmtpStatusSync := make(chan struct{})
|
|
|
|
be, s, c, scanner := testServerGreetedLMTP(t, func(s *smtp.Server) {
|
|
s.LMTP = true
|
|
be := s.Backend.(*backend)
|
|
be.implementLMTPData = true
|
|
be.lmtpStatusSync = lmtpStatusSync
|
|
be.lmtpStatus = []struct {
|
|
addr string
|
|
err error
|
|
}{
|
|
{"root@gchq.gov.uk", errors.New("nah")},
|
|
{"root@bnd.bund.de", nil},
|
|
}
|
|
})
|
|
defer s.Close()
|
|
defer c.Close()
|
|
|
|
sendDeliveryCmdsLMTP(t, scanner, c)
|
|
|
|
// Test backend sends to sync channel after calling SetStatus.
|
|
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "554 5.0.0 <root@gchq.gov.uk>") {
|
|
t.Fatal("Invalid DATA first response:", scanner.Text())
|
|
}
|
|
|
|
<-be.lmtpStatusSync
|
|
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "250 ") {
|
|
t.Fatal("Invalid DATA second response:", scanner.Text())
|
|
}
|
|
|
|
<-be.lmtpStatusSync
|
|
|
|
if len(be.messages) != 0 || len(be.anonmsgs) != 1 {
|
|
t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs)
|
|
}
|
|
}
|
|
|
|
func TestServer_LMTP_Expand(t *testing.T) {
|
|
// This checks whether handleDataLMTP
|
|
// correctly expands results if backend doesn't
|
|
// implement LMTPSession.
|
|
|
|
be, s, c, scanner := testServerGreetedLMTP(t, func(s *smtp.Server) {
|
|
s.LMTP = true
|
|
})
|
|
defer s.Close()
|
|
defer c.Close()
|
|
|
|
sendDeliveryCmdsLMTP(t, scanner, c)
|
|
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "250 ") {
|
|
t.Fatal("Invalid DATA first response:", scanner.Text())
|
|
}
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "250 ") {
|
|
t.Fatal("Invalid DATA second response:", scanner.Text())
|
|
}
|
|
|
|
if len(be.messages) != 0 || len(be.anonmsgs) != 1 {
|
|
t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs)
|
|
}
|
|
}
|
|
|
|
func TestServer_LMTP_DuplicatedRcpt(t *testing.T) {
|
|
be, s, c, scanner := testServerGreetedLMTP(t, func(s *smtp.Server) {
|
|
s.LMTP = true
|
|
be := s.Backend.(*backend)
|
|
be.implementLMTPData = true
|
|
be.lmtpStatus = []struct {
|
|
addr string
|
|
err error
|
|
}{
|
|
{"root@gchq.gov.uk", &smtp.SMTPError{Code: 555}},
|
|
{"root@bnd.bund.de", nil},
|
|
{"root@gchq.gov.uk", &smtp.SMTPError{Code: 556}},
|
|
}
|
|
})
|
|
defer s.Close()
|
|
defer c.Close()
|
|
|
|
sendLHLO(t, scanner, c)
|
|
|
|
io.WriteString(c, "MAIL FROM:<root@nsa.gov>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "RCPT TO:<root@bnd.bund.de>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "DATA\r\n")
|
|
scanner.Scan()
|
|
io.WriteString(c, "Hey <3\r\n")
|
|
io.WriteString(c, ".\r\n")
|
|
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "555 5.0.0 <root@gchq.gov.uk>") {
|
|
t.Fatal("Invalid DATA first response:", scanner.Text())
|
|
}
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "250 ") {
|
|
t.Fatal("Invalid DATA second response:", scanner.Text())
|
|
}
|
|
scanner.Scan()
|
|
if !strings.HasPrefix(scanner.Text(), "556 5.0.0 <root@gchq.gov.uk>") {
|
|
t.Fatal("Invalid DATA first response:", scanner.Text())
|
|
}
|
|
|
|
if len(be.messages) != 0 || len(be.anonmsgs) != 1 {
|
|
t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs)
|
|
}
|
|
}
|