1package smtp 2 3import "strconv" 4 5// http://www.rfc-editor.org/rfc/rfc5321.txt 6 7// Reply is a struct representing an SMTP reply (status code + lines) 8type Reply struct { 9 Status int 10 lines []string 11 Done func() 12} 13 14// Lines returns the formatted SMTP reply 15func (r Reply) Lines() []string { 16 var lines []string 17 18 if len(r.lines) == 0 { 19 l := strconv.Itoa(r.Status) 20 lines = append(lines, l+"\n") 21 return lines 22 } 23 24 for i, line := range r.lines { 25 l := "" 26 if i == len(r.lines)-1 { 27 l = strconv.Itoa(r.Status) + " " + line + "\r\n" 28 } else { 29 l = strconv.Itoa(r.Status) + "-" + line + "\r\n" 30 } 31 lines = append(lines, l) 32 } 33 34 return lines 35} 36 37// ReplyIdent creates a 220 welcome reply 38func ReplyIdent(ident string) *Reply { return &Reply{220, []string{ident}, nil} } 39 40// ReplyReadyToStartTLS creates a 220 ready to start TLS reply 41func ReplyReadyToStartTLS(callback func()) *Reply { 42 return &Reply{220, []string{"Ready to start TLS"}, callback} 43} 44 45// ReplyBye creates a 221 Bye reply 46func ReplyBye() *Reply { return &Reply{221, []string{"Bye"}, nil} } 47 48// ReplyAuthOk creates a 235 authentication successful reply 49func ReplyAuthOk() *Reply { return &Reply{235, []string{"Authentication successful"}, nil} } 50 51// ReplyOk creates a 250 Ok reply 52func ReplyOk(message ...string) *Reply { 53 if len(message) == 0 { 54 message = []string{"Ok"} 55 } 56 return &Reply{250, message, nil} 57} 58 59// ReplySenderOk creates a 250 Sender ok reply 60func ReplySenderOk(sender string) *Reply { 61 return &Reply{250, []string{"Sender " + sender + " ok"}, nil} 62} 63 64// ReplyRecipientOk creates a 250 Sender ok reply 65func ReplyRecipientOk(recipient string) *Reply { 66 return &Reply{250, []string{"Recipient " + recipient + " ok"}, nil} 67} 68 69// ReplyAuthResponse creates a 334 authentication reply 70func ReplyAuthResponse(response string) *Reply { return &Reply{334, []string{response}, nil} } 71 72// ReplyDataResponse creates a 354 data reply 73func ReplyDataResponse() *Reply { return &Reply{354, []string{"End data with <CR><LF>.<CR><LF>"}, nil} } 74 75// ReplyStorageFailed creates a 452 error reply 76func ReplyStorageFailed(reason string) *Reply { return &Reply{452, []string{reason}, nil} } 77 78// ReplyUnrecognisedCommand creates a 500 Unrecognised command reply 79func ReplyUnrecognisedCommand() *Reply { return &Reply{500, []string{"Unrecognised command"}, nil} } 80 81// ReplyLineTooLong creates a 500 Line too long reply 82func ReplyLineTooLong() *Reply { return &Reply{500, []string{"Line too long"}, nil} } 83 84// ReplySyntaxError creates a 501 Syntax error reply 85func ReplySyntaxError(response string) *Reply { 86 if len(response) > 0 { 87 response = " (" + response + ")" 88 } 89 return &Reply{501, []string{"Syntax error" + response}, nil} 90} 91 92// ReplyUnsupportedAuth creates a 504 unsupported authentication reply 93func ReplyUnsupportedAuth() *Reply { 94 return &Reply{504, []string{"Unsupported authentication mechanism"}, nil} 95} 96 97// ReplyMustIssueSTARTTLSFirst creates a 530 reply for RFC3207 98func ReplyMustIssueSTARTTLSFirst() *Reply { 99 return &Reply{530, []string{"Must issue a STARTTLS command first"}, nil} 100} 101 102// ReplyInvalidAuth creates a 535 error reply 103func ReplyInvalidAuth() *Reply { 104 return &Reply{535, []string{"Authentication credentials invalid"}, nil} 105} 106 107// ReplyError creates a 500 error reply 108func ReplyError(err error) *Reply { return &Reply{550, []string{err.Error()}, nil} } 109 110// ReplyTooManyRecipients creates a 552 too many recipients reply 111func ReplyTooManyRecipients() *Reply { return &Reply{552, []string{"Too many recipients"}, nil} } 112