2 // Copyright 2020 Blue Static <https://www.bluestatic.org>
3 // This program is free software licensed under the GNU General Public License,
4 // version 3.0. The full text of the license can be found in LICENSE.txt.
5 // SPDX-License-Identifier: GPL-3.0-only
20 "src.bluestatic.org/mailpopbox/smtp"
23 func runSMTPServer(config Config, log *zap.Logger) <-chan ServerControlMessage {
26 controlChan: make(chan ServerControlMessage),
27 log: log.With(zap.String("server", "smtp")),
30 return server.controlChan
33 type smtpServer struct {
39 controlChan chan ServerControlMessage
42 func (server *smtpServer) run() {
43 if !server.loadTLSConfig() {
47 addr := fmt.Sprintf(":%d", server.config.SMTPPort)
48 server.log.Info("starting server", zap.String("address", addr))
50 l, err := net.Listen("tcp", addr)
52 server.log.Error("listen", zap.Error(err))
53 server.controlChan <- ServerControlFatalError
57 connChan := make(chan net.Conn)
58 go RunAcceptLoop(l, connChan, server.log)
60 reloadChan := CreateReloadSignal()
65 if !server.loadTLSConfig() {
68 case conn, ok := <-connChan:
70 go smtp.AcceptConnection(conn, server, server.log)
78 func (server *smtpServer) loadTLSConfig() bool {
80 server.tlsConfig, err = server.config.GetTLSConfig()
82 server.log.Error("failed to configure TLS", zap.Error(err))
83 server.controlChan <- ServerControlFatalError
86 server.log.Info("loaded TLS config")
90 func (server *smtpServer) Name() string {
91 return server.config.Hostname
94 func (server *smtpServer) TLSConfig() *tls.Config {
95 return server.tlsConfig
98 func (server *smtpServer) VerifyAddress(addr mail.Address) smtp.ReplyLine {
99 if server.maildropForAddress(addr) == "" {
100 return smtp.ReplyBadMailbox
105 func (server *smtpServer) OnEHLO() *smtp.ReplyLine {
109 func (server *smtpServer) OnMessageDelivered(en smtp.Envelope) *smtp.ReplyLine {
110 maildrop := server.maildropForAddress(en.RcptTo[0])
113 return &smtp.ReplyBadMailbox
116 f, err := os.Create(path.Join(maildrop, en.ID+".msg"))
119 return &smtp.ReplyBadMailbox
122 smtp.WriteEnvelopeForDelivery(f, en)
127 func (server *smtpServer) maildropForAddress(addr mail.Address) string {
128 domainIdx := strings.LastIndex(addr.Address, "@")
133 domain := addr.Address[domainIdx+1:]
135 for _, s := range server.config.Servers {
136 if domain == s.Domain {
137 return s.MaildropPath