12 "github.com/uber-go/zap"
14 "src.bluestatic.org/mailpopbox/smtp"
17 func runSMTPServer(config Config, log zap.Logger) <-chan ServerControlMessage {
20 controlChan: make(chan ServerControlMessage),
21 log: log.With(zap.String("server", "smtp")),
24 return server.controlChan
27 type smtpServer struct {
33 controlChan chan ServerControlMessage
36 func (server *smtpServer) run() {
37 if !server.loadTLSConfig() {
41 addr := fmt.Sprintf(":%d", server.config.SMTPPort)
42 server.log.Info("starting server", zap.String("address", addr))
44 l, err := net.Listen("tcp", addr)
46 server.log.Error("listen", zap.Error(err))
47 server.controlChan <- ServerControlFatalError
51 connChan := make(chan net.Conn)
52 go RunAcceptLoop(l, connChan, server.log)
54 reloadChan := CreateReloadSignal()
59 if !server.loadTLSConfig() {
62 case conn, ok := <-connChan:
64 go smtp.AcceptConnection(conn, server, server.log)
72 func (server *smtpServer) loadTLSConfig() bool {
74 server.tlsConfig, err = server.config.GetTLSConfig()
76 server.log.Error("failed to configure TLS", zap.Error(err))
77 server.controlChan <- ServerControlFatalError
80 server.log.Info("loaded TLS config")
84 func (server *smtpServer) Name() string {
85 return server.config.Hostname
88 func (server *smtpServer) TLSConfig() *tls.Config {
89 return server.tlsConfig
92 func (server *smtpServer) VerifyAddress(addr mail.Address) smtp.ReplyLine {
93 if server.maildropForAddress(addr) == "" {
94 return smtp.ReplyBadMailbox
99 func (server *smtpServer) OnEHLO() *smtp.ReplyLine {
103 func (server *smtpServer) OnMessageDelivered(en smtp.Envelope) *smtp.ReplyLine {
104 maildrop := server.maildropForAddress(en.RcptTo[0])
107 return &smtp.ReplyBadMailbox
110 f, err := os.Create(path.Join(maildrop, en.ID+".msg"))
113 return &smtp.ReplyBadMailbox
116 smtp.WriteEnvelopeForDelivery(f, en)
121 func (server *smtpServer) maildropForAddress(addr mail.Address) string {
122 domainIdx := strings.LastIndex(addr.Address, "@")
127 domain := addr.Address[domainIdx+1:]
129 for _, s := range server.config.Servers {
130 if domain == s.Domain {
131 return s.MaildropPath