1package smtp_test 2 3import ( 4 "bufio" 5 "errors" 6 "io" 7 "strings" 8 "testing" 9 10 "github.com/emersion/go-smtp" 11) 12 13func sendDeliveryCmdsLMTP(t *testing.T, scanner *bufio.Scanner, c io.Writer) { 14 sendLHLO(t, scanner, c) 15 16 io.WriteString(c, "MAIL FROM:<root@nsa.gov>\r\n") 17 scanner.Scan() 18 io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n") 19 scanner.Scan() 20 io.WriteString(c, "RCPT TO:<root@bnd.bund.de>\r\n") 21 scanner.Scan() 22 io.WriteString(c, "DATA\r\n") 23 scanner.Scan() 24 io.WriteString(c, "Hey <3\r\n") 25 io.WriteString(c, ".\r\n") 26} 27 28func sendLHLO(t *testing.T, scanner *bufio.Scanner, c io.Writer) { 29 io.WriteString(c, "LHLO localhost\r\n") 30 scanner.Scan() 31 if scanner.Text() != "250-Hello localhost" { 32 t.Fatal("Invalid LHLO response:", scanner.Text()) 33 } 34 for scanner.Scan() { 35 s := scanner.Text() 36 37 if strings.HasPrefix(s, "250 ") { 38 break 39 } else if !strings.HasPrefix(s, "250-") { 40 t.Fatal("Invalid capability response:", s) 41 } 42 } 43} 44 45func TestServer_LMTP(t *testing.T) { 46 be, s, c, scanner := testServerGreeted(t, func(s *smtp.Server) { 47 s.LMTP = true 48 be := s.Backend.(*backend) 49 be.implementLMTPData = true 50 be.lmtpStatus = []struct { 51 addr string 52 err error 53 }{ 54 {"root@gchq.gov.uk", errors.New("nah")}, 55 {"root@bnd.bund.de", nil}, 56 } 57 }) 58 defer s.Close() 59 defer c.Close() 60 61 sendDeliveryCmdsLMTP(t, scanner, c) 62 63 scanner.Scan() 64 if !strings.HasPrefix(scanner.Text(), "554 5.0.0 <root@gchq.gov.uk>") { 65 t.Fatal("Invalid DATA first response:", scanner.Text()) 66 } 67 scanner.Scan() 68 if !strings.HasPrefix(scanner.Text(), "250 ") { 69 t.Fatal("Invalid DATA second response:", scanner.Text()) 70 } 71 72 if len(be.messages) != 0 || len(be.anonmsgs) != 1 { 73 t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs) 74 } 75} 76 77func TestServer_LMTP_Early(t *testing.T) { 78 // This test confirms responses are sent as early as possible 79 // e.g. right after SetStatus is called. 80 81 lmtpStatusSync := make(chan struct{}) 82 83 be, s, c, scanner := testServerGreeted(t, func(s *smtp.Server) { 84 s.LMTP = true 85 be := s.Backend.(*backend) 86 be.implementLMTPData = true 87 be.lmtpStatusSync = lmtpStatusSync 88 be.lmtpStatus = []struct { 89 addr string 90 err error 91 }{ 92 {"root@gchq.gov.uk", errors.New("nah")}, 93 {"root@bnd.bund.de", nil}, 94 } 95 }) 96 defer s.Close() 97 defer c.Close() 98 99 sendDeliveryCmdsLMTP(t, scanner, c) 100 101 // Test backend sends to sync channel after calling SetStatus. 102 103 scanner.Scan() 104 if !strings.HasPrefix(scanner.Text(), "554 5.0.0 <root@gchq.gov.uk>") { 105 t.Fatal("Invalid DATA first response:", scanner.Text()) 106 } 107 108 <-be.lmtpStatusSync 109 110 scanner.Scan() 111 if !strings.HasPrefix(scanner.Text(), "250 ") { 112 t.Fatal("Invalid DATA second response:", scanner.Text()) 113 } 114 115 <-be.lmtpStatusSync 116 117 if len(be.messages) != 0 || len(be.anonmsgs) != 1 { 118 t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs) 119 } 120} 121 122func TestServer_LMTP_Expand(t *testing.T) { 123 // This checks whether handleDataLMTP 124 // correctly expands results if backend doesn't 125 // implement LMTPSession. 126 127 be, s, c, scanner := testServerGreeted(t, func(s *smtp.Server) { 128 s.LMTP = true 129 }) 130 defer s.Close() 131 defer c.Close() 132 133 sendDeliveryCmdsLMTP(t, scanner, c) 134 135 scanner.Scan() 136 if !strings.HasPrefix(scanner.Text(), "250 ") { 137 t.Fatal("Invalid DATA first response:", scanner.Text()) 138 } 139 scanner.Scan() 140 if !strings.HasPrefix(scanner.Text(), "250 ") { 141 t.Fatal("Invalid DATA second response:", scanner.Text()) 142 } 143 144 if len(be.messages) != 0 || len(be.anonmsgs) != 1 { 145 t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs) 146 } 147} 148 149func TestServer_LMTP_DuplicatedRcpt(t *testing.T) { 150 be, s, c, scanner := testServerGreeted(t, func(s *smtp.Server) { 151 s.LMTP = true 152 be := s.Backend.(*backend) 153 be.implementLMTPData = true 154 be.lmtpStatus = []struct { 155 addr string 156 err error 157 }{ 158 {"root@gchq.gov.uk", &smtp.SMTPError{Code: 555}}, 159 {"root@bnd.bund.de", nil}, 160 {"root@gchq.gov.uk", &smtp.SMTPError{Code: 556}}, 161 } 162 }) 163 defer s.Close() 164 defer c.Close() 165 166 sendLHLO(t, scanner, c) 167 168 io.WriteString(c, "MAIL FROM:<root@nsa.gov>\r\n") 169 scanner.Scan() 170 io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n") 171 scanner.Scan() 172 io.WriteString(c, "RCPT TO:<root@bnd.bund.de>\r\n") 173 scanner.Scan() 174 io.WriteString(c, "RCPT TO:<root@gchq.gov.uk>\r\n") 175 scanner.Scan() 176 io.WriteString(c, "DATA\r\n") 177 scanner.Scan() 178 io.WriteString(c, "Hey <3\r\n") 179 io.WriteString(c, ".\r\n") 180 181 scanner.Scan() 182 if !strings.HasPrefix(scanner.Text(), "555 5.0.0 <root@gchq.gov.uk>") { 183 t.Fatal("Invalid DATA first response:", scanner.Text()) 184 } 185 scanner.Scan() 186 if !strings.HasPrefix(scanner.Text(), "250 ") { 187 t.Fatal("Invalid DATA second response:", scanner.Text()) 188 } 189 scanner.Scan() 190 if !strings.HasPrefix(scanner.Text(), "556 5.0.0 <root@gchq.gov.uk>") { 191 t.Fatal("Invalid DATA first response:", scanner.Text()) 192 } 193 194 if len(be.messages) != 0 || len(be.anonmsgs) != 1 { 195 t.Fatal("Invalid number of sent messages:", be.messages, be.anonmsgs) 196 } 197} 198