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