package main import ( "context" "io" "log" "os" "forge.cadoles.com/wpetit/fake-smtp/internal/command" "forge.cadoles.com/wpetit/fake-smtp/internal/config" "github.com/emersion/go-smtp" "github.com/jhillyerd/enmime" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/middleware/container" "gitlab.com/wpetit/goweb/service" ) type Backend struct { ctn *service.Container username string password string } // Login handles a login command with username and password. func (b *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) { if b.username != "" && username != b.username { return nil, errors.New("invalid username") } if b.password != "" && password != b.password { return nil, errors.New("invalid password") } ctx := context.WithValue(context.Background(), container.KeyServiceContainer, b.ctn) return &Session{ctx, b.ctn, username}, nil } // AnonymousLogin requires clients to authenticate using SMTP AUTH before sending emails func (b *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) { if b.username != "" || b.password != "" { return nil, smtp.ErrAuthRequired } return nil, nil } // A Session is returned after successful login. type Session struct { ctx context.Context ctn *service.Container username string } func (s *Session) Mail(from string, opts smtp.MailOptions) error { return nil } func (s *Session) Rcpt(to string) error { return nil } func (s *Session) Data(r io.Reader) error { env, err := enmime.ReadEnvelope(r) if err != nil { return errors.Wrap(err, "could not read envelope") } bus, err := cqrs.From(s.ctn) if err != nil { return errors.Wrap(err, "could not retrieve cqrs service") } cmd := &command.StoreEmailRequest{ Envelope: env, } if _, err := bus.Exec(s.ctx, cmd); err != nil { return errors.Wrap(err, "could not exec command") } return nil } func (s *Session) Reset() {} func (s *Session) Logout() error { return nil } func startSMTPServer(conf *config.Config, ctn *service.Container) { be := &Backend{ ctn: ctn, username: conf.SMTP.Username, password: conf.SMTP.Password, } s := smtp.NewServer(be) s.Addr = conf.SMTP.Address s.Domain = conf.SMTP.Domain s.ReadTimeout = conf.SMTP.ReadTimeout s.WriteTimeout = conf.SMTP.WriteTimeout s.MaxMessageBytes = conf.SMTP.MaxMessageBytes s.MaxRecipients = conf.SMTP.MaxRecipients s.AllowInsecureAuth = conf.SMTP.AllowInsecureAuth if conf.SMTP.Debug { s.Debug = os.Stdout } log.Println("starting server at", s.Addr) if err := s.ListenAndServe(); err != nil { log.Fatal(err) } }