@@ -17,14 +17,15 @@ import (
1717
1818// mockSMTPServer is a test SMTP server that captures commands and messages
1919type mockSMTPServer struct {
20- listener net.Listener
21- mu sync.Mutex
22- commands []string
23- messages []capturedMessage
24- authSuccess bool
25- closed bool
26- wg sync.WaitGroup
27- mailFromCmd string // captures the exact MAIL FROM command
20+ listener net.Listener
21+ mu sync.Mutex
22+ commands []string
23+ messages []capturedMessage
24+ authSuccess bool
25+ closed bool
26+ wg sync.WaitGroup
27+ mailFromCmd string // captures the exact MAIL FROM command
28+ multilineBanner bool // send multi-line 220 banner (RFC 5321 compliant)
2829}
2930
3031type capturedMessage struct {
@@ -49,6 +50,26 @@ func newMockSMTPServer(t *testing.T, authSuccess bool) *mockSMTPServer {
4950 return server
5051}
5152
53+ // newMockSMTPServerWithMultilineBanner creates a mock SMTP server that sends
54+ // a multi-line 220 greeting banner (RFC 5321 Section 4.2 compliant).
55+ // This tests the fix for issue #183.
56+ func newMockSMTPServerWithMultilineBanner (t * testing.T , authSuccess bool ) * mockSMTPServer {
57+ listener , err := net .Listen ("tcp" , "127.0.0.1:0" )
58+ require .NoError (t , err )
59+
60+ server := & mockSMTPServer {
61+ listener : listener ,
62+ authSuccess : authSuccess ,
63+ commands : make ([]string , 0 ),
64+ messages : make ([]capturedMessage , 0 ),
65+ multilineBanner : true ,
66+ }
67+
68+ server .wg .Add (1 )
69+ go server .serve ()
70+ return server
71+ }
72+
5273func (s * mockSMTPServer ) serve () {
5374 defer s .wg .Done ()
5475 for {
@@ -73,8 +94,16 @@ func (s *mockSMTPServer) handleConnection(conn net.Conn) {
7394
7495 reader := bufio .NewReader (conn )
7596
76- // Send greeting
77- conn .Write ([]byte ("220 localhost SMTP Mock Server\r \n " ))
97+ // Send greeting (multi-line or single-line based on configuration)
98+ if s .multilineBanner {
99+ // RFC 5321 multi-line 220 banner (issue #183)
100+ // Realistic example based on enterprise SMTP relays and ISP servers
101+ conn .Write ([]byte ("220-mail.example.com ESMTP Postfix\r \n " ))
102+ conn .Write ([]byte ("220-Authorized use only. All activity may be monitored.\r \n " ))
103+ conn .Write ([]byte ("220 Service ready\r \n " ))
104+ } else {
105+ conn .Write ([]byte ("220 localhost SMTP Mock Server\r \n " ))
106+ }
78107
79108 var from string
80109 var recipients []string
@@ -315,6 +344,43 @@ func TestSendRawEmail_MultipleRecipients(t *testing.T) {
315344 assert .Len (t , messages [0 ].recipients , 3 )
316345}
317346
347+ func TestSendRawEmail_MultilineBanner (t * testing.T ) {
348+ // Test fix for issue #183: Multi-line 220 banner handling
349+ // RFC 5321 Section 4.2 allows multi-line greetings like:
350+ // 220-smtp.example.com ESMTP
351+ // 220-Additional info
352+ // 220 Service ready
353+
354+ server := newMockSMTPServerWithMultilineBanner (t , true )
355+ defer server .Close ()
356+
357+ port := server .Port ()
358+ msg := []
byte (
"From: [email protected] \r \n To: [email protected] \r \n Subject: Test\r \n \r \n Test body" )
359+
360+ err := sendRawEmail (
"127.0.0.1" ,
port ,
"" ,
"" ,
false ,
"[email protected] " , []
string {
"[email protected] " },
msg )
361+ require .NoError (t , err , "Should handle multi-line 220 banner without error" )
362+
363+ messages := server .GetMessages ()
364+ require .Len (t , messages , 1 )
365+ assert .
Equal (
t ,
"[email protected] " ,
messages [
0 ].
from )
366+ assert .
Contains (
t ,
messages [
0 ].
recipients ,
"[email protected] " )
367+ }
368+
369+ func TestSendRawEmail_MultilineBannerWithAuth (t * testing.T ) {
370+ // Test multi-line banner with authentication
371+ server := newMockSMTPServerWithMultilineBanner (t , true )
372+ defer server .Close ()
373+
374+ port := server .Port ()
375+ msg := []
byte (
"From: [email protected] \r \n To: [email protected] \r \n Subject: Test\r \n \r \n Test body" )
376+
377+ err := sendRawEmail (
"127.0.0.1" ,
port ,
"user" ,
"pass" ,
false ,
"[email protected] " , []
string {
"[email protected] " },
msg )
378+ require .NoError (t , err , "Should handle multi-line 220 banner with auth without error" )
379+
380+ messages := server .GetMessages ()
381+ require .Len (t , messages , 1 )
382+ }
383+
318384// ============================================================================
319385// Tests for SMTPService.SendEmail with real message composition
320386// ============================================================================
0 commit comments