Add support for outbound SMTP delivery.
[mailpopbox.git] / smtp / server.go
1 package smtp
2
3 import (
4 "crypto/tls"
5 "fmt"
6 "io"
7 "net"
8 "net/mail"
9 "strings"
10 "time"
11 )
12
13 type ReplyLine struct {
14 Code int
15 Message string
16 }
17
18 func (l ReplyLine) String() string {
19 return fmt.Sprintf("%d %s", l.Code, l.Message)
20 }
21
22 const SendAsAddress = "sendas+"
23
24 var (
25 ReplyOK = ReplyLine{250, "OK"}
26 ReplyBadSyntax = ReplyLine{501, "syntax error"}
27 ReplyBadSequence = ReplyLine{503, "bad sequence of commands"}
28 ReplyBadMailbox = ReplyLine{550, "mailbox unavailable"}
29 ReplyMailboxUnallowed = ReplyLine{553, "mailbox name not allowed"}
30 )
31
32 func DomainForAddress(addr mail.Address) string {
33 return DomainForAddressString(addr.Address)
34 }
35
36 func DomainForAddressString(address string) string {
37 domainIdx := strings.LastIndex(address, "@")
38 if domainIdx == -1 {
39 return ""
40 }
41 return address[domainIdx+1:]
42 }
43
44 type Envelope struct {
45 RemoteAddr net.Addr
46 EHLO string
47 MailFrom mail.Address
48 RcptTo []mail.Address
49 Data []byte
50 Received time.Time
51 ID string
52 }
53
54 func WriteEnvelopeForDelivery(w io.Writer, e Envelope) {
55 fmt.Fprintf(w, "Delivered-To: <%s>\r\n", e.RcptTo[0].Address)
56 fmt.Fprintf(w, "Return-Path: <%s>\r\n", e.MailFrom.Address)
57 w.Write(e.Data)
58 }
59
60 type Server interface {
61 Name() string
62 TLSConfig() *tls.Config
63 VerifyAddress(mail.Address) ReplyLine
64 // Verify that the authc+passwd identity can send mail as authz.
65 Authenticate(authz, authc, passwd string) bool
66 OnMessageDelivered(Envelope) *ReplyLine
67
68 // RelayMessage instructs the server to send the Envelope to another
69 // MTA for outbound delivery.
70 RelayMessage(Envelope)
71 }
72
73 type EmptyServerCallbacks struct{}
74
75 func (*EmptyServerCallbacks) TLSConfig() *tls.Config {
76 return nil
77 }
78
79 func (*EmptyServerCallbacks) VerifyAddress(mail.Address) ReplyLine {
80 return ReplyOK
81 }
82
83 func (*EmptyServerCallbacks) Authenticate(authz, authc, passwd string) bool {
84 return false
85 }
86
87 func (*EmptyServerCallbacks) OnMessageDelivered(Envelope) *ReplyLine {
88 return nil
89 }
90
91 func (*EmptyServerCallbacks) RelayMessage(Envelope) {
92 }