Start saving SMTP messages in the maildrop.
[mailpopbox.git] / smtp.go
1 package main
2
3 import (
4 "crypto/tls"
5 "fmt"
6 "net"
7 "net/mail"
8 "os"
9 "path"
10 "strings"
11
12 "src.bluestatic.org/mailpopbox/smtp"
13 )
14
15 func runSMTPServer(config Config) <-chan error {
16 server := smtpServer{
17 config: config,
18 rc: make(chan error),
19 }
20 go server.run()
21 return server.rc
22 }
23
24 type smtpServer struct {
25 config Config
26 rc chan error
27 }
28
29 func (server *smtpServer) run() {
30 l, err := net.Listen("tcp", fmt.Sprintf(":%d", server.config.SMTPPort))
31 if err != nil {
32 server.rc <- err
33 return
34 }
35
36 for {
37 conn, err := l.Accept()
38 if err != nil {
39 server.rc <- err
40 return
41 }
42
43 go smtp.AcceptConnection(conn, server)
44 }
45 }
46
47 func (server *smtpServer) Name() string {
48 return server.config.Hostname
49 }
50
51 func (server *smtpServer) TLSConfig() *tls.Config {
52 return nil
53 }
54
55 func (server *smtpServer) VerifyAddress(addr mail.Address) smtp.ReplyLine {
56 if server.maildropForAddress(addr) == "" {
57 return smtp.ReplyBadMailbox
58 }
59 return smtp.ReplyOK
60 }
61
62 func (server *smtpServer) OnEHLO() *smtp.ReplyLine {
63 return nil
64 }
65
66 func (server *smtpServer) OnMessageDelivered(en smtp.Envelope) *smtp.ReplyLine {
67 maildrop := server.maildropForAddress(en.RcptTo[0])
68 if maildrop == "" {
69 // TODO: log error
70 return &smtp.ReplyBadMailbox
71 }
72
73 f, err := os.Create(path.Join(maildrop, en.ID+".msg"))
74 if err != nil {
75 // TODO: log error
76 return &smtp.ReplyBadMailbox
77 }
78
79 smtp.WriteEnvelopeForDelivery(f, en)
80 f.Close()
81 return nil
82 }
83
84 func (server *smtpServer) maildropForAddress(addr mail.Address) string {
85 domainIdx := strings.LastIndex(addr.Address, "@")
86 if domainIdx == -1 {
87 return ""
88 }
89
90 domain := addr.Address[domainIdx+1:]
91
92 for _, s := range server.config.Servers {
93 if domain == s.Domain {
94 return s.MaildropPath
95 }
96 }
97
98 return ""
99 }